react-native-inapp-inspector 1.1.27 → 1.1.28
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/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +34 -0
- package/dist/commonjs/components/ErrorBoundary.d.ts +1 -1
- package/dist/commonjs/components/ErrorBoundary.js +530 -100
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +176 -126
- package/dist/commonjs/components/Inspector/BundleTab.d.ts +1 -0
- package/dist/commonjs/components/Inspector/BundleTab.js +145 -21
- package/dist/commonjs/components/Inspector/CrashTab.js +0 -8
- package/dist/commonjs/components/Inspector/NetworkDetail.js +41 -0
- package/dist/commonjs/components/Inspector/PerformanceTab.d.ts +5 -0
- package/dist/commonjs/components/Inspector/PerformanceTab.js +588 -155
- package/dist/commonjs/components/Inspector/SettingsPanel.js +57 -22
- package/dist/commonjs/components/Inspector/TabBar.js +13 -1
- package/dist/commonjs/components/LogCard.js +75 -34
- package/dist/commonjs/components/NetworkIcons.d.ts +112 -102
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/analyticsLogger.d.ts +1 -11
- package/dist/commonjs/customHooks/analyticsLogger.js +8 -1
- package/dist/commonjs/customHooks/bundleAnalyzer.js +121 -124
- package/dist/commonjs/customHooks/networkLogger.d.ts +1 -0
- package/dist/commonjs/customHooks/networkLogger.js +16 -0
- package/dist/commonjs/customHooks/performanceTracker.d.ts +74 -0
- package/dist/commonjs/customHooks/performanceTracker.js +546 -392
- package/dist/commonjs/customHooks/reduxLogger.d.ts +1 -0
- package/dist/commonjs/customHooks/reduxLogger.js +3 -1
- package/dist/commonjs/helpers/index.js +27 -3
- package/dist/commonjs/i18n/locales/en.json +225 -4
- package/dist/commonjs/index.d.ts +1 -1
- package/dist/commonjs/index.js +36 -2
- package/dist/commonjs/styles/index.d.ts +3 -1
- package/dist/commonjs/styles/index.js +8 -6
- package/dist/commonjs/types/interfaces.d.ts +3 -0
- package/dist/esm/components/ErrorBoundary.d.ts +1 -1
- package/dist/esm/components/ErrorBoundary.js +498 -101
- package/dist/esm/components/Inspector/AnalyticsTab.js +177 -127
- package/dist/esm/components/Inspector/BundleTab.d.ts +1 -0
- package/dist/esm/components/Inspector/BundleTab.js +145 -23
- package/dist/esm/components/Inspector/CrashTab.js +0 -8
- package/dist/esm/components/Inspector/NetworkDetail.js +41 -0
- package/dist/esm/components/Inspector/PerformanceTab.d.ts +5 -0
- package/dist/esm/components/Inspector/PerformanceTab.js +591 -158
- package/dist/esm/components/Inspector/SettingsPanel.js +57 -22
- package/dist/esm/components/Inspector/TabBar.js +13 -1
- package/dist/esm/components/LogCard.js +75 -34
- package/dist/esm/components/NetworkIcons.d.ts +112 -102
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/analyticsLogger.d.ts +1 -11
- package/dist/esm/customHooks/analyticsLogger.js +6 -0
- package/dist/esm/customHooks/bundleAnalyzer.js +121 -124
- package/dist/esm/customHooks/networkLogger.d.ts +1 -0
- package/dist/esm/customHooks/networkLogger.js +16 -0
- package/dist/esm/customHooks/performanceTracker.d.ts +74 -0
- package/dist/esm/customHooks/performanceTracker.js +531 -391
- package/dist/esm/customHooks/reduxLogger.d.ts +1 -0
- package/dist/esm/customHooks/reduxLogger.js +1 -0
- package/dist/esm/helpers/index.js +27 -3
- package/dist/esm/i18n/locales/en.json +225 -4
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +24 -3
- package/dist/esm/styles/index.d.ts +3 -1
- package/dist/esm/styles/index.js +8 -6
- package/dist/esm/types/interfaces.d.ts +3 -0
- package/ios/NetworkInspectorModule.m +10 -0
- package/package.json +1 -1
|
@@ -36,6 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.downloadBundleFile = void 0;
|
|
39
40
|
const react_1 = __importStar(require("react"));
|
|
40
41
|
const react_native_1 = require("react-native");
|
|
41
42
|
const i18n_1 = require("../../i18n");
|
|
@@ -44,6 +45,7 @@ const CopyButton_1 = __importDefault(require("../CopyButton"));
|
|
|
44
45
|
const HighlightText_1 = __importDefault(require("../HighlightText"));
|
|
45
46
|
const AppColors_1 = require("../../styles/AppColors");
|
|
46
47
|
const AppFonts_1 = require("../../styles/AppFonts");
|
|
48
|
+
const helpers_1 = require("../../helpers");
|
|
47
49
|
const NetworkIcons_1 = require("../NetworkIcons");
|
|
48
50
|
const react_native_svg_1 = __importStar(require("react-native-svg"));
|
|
49
51
|
const bundleAnalyzer_1 = require("../../customHooks/bundleAnalyzer");
|
|
@@ -342,7 +344,73 @@ function buildBundleFileTree(files) {
|
|
|
342
344
|
}
|
|
343
345
|
return convertMapToNodes(rootMap);
|
|
344
346
|
}
|
|
345
|
-
const
|
|
347
|
+
const downloadBundleFile = async (file, scriptURL) => {
|
|
348
|
+
let content = '';
|
|
349
|
+
// 1. Attempt to fetch real source code from Metro dev server if available
|
|
350
|
+
try {
|
|
351
|
+
let devServerOrigin = 'http://localhost:8081';
|
|
352
|
+
if (scriptURL && scriptURL.startsWith('http')) {
|
|
353
|
+
const match = scriptURL.match(/^(https?:\/\/[^/]+)/);
|
|
354
|
+
if (match) {
|
|
355
|
+
devServerOrigin = match[1];
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
const cleanPath = file.path.replace(/^\/+/, '');
|
|
359
|
+
const url = `${devServerOrigin}/${cleanPath}`;
|
|
360
|
+
const res = await fetch(url);
|
|
361
|
+
if (res.ok) {
|
|
362
|
+
const text = await res.text();
|
|
363
|
+
if (text && text.length > 0) {
|
|
364
|
+
content = text;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
catch { }
|
|
369
|
+
// 2. If dev server direct fetch is unavailable, provide structured module descriptor with full path
|
|
370
|
+
if (!content) {
|
|
371
|
+
content = `// ─────────────────────────────────────────────────────────────
|
|
372
|
+
// File: ${file.name}
|
|
373
|
+
// Path: ${file.path}
|
|
374
|
+
// Category: ${file.category.toUpperCase()}
|
|
375
|
+
// Size: ${file.sizeKb} KB
|
|
376
|
+
// Status: ${file.status === 'optimal' ? 'Active in Dependency Graph' : 'Not consumed / Static'}
|
|
377
|
+
// Meta: ${file.meta}
|
|
378
|
+
// ─────────────────────────────────────────────────────────────
|
|
379
|
+
|
|
380
|
+
export default {
|
|
381
|
+
id: ${JSON.stringify(file.id)},
|
|
382
|
+
name: ${JSON.stringify(file.name)},
|
|
383
|
+
path: ${JSON.stringify(file.path)},
|
|
384
|
+
category: ${JSON.stringify(file.category)},
|
|
385
|
+
sizeKb: ${file.sizeKb},
|
|
386
|
+
meta: ${JSON.stringify(file.meta)},
|
|
387
|
+
status: ${JSON.stringify(file.status || 'optimal')},
|
|
388
|
+
};
|
|
389
|
+
`;
|
|
390
|
+
}
|
|
391
|
+
// 3. Trigger native Share / Download sheet
|
|
392
|
+
try {
|
|
393
|
+
await react_native_1.Share.share(react_native_1.Platform.OS === 'ios'
|
|
394
|
+
? {
|
|
395
|
+
title: file.name,
|
|
396
|
+
message: content,
|
|
397
|
+
}
|
|
398
|
+
: {
|
|
399
|
+
title: `Download ${file.name}`,
|
|
400
|
+
message: content,
|
|
401
|
+
}, {
|
|
402
|
+
dialogTitle: `Download / Save ${file.name}`,
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
catch { }
|
|
406
|
+
// 4. Also copy directly to clipboard for quick paste in VS Code or external editor
|
|
407
|
+
try {
|
|
408
|
+
(0, helpers_1.copyToClipboard)(content, file.name);
|
|
409
|
+
}
|
|
410
|
+
catch { }
|
|
411
|
+
};
|
|
412
|
+
exports.downloadBundleFile = downloadBundleFile;
|
|
413
|
+
const BundleTreeNodeView = ({ node, level, search, totalBundleKb, expandedFolders, toggleFolder, isLastChild, onDownload, }) => {
|
|
346
414
|
const isExpanded = search ? true : !!expandedFolders[node.fullPath];
|
|
347
415
|
const isCollapsed = !isExpanded;
|
|
348
416
|
const indentLeft = level * 16 + 10;
|
|
@@ -380,7 +448,7 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, expandedFolder
|
|
|
380
448
|
</TouchableScale_1.default>
|
|
381
449
|
|
|
382
450
|
{!isCollapsed && (<react_native_1.View style={bundleStyles.treeChildrenContainer}>
|
|
383
|
-
{node.children.map((child, cIdx) => (<BundleTreeNodeView key={child.id} node={child} level={level + 1} search={search} totalBundleKb={totalBundleKb} expandedFolders={expandedFolders} toggleFolder={toggleFolder} isLastChild={cIdx === node.children.length - 1}/>))}
|
|
451
|
+
{node.children.map((child, cIdx) => (<BundleTreeNodeView key={child.id} node={child} level={level + 1} search={search} totalBundleKb={totalBundleKb} expandedFolders={expandedFolders} toggleFolder={toggleFolder} isLastChild={cIdx === node.children.length - 1} onDownload={onDownload}/>))}
|
|
384
452
|
</react_native_1.View>)}
|
|
385
453
|
</react_native_1.View>);
|
|
386
454
|
}
|
|
@@ -421,7 +489,13 @@ const BundleTreeNodeView = ({ node, level, search, totalBundleKb, expandedFolder
|
|
|
421
489
|
<react_native_1.Text style={bundleStyles.treeFilePctText}>{pctOfTotal}%</react_native_1.Text>
|
|
422
490
|
</react_native_1.View>
|
|
423
491
|
|
|
424
|
-
<
|
|
492
|
+
<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 5 }}>
|
|
493
|
+
{onDownload && (<TouchableScale_1.default onPress={() => onDownload(file)} style={bundleStyles.treeActionBtn} hitSlop={8}>
|
|
494
|
+
<NetworkIcons_1.DownloadIcon size={13} color={AppColors_1.AppColors.sky500}/>
|
|
495
|
+
</TouchableScale_1.default>)}
|
|
496
|
+
|
|
497
|
+
<CopyButton_1.default value={() => file} label={(0, i18n_1.t)('bundle.fileDetailsJson')}/>
|
|
498
|
+
</react_native_1.View>
|
|
425
499
|
</react_native_1.View>
|
|
426
500
|
</react_native_1.View>);
|
|
427
501
|
};
|
|
@@ -598,12 +672,28 @@ const BundleTab = react_1.default.memo(() => {
|
|
|
598
672
|
const filteredTotalKb = (0, react_1.useMemo)(() => {
|
|
599
673
|
return filteredFiles.reduce((acc, f) => acc + f.sizeKb, 0);
|
|
600
674
|
}, [filteredFiles]);
|
|
601
|
-
// Tree View State & Node Generation (
|
|
675
|
+
// Tree View State & Node Generation (Top folders expanded by default)
|
|
602
676
|
const [filesViewMode, setFilesViewMode] = (0, react_1.useState)('tree');
|
|
603
677
|
const [expandedFolders, setExpandedFolders] = (0, react_1.useState)({});
|
|
604
678
|
const fileTreeNodes = (0, react_1.useMemo)(() => {
|
|
605
679
|
return buildBundleFileTree(filteredFiles);
|
|
606
680
|
}, [filteredFiles]);
|
|
681
|
+
(0, react_1.useEffect)(() => {
|
|
682
|
+
if (fileTreeNodes.length > 0 && Object.keys(expandedFolders).length === 0) {
|
|
683
|
+
const initial = {};
|
|
684
|
+
fileTreeNodes.forEach(node => {
|
|
685
|
+
if (node.isFolder) {
|
|
686
|
+
initial[node.fullPath] = true;
|
|
687
|
+
node.children.forEach(child => {
|
|
688
|
+
if (child.isFolder) {
|
|
689
|
+
initial[child.fullPath] = true;
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
setExpandedFolders(initial);
|
|
695
|
+
}
|
|
696
|
+
}, [fileTreeNodes]);
|
|
607
697
|
const toggleFolder = (0, react_1.useCallback)((path) => {
|
|
608
698
|
setExpandedFolders(prev => ({
|
|
609
699
|
...prev,
|
|
@@ -1356,7 +1446,7 @@ const BundleTab = react_1.default.memo(() => {
|
|
|
1356
1446
|
|
|
1357
1447
|
{/* ── MODE 1: DIRECTORY TREE VIEW ── */}
|
|
1358
1448
|
{filesViewMode === 'tree' ? (<react_native_1.View style={bundleStyles.treeRootCard}>
|
|
1359
|
-
{fileTreeNodes.map((node, nIdx) => (<BundleTreeNodeView key={node.id} node={node} level={0} search={search} totalBundleKb={summary.totalKb} expandedFolders={expandedFolders} toggleFolder={toggleFolder} isLastChild={nIdx === fileTreeNodes.length - 1}/>))}
|
|
1449
|
+
{fileTreeNodes.map((node, nIdx) => (<BundleTreeNodeView key={node.id} node={node} level={0} search={search} totalBundleKb={summary.totalKb} expandedFolders={expandedFolders} toggleFolder={toggleFolder} isLastChild={nIdx === fileTreeNodes.length - 1} onDownload={f => (0, exports.downloadBundleFile)(f, analysis?.scriptURL)}/>))}
|
|
1360
1450
|
</react_native_1.View>) : (
|
|
1361
1451
|
/* ── MODE 2: FLAT LIST VIEW ── */
|
|
1362
1452
|
filteredFiles.map((file, index) => {
|
|
@@ -1392,6 +1482,9 @@ const BundleTab = react_1.default.memo(() => {
|
|
|
1392
1482
|
</react_native_1.Text>
|
|
1393
1483
|
<react_native_1.Text style={bundleStyles.filePercent}>{pctOfTotal}%</react_native_1.Text>
|
|
1394
1484
|
</react_native_1.View>
|
|
1485
|
+
<TouchableScale_1.default onPress={() => (0, exports.downloadBundleFile)(file, analysis?.scriptURL)} style={bundleStyles.downloadFileBtn} hitSlop={8}>
|
|
1486
|
+
<NetworkIcons_1.DownloadIcon size={14} color={AppColors_1.AppColors.sky500}/>
|
|
1487
|
+
</TouchableScale_1.default>
|
|
1395
1488
|
<CopyButton_1.default value={() => file} label={t('bundle.fileDetailsJson')}/>
|
|
1396
1489
|
</react_native_1.View>
|
|
1397
1490
|
</react_native_1.View>
|
|
@@ -1410,21 +1503,25 @@ const BundleTab = react_1.default.memo(() => {
|
|
|
1410
1503
|
<react_native_1.Text style={bundleStyles.fileMetaText}>{file.meta}</react_native_1.Text>
|
|
1411
1504
|
{file.advice && (<react_native_1.View style={[
|
|
1412
1505
|
bundleStyles.adviceBadge,
|
|
1413
|
-
file.status === 'warning' &&
|
|
1414
|
-
|
|
1506
|
+
file.status === 'warning' &&
|
|
1507
|
+
bundleStyles.adviceWarning,
|
|
1508
|
+
file.status === 'optimal' &&
|
|
1509
|
+
bundleStyles.adviceOptimal,
|
|
1415
1510
|
isUnused && bundleStyles.adviceUnused,
|
|
1416
1511
|
]}>
|
|
1417
|
-
<react_native_1.View style={{ flexDirection: 'row', alignItems: 'flex-start', gap: 5 }}>
|
|
1418
1512
|
{isUnused ? (<NetworkIcons_1.TrashIcon color={AppColors_1.AppColors.red600} size={12}/>) : file.status === 'warning' ? (<NetworkIcons_1.LightbulbIcon color={AppColors_1.AppColors.amber800Warm} size={12}/>) : (<NetworkIcons_1.SparkleIcon color={AppColors_1.AppColors.emerald700} size={12}/>)}
|
|
1419
1513
|
<react_native_1.Text style={[
|
|
1420
1514
|
bundleStyles.adviceText,
|
|
1421
|
-
file.status === 'warning' && {
|
|
1422
|
-
|
|
1515
|
+
file.status === 'warning' && {
|
|
1516
|
+
color: AppColors_1.AppColors.amber800Warm,
|
|
1517
|
+
},
|
|
1518
|
+
file.status === 'optimal' && {
|
|
1519
|
+
color: AppColors_1.AppColors.emerald700,
|
|
1520
|
+
},
|
|
1423
1521
|
isUnused && { color: AppColors_1.AppColors.red600 },
|
|
1424
1522
|
]}>
|
|
1425
1523
|
{file.advice}
|
|
1426
1524
|
</react_native_1.Text>
|
|
1427
|
-
</react_native_1.View>
|
|
1428
1525
|
</react_native_1.View>)}
|
|
1429
1526
|
</react_native_1.View>
|
|
1430
1527
|
</react_native_1.View>);
|
|
@@ -1655,6 +1752,9 @@ const BundleTab = react_1.default.memo(() => {
|
|
|
1655
1752
|
{t('bundle.fileSizeKb', { size: file.sizeKb })}
|
|
1656
1753
|
</react_native_1.Text>
|
|
1657
1754
|
</react_native_1.View>
|
|
1755
|
+
<TouchableScale_1.default onPress={() => (0, exports.downloadBundleFile)(file, analysis?.scriptURL)} style={bundleStyles.downloadFileBtn} hitSlop={8}>
|
|
1756
|
+
<NetworkIcons_1.DownloadIcon size={14} color={AppColors_1.AppColors.sky500}/>
|
|
1757
|
+
</TouchableScale_1.default>
|
|
1658
1758
|
<CopyButton_1.default value={() => file} label={t('bundle.mediaItemJson')}/>
|
|
1659
1759
|
</react_native_1.View>
|
|
1660
1760
|
</react_native_1.View>
|
|
@@ -1666,16 +1766,18 @@ const BundleTab = react_1.default.memo(() => {
|
|
|
1666
1766
|
file.status === 'warning' && bundleStyles.adviceWarning,
|
|
1667
1767
|
file.status === 'optimal' && bundleStyles.adviceOptimal,
|
|
1668
1768
|
]}>
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
<react_native_1.Text style={[
|
|
1769
|
+
{file.status === 'warning' ? (<NetworkIcons_1.LightbulbIcon color={AppColors_1.AppColors.amber800Warm} size={12}/>) : (<NetworkIcons_1.SparkleIcon color={AppColors_1.AppColors.emerald700} size={12}/>)}
|
|
1770
|
+
<react_native_1.Text style={[
|
|
1672
1771
|
bundleStyles.adviceText,
|
|
1673
|
-
file.status === 'warning' && {
|
|
1674
|
-
|
|
1772
|
+
file.status === 'warning' && {
|
|
1773
|
+
color: AppColors_1.AppColors.amber800Warm,
|
|
1774
|
+
},
|
|
1775
|
+
file.status === 'optimal' && {
|
|
1776
|
+
color: AppColors_1.AppColors.emerald700,
|
|
1777
|
+
},
|
|
1675
1778
|
]}>
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
</react_native_1.View>
|
|
1779
|
+
{file.advice}
|
|
1780
|
+
</react_native_1.Text>
|
|
1679
1781
|
</react_native_1.View>)}
|
|
1680
1782
|
</react_native_1.View>
|
|
1681
1783
|
</react_native_1.View>))}
|
|
@@ -2446,6 +2548,24 @@ const bundleStyles = react_native_1.StyleSheet.create({
|
|
|
2446
2548
|
fileSizeBox: {
|
|
2447
2549
|
alignItems: 'flex-end',
|
|
2448
2550
|
},
|
|
2551
|
+
downloadFileBtn: {
|
|
2552
|
+
padding: 6,
|
|
2553
|
+
borderRadius: 6,
|
|
2554
|
+
backgroundColor: `${AppColors_1.AppColors.sky500}14`,
|
|
2555
|
+
alignItems: 'center',
|
|
2556
|
+
justifyContent: 'center',
|
|
2557
|
+
borderWidth: 1,
|
|
2558
|
+
borderColor: `${AppColors_1.AppColors.sky500}28`,
|
|
2559
|
+
},
|
|
2560
|
+
treeActionBtn: {
|
|
2561
|
+
padding: 4,
|
|
2562
|
+
borderRadius: 4,
|
|
2563
|
+
backgroundColor: `${AppColors_1.AppColors.sky500}14`,
|
|
2564
|
+
alignItems: 'center',
|
|
2565
|
+
justifyContent: 'center',
|
|
2566
|
+
borderWidth: 1,
|
|
2567
|
+
borderColor: `${AppColors_1.AppColors.sky500}28`,
|
|
2568
|
+
},
|
|
2449
2569
|
fileSizeKb: {
|
|
2450
2570
|
fontFamily: AppFonts_1.AppFonts.interBold,
|
|
2451
2571
|
fontSize: 12,
|
|
@@ -2617,10 +2737,13 @@ const bundleStyles = react_native_1.StyleSheet.create({
|
|
|
2617
2737
|
color: AppColors_1.AppColors.amber800Warm,
|
|
2618
2738
|
},
|
|
2619
2739
|
adviceBadge: {
|
|
2740
|
+
flexDirection: 'row',
|
|
2741
|
+
alignItems: 'center',
|
|
2620
2742
|
paddingHorizontal: 8,
|
|
2621
|
-
paddingVertical:
|
|
2743
|
+
paddingVertical: 5,
|
|
2622
2744
|
borderRadius: 6,
|
|
2623
|
-
marginTop:
|
|
2745
|
+
marginTop: 4,
|
|
2746
|
+
gap: 6,
|
|
2624
2747
|
},
|
|
2625
2748
|
adviceWarning: {
|
|
2626
2749
|
backgroundColor: AppColors_1.AppColors.amber100,
|
|
@@ -2636,6 +2759,7 @@ const bundleStyles = react_native_1.StyleSheet.create({
|
|
|
2636
2759
|
fontFamily: AppFonts_1.AppFonts.interMedium,
|
|
2637
2760
|
fontSize: 10.5,
|
|
2638
2761
|
lineHeight: 14,
|
|
2762
|
+
flex: 1,
|
|
2639
2763
|
},
|
|
2640
2764
|
impactBadge: {
|
|
2641
2765
|
paddingHorizontal: 6,
|
|
@@ -72,14 +72,6 @@ const CrashTab = react_1.default.memo(() => {
|
|
|
72
72
|
const [crashFilters, setCrashFilters] = (0, react_1.useState)(CrashFilterModal_1.DEFAULT_CRASH_FILTERS);
|
|
73
73
|
const [isFilterModalOpen, setIsFilterModalOpen] = (0, react_1.useState)(false);
|
|
74
74
|
const [detailSubTab, setDetailSubTab] = (0, react_1.useState)('stack');
|
|
75
|
-
// Auto-open the latest crash detail on first visit if crashes exist
|
|
76
|
-
const hasAutoOpened = react_1.default.useRef(false);
|
|
77
|
-
react_1.default.useEffect(() => {
|
|
78
|
-
if (!hasAutoOpened.current && !selectedCrash && crashRecords.length > 0) {
|
|
79
|
-
setSelectedCrash(crashRecords[0]);
|
|
80
|
-
hasAutoOpened.current = true;
|
|
81
|
-
}
|
|
82
|
-
}, [crashRecords, selectedCrash, setSelectedCrash]);
|
|
83
75
|
// Calculate statistics
|
|
84
76
|
const stats = (0, react_1.useMemo)(() => {
|
|
85
77
|
const total = crashRecords.length;
|
|
@@ -102,6 +102,47 @@ const NetworkDetail = react_1.default.memo(() => {
|
|
|
102
102
|
</react_native_1.Text>
|
|
103
103
|
</react_native_1.View>
|
|
104
104
|
|
|
105
|
+
{/* Client Chip (AXIOS / FETCH / XHR) */}
|
|
106
|
+
{selected.client && (<react_native_1.View style={[
|
|
107
|
+
styles_1.default.chip,
|
|
108
|
+
{
|
|
109
|
+
backgroundColor: selected.client === 'axios'
|
|
110
|
+
? `${AppColors_1.AppColors.purple}14`
|
|
111
|
+
: selected.client === 'apollo' || selected.client === 'graphql'
|
|
112
|
+
? `${AppColors_1.AppColors.pink500}14`
|
|
113
|
+
: selected.client === 'xhr'
|
|
114
|
+
? `${AppColors_1.AppColors.amber500}14`
|
|
115
|
+
: `${AppColors_1.AppColors.sky500}14`,
|
|
116
|
+
borderColor: selected.client === 'axios'
|
|
117
|
+
? `${AppColors_1.AppColors.purple}30`
|
|
118
|
+
: selected.client === 'apollo' || selected.client === 'graphql'
|
|
119
|
+
? `${AppColors_1.AppColors.pink500}30`
|
|
120
|
+
: selected.client === 'xhr'
|
|
121
|
+
? `${AppColors_1.AppColors.amber500}30`
|
|
122
|
+
: `${AppColors_1.AppColors.sky500}30`,
|
|
123
|
+
paddingHorizontal: 6,
|
|
124
|
+
paddingVertical: 3,
|
|
125
|
+
borderRadius: 6,
|
|
126
|
+
},
|
|
127
|
+
]}>
|
|
128
|
+
<react_native_1.Text style={[
|
|
129
|
+
styles_1.default.chipText,
|
|
130
|
+
{
|
|
131
|
+
fontFamily: AppFonts_1.AppFonts.interBold,
|
|
132
|
+
fontSize: 9.5,
|
|
133
|
+
color: selected.client === 'axios'
|
|
134
|
+
? AppColors_1.AppColors.purple
|
|
135
|
+
: selected.client === 'apollo' || selected.client === 'graphql'
|
|
136
|
+
? AppColors_1.AppColors.pink500
|
|
137
|
+
: selected.client === 'xhr'
|
|
138
|
+
? AppColors_1.AppColors.amber700
|
|
139
|
+
: AppColors_1.AppColors.sky600,
|
|
140
|
+
},
|
|
141
|
+
]}>
|
|
142
|
+
{selected.client.toUpperCase()}
|
|
143
|
+
</react_native_1.Text>
|
|
144
|
+
</react_native_1.View>)}
|
|
145
|
+
|
|
105
146
|
{/* Status Pill */}
|
|
106
147
|
{selected.status != null && (<react_native_1.View style={[
|
|
107
148
|
styles_1.default.chip,
|
|
@@ -6,6 +6,11 @@ export interface PerformanceEvent {
|
|
|
6
6
|
category: 'render' | 'navigation' | 'memory' | 'io' | 'bridge';
|
|
7
7
|
fps: number;
|
|
8
8
|
durationMs: number;
|
|
9
|
+
droppedFrames?: number;
|
|
10
|
+
frameTimeMs?: number;
|
|
11
|
+
frameBudgetPct?: number;
|
|
12
|
+
bottleneckThread?: 'JS Thread' | 'UI Thread' | 'Bridge' | 'Balanced';
|
|
13
|
+
screenName?: string;
|
|
9
14
|
label: string;
|
|
10
15
|
detail: string;
|
|
11
16
|
source?: string;
|