@buoy-gg/network 7.0.12 → 7.0.14
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/lib/commonjs/index.js +52 -0
- package/lib/commonjs/network/components/NetworkDetailStepper.js +26 -14
- package/lib/commonjs/network/components/NetworkEventDetailView.js +86 -14
- package/lib/commonjs/network/components/NetworkEventItemCompact.js +4 -0
- package/lib/commonjs/network/components/NetworkHeaderLive.js +32 -7
- package/lib/commonjs/network/components/NetworkHeaderMenu.js +183 -0
- package/lib/commonjs/network/components/NetworkListScreen.js +134 -8
- package/lib/commonjs/network/components/NetworkModal.js +198 -51
- package/lib/commonjs/network/components/NetworkNumberPrompt.js +178 -0
- package/lib/commonjs/network/components/NetworkOverrideEditor.js +797 -0
- package/lib/commonjs/network/components/NetworkOverrideHeaderButton.js +102 -0
- package/lib/commonjs/network/components/NetworkOverridesButton.js +88 -0
- package/lib/commonjs/network/components/NetworkOverridesScreen.js +489 -0
- package/lib/commonjs/network/components/response-editor/Explorer.js +973 -0
- package/lib/commonjs/network/components/response-editor/deleteNestedDataByPath.js +56 -0
- package/lib/commonjs/network/components/response-editor/editorContext.js +33 -0
- package/lib/commonjs/network/components/response-editor/updateNestedDataByPath.js +61 -0
- package/lib/commonjs/network/hooks/useNetworkSelection.js +53 -0
- package/lib/commonjs/network/hooks/useOverrideRules.js +36 -0
- package/lib/commonjs/network/overrides/applyToFetch.js +80 -0
- package/lib/commonjs/network/overrides/applyToXhr.js +190 -0
- package/lib/commonjs/network/overrides/engine.js +70 -0
- package/lib/commonjs/network/overrides/matchRule.js +81 -0
- package/lib/commonjs/network/overrides/overrideRulesStore.js +550 -0
- package/lib/commonjs/network/overrides/presets.js +70 -0
- package/lib/commonjs/network/overrides/resolveOverride.js +158 -0
- package/lib/commonjs/network/overrides/types.js +85 -0
- package/lib/commonjs/network/sync/networkSyncAdapter.js +230 -1
- package/lib/commonjs/network/types/index.js +5 -1
- package/lib/commonjs/network/utils/networkEventStore.js +52 -6
- package/lib/commonjs/network/utils/networkListener.js +90 -10
- package/lib/commonjs/network/utils/networkSelectionStore.js +193 -0
- package/lib/commonjs/preset.js +11 -0
- package/lib/module/index.js +19 -0
- package/lib/module/network/components/NetworkDetailStepper.js +27 -15
- package/lib/module/network/components/NetworkEventDetailView.js +87 -15
- package/lib/module/network/components/NetworkEventItemCompact.js +5 -1
- package/lib/module/network/components/NetworkHeaderLive.js +32 -7
- package/lib/module/network/components/NetworkHeaderMenu.js +177 -0
- package/lib/module/network/components/NetworkListScreen.js +135 -9
- package/lib/module/network/components/NetworkModal.js +200 -53
- package/lib/module/network/components/NetworkNumberPrompt.js +174 -0
- package/lib/module/network/components/NetworkOverrideEditor.js +794 -0
- package/lib/module/network/components/NetworkOverrideHeaderButton.js +99 -0
- package/lib/module/network/components/NetworkOverridesButton.js +85 -0
- package/lib/module/network/components/NetworkOverridesScreen.js +485 -0
- package/lib/module/network/components/response-editor/Explorer.js +972 -0
- package/lib/module/network/components/response-editor/deleteNestedDataByPath.js +51 -0
- package/lib/module/network/components/response-editor/editorContext.js +29 -0
- package/lib/module/network/components/response-editor/updateNestedDataByPath.js +56 -0
- package/lib/module/network/hooks/useNetworkSelection.js +46 -0
- package/lib/module/network/hooks/useOverrideRules.js +32 -0
- package/lib/module/network/overrides/applyToFetch.js +72 -0
- package/lib/module/network/overrides/applyToXhr.js +185 -0
- package/lib/module/network/overrides/engine.js +64 -0
- package/lib/module/network/overrides/matchRule.js +75 -0
- package/lib/module/network/overrides/overrideRulesStore.js +547 -0
- package/lib/module/network/overrides/presets.js +65 -0
- package/lib/module/network/overrides/resolveOverride.js +152 -0
- package/lib/module/network/overrides/types.js +80 -0
- package/lib/module/network/sync/networkSyncAdapter.js +230 -1
- package/lib/module/network/types/index.js +3 -1
- package/lib/module/network/utils/networkEventStore.js +52 -6
- package/lib/module/network/utils/networkListener.js +91 -10
- package/lib/module/network/utils/networkSelectionStore.js +188 -0
- package/lib/module/preset.js +13 -1
- package/lib/typescript/index.d.ts +9 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkDetailStepper.d.ts +8 -5
- package/lib/typescript/network/components/NetworkDetailStepper.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkEventDetailView.d.ts +36 -1
- package/lib/typescript/network/components/NetworkEventDetailView.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts +6 -0
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkHeaderLive.d.ts +13 -3
- package/lib/typescript/network/components/NetworkHeaderLive.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkHeaderMenu.d.ts +46 -0
- package/lib/typescript/network/components/NetworkHeaderMenu.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkListScreen.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkModal.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkNumberPrompt.d.ts +33 -0
- package/lib/typescript/network/components/NetworkNumberPrompt.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverrideEditor.d.ts +17 -0
- package/lib/typescript/network/components/NetworkOverrideEditor.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts +27 -0
- package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverridesButton.d.ts +17 -0
- package/lib/typescript/network/components/NetworkOverridesButton.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverridesScreen.d.ts +29 -0
- package/lib/typescript/network/components/NetworkOverridesScreen.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/Explorer.d.ts +17 -0
- package/lib/typescript/network/components/response-editor/Explorer.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts +9 -0
- package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/editorContext.d.ts +29 -0
- package/lib/typescript/network/components/response-editor/editorContext.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts +10 -0
- package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts.map +1 -0
- package/lib/typescript/network/hooks/useNetworkSelection.d.ts +26 -0
- package/lib/typescript/network/hooks/useNetworkSelection.d.ts.map +1 -0
- package/lib/typescript/network/hooks/useOverrideRules.d.ts +29 -0
- package/lib/typescript/network/hooks/useOverrideRules.d.ts.map +1 -0
- package/lib/typescript/network/overrides/__tests__/applyToFetch.test.d.ts +16 -0
- package/lib/typescript/network/overrides/__tests__/applyToFetch.test.d.ts.map +1 -0
- package/lib/typescript/network/overrides/__tests__/applyToXhr.test.d.ts +19 -0
- package/lib/typescript/network/overrides/__tests__/applyToXhr.test.d.ts.map +1 -0
- package/lib/typescript/network/overrides/__tests__/resolveOverride.test.d.ts +22 -0
- package/lib/typescript/network/overrides/__tests__/resolveOverride.test.d.ts.map +1 -0
- package/lib/typescript/network/overrides/applyToFetch.d.ts +50 -0
- package/lib/typescript/network/overrides/applyToFetch.d.ts.map +1 -0
- package/lib/typescript/network/overrides/applyToXhr.d.ts +43 -0
- package/lib/typescript/network/overrides/applyToXhr.d.ts.map +1 -0
- package/lib/typescript/network/overrides/engine.d.ts +47 -0
- package/lib/typescript/network/overrides/engine.d.ts.map +1 -0
- package/lib/typescript/network/overrides/matchRule.d.ts +22 -0
- package/lib/typescript/network/overrides/matchRule.d.ts.map +1 -0
- package/lib/typescript/network/overrides/overrideRulesStore.d.ts +205 -0
- package/lib/typescript/network/overrides/overrideRulesStore.d.ts.map +1 -0
- package/lib/typescript/network/overrides/presets.d.ts +38 -0
- package/lib/typescript/network/overrides/presets.d.ts.map +1 -0
- package/lib/typescript/network/overrides/resolveOverride.d.ts +46 -0
- package/lib/typescript/network/overrides/resolveOverride.d.ts.map +1 -0
- package/lib/typescript/network/overrides/types.d.ts +169 -0
- package/lib/typescript/network/overrides/types.d.ts.map +1 -0
- package/lib/typescript/network/sync/networkSyncAdapter.d.ts +73 -0
- package/lib/typescript/network/sync/networkSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/network/types/index.d.ts +10 -0
- package/lib/typescript/network/types/index.d.ts.map +1 -1
- package/lib/typescript/network/utils/networkEventStore.d.ts +14 -0
- package/lib/typescript/network/utils/networkEventStore.d.ts.map +1 -1
- package/lib/typescript/network/utils/networkListener.d.ts +3 -0
- package/lib/typescript/network/utils/networkListener.d.ts.map +1 -1
- package/lib/typescript/network/utils/networkSelectionStore.d.ts +117 -0
- package/lib/typescript/network/utils/networkSelectionStore.d.ts.map +1 -0
- package/lib/typescript/preset.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { useState, useEffect, useMemo } from "react";
|
|
3
|
+
import { useState, useEffect, useMemo, memo } from "react";
|
|
4
4
|
import { View, Text, StyleSheet, ScrollView, TouchableOpacity } from "react-native";
|
|
5
|
-
import { Clock, Upload, Download, AlertCircle, ChevronDown, ChevronUp, Lock, Unlock, FileJson, Filter, Globe, Link, Copy, InlineCopyButton, macOSColors, useFeatureGate, UpgradeModal } from "@buoy-gg/shared-ui";
|
|
5
|
+
import { Clock, Upload, Download, AlertCircle, ChevronDown, ChevronUp, Lock, Unlock, FileJson, Filter, Globe, Link, Copy, FlaskConical, InlineCopyButton, macOSColors, useFeatureGate, UpgradeModal } from "@buoy-gg/shared-ui";
|
|
6
6
|
import { formatBytes, formatDuration, formatHttpStatus } from "../utils/formatting";
|
|
7
7
|
import { formatRelativeTime } from "@buoy-gg/shared-ui";
|
|
8
8
|
import { DataViewer } from "@buoy-gg/shared-ui/dataViewer";
|
|
@@ -16,6 +16,10 @@ import { useNetworkBodyResolver } from "../sync/networkBodyResolver";
|
|
|
16
16
|
*/
|
|
17
17
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
18
18
|
const NEUTRAL_ICON = macOSColors.semantic.success;
|
|
19
|
+
|
|
20
|
+
/** Hoisted so the defaults don't mint a new Set/function per render. */
|
|
21
|
+
const EMPTY_PATTERNS = new Set();
|
|
22
|
+
const noop = () => {};
|
|
19
23
|
/**
|
|
20
24
|
* The measurable slice of a request's lifetime, as proportional bars.
|
|
21
25
|
*
|
|
@@ -69,8 +73,11 @@ const TimingPhases = ({
|
|
|
69
73
|
children: /*#__PURE__*/_jsx(View, {
|
|
70
74
|
style: [styles.phaseBar, {
|
|
71
75
|
backgroundColor: phase.color,
|
|
72
|
-
// A floor so a 1ms phase is still a visible tick
|
|
73
|
-
|
|
76
|
+
// A floor so a 1ms phase is still a visible tick, and a
|
|
77
|
+
// ceiling because `total` and the phases are measured at
|
|
78
|
+
// different points — ttfb can exceed event.duration, which
|
|
79
|
+
// would push the bar past its track and over the label.
|
|
80
|
+
width: `${Math.min(100, Math.max(1, phase.value / span * 100))}%`
|
|
74
81
|
}]
|
|
75
82
|
})
|
|
76
83
|
}), /*#__PURE__*/_jsx(Text, {
|
|
@@ -81,6 +88,17 @@ const TimingPhases = ({
|
|
|
81
88
|
});
|
|
82
89
|
};
|
|
83
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Stand-in for a body tree while the prev/next cursor is still moving.
|
|
93
|
+
*
|
|
94
|
+
* Deliberately a fixed-height nothing: it must cost ~0 to render (that is the
|
|
95
|
+
* entire point) and it must not resize the scroll view as the real tree swaps
|
|
96
|
+
* in, or fast stepping would make the page jump under the reader.
|
|
97
|
+
*/
|
|
98
|
+
const BodyDeferred = () => /*#__PURE__*/_jsx(View, {
|
|
99
|
+
style: styles.bodyDeferred
|
|
100
|
+
});
|
|
101
|
+
|
|
84
102
|
// Component for collapsible sections matching Sentry style
|
|
85
103
|
const CollapsibleSection = ({
|
|
86
104
|
title,
|
|
@@ -260,11 +278,30 @@ const UrlBreakdown = ({
|
|
|
260
278
|
/**
|
|
261
279
|
* Detailed inspector rendering request/response metadata for a single network event. Designed to
|
|
262
280
|
* mimic Sentry’s layout with collapsible sections, diff views, and quick copy affordances.
|
|
281
|
+
*
|
|
282
|
+
* MEMOIZED with profiling evidence, not by reflex. Two render paths hit this
|
|
283
|
+
* subtree with unchanged props:
|
|
284
|
+
*
|
|
285
|
+
* 1. `useLiveNetworkEvent` re-subscribes when the selected ID changes, and
|
|
286
|
+
* `subscribeToEvents` replays immediately — so every step through the
|
|
287
|
+
* prev/next footer committed the SAME event object twice, rendering this
|
|
288
|
+
* whole tree (expanded DataViewer included) a second time for nothing.
|
|
289
|
+
* 2. Any modal-root state change (header search, mode toggle) re-renders the
|
|
290
|
+
* shell, and the detail body has nothing to do with it.
|
|
291
|
+
*
|
|
292
|
+
* Both props besides `event` are stable by construction — `values` is memoized
|
|
293
|
+
* in `useIgnoredPatterns` and `toggle` is module-scope there — so the bail-out
|
|
294
|
+
* actually fires.
|
|
295
|
+
*
|
|
296
|
+
* Measured baseline (js-top, example-dev-build, 5 steps over 109–324KB
|
|
297
|
+
* pokeapi responses): 307ms of React work across 5 steps ≈ 61ms of JS per
|
|
298
|
+
* step. Case 1 alone is half of that, since it re-ran the whole body render.
|
|
263
299
|
*/
|
|
264
|
-
export function NetworkEventDetailView({
|
|
300
|
+
export const NetworkEventDetailView = /*#__PURE__*/memo(function NetworkEventDetailView({
|
|
265
301
|
event,
|
|
266
|
-
ignoredPatterns =
|
|
267
|
-
onTogglePattern =
|
|
302
|
+
ignoredPatterns = EMPTY_PATTERNS,
|
|
303
|
+
onTogglePattern = noop,
|
|
304
|
+
showBodies = true
|
|
268
305
|
}) {
|
|
269
306
|
const status = event.status ? formatHttpStatus(event.status) : null;
|
|
270
307
|
const isPending = !event.status && !event.error;
|
|
@@ -408,8 +445,24 @@ ${JSON.stringify(requestDetails.responseData, null, 2)}
|
|
|
408
445
|
style: styles.httpDurationText,
|
|
409
446
|
children: formatDuration(event.duration)
|
|
410
447
|
})]
|
|
411
|
-
}) : null,
|
|
412
|
-
|
|
448
|
+
}) : null, event.override ? /*#__PURE__*/_jsxs(View, {
|
|
449
|
+
style: styles.overrideBadge,
|
|
450
|
+
children: [/*#__PURE__*/_jsx(FlaskConical, {
|
|
451
|
+
size: 10,
|
|
452
|
+
color: macOSColors.semantic.warning
|
|
453
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
454
|
+
style: styles.overrideBadgeText,
|
|
455
|
+
children: event.override.ruleName || "Overridden"
|
|
456
|
+
})]
|
|
457
|
+
}) : null, isPro ? /*#__PURE__*/_jsx(InlineCopyButton
|
|
458
|
+
// LAZY, not `getFullRequestDetails()`. CopyButton resolves a
|
|
459
|
+
// function value at press time; calling it here instead
|
|
460
|
+
// pretty-printed the headers AND both bodies on every render —
|
|
461
|
+
// four JSON.stringify passes over the full payload just to have
|
|
462
|
+
// a string nobody asked for yet. Same shape NetworkSavedScreen
|
|
463
|
+
// already uses for its copy button.
|
|
464
|
+
, {
|
|
465
|
+
value: getFullRequestDetails,
|
|
413
466
|
buttonStyle: styles.copyFullButton
|
|
414
467
|
}) : /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
415
468
|
style: styles.copyFullButton,
|
|
@@ -543,14 +596,14 @@ ${JSON.stringify(requestDetails.responseData, null, 2)}
|
|
|
543
596
|
defaultOpen: false,
|
|
544
597
|
children: /*#__PURE__*/_jsx(View, {
|
|
545
598
|
style: styles.dataViewerContainer,
|
|
546
|
-
children: /*#__PURE__*/_jsx(DataViewer, {
|
|
599
|
+
children: showBodies ? /*#__PURE__*/_jsx(DataViewer, {
|
|
547
600
|
title: "",
|
|
548
601
|
data: requestData,
|
|
549
602
|
showTypeFilter: true,
|
|
550
603
|
rawMode: true,
|
|
551
604
|
initialExpanded: true,
|
|
552
605
|
disableCopy: !isPro
|
|
553
|
-
})
|
|
606
|
+
}) : /*#__PURE__*/_jsx(BodyDeferred, {})
|
|
554
607
|
})
|
|
555
608
|
}) : requestBodyOmitted ? /*#__PURE__*/_jsx(CollapsibleSection, {
|
|
556
609
|
title: "Request Body",
|
|
@@ -575,14 +628,14 @@ ${JSON.stringify(requestDetails.responseData, null, 2)}
|
|
|
575
628
|
defaultOpen: true,
|
|
576
629
|
children: /*#__PURE__*/_jsx(View, {
|
|
577
630
|
style: styles.dataViewerContainer,
|
|
578
|
-
children: /*#__PURE__*/_jsx(DataViewer, {
|
|
631
|
+
children: showBodies ? /*#__PURE__*/_jsx(DataViewer, {
|
|
579
632
|
title: "",
|
|
580
633
|
data: responseData,
|
|
581
634
|
showTypeFilter: true,
|
|
582
635
|
rawMode: true,
|
|
583
636
|
initialExpanded: true,
|
|
584
637
|
disableCopy: !isPro
|
|
585
|
-
})
|
|
638
|
+
}) : /*#__PURE__*/_jsx(BodyDeferred, {})
|
|
586
639
|
})
|
|
587
640
|
}) : responseBodyOmitted ? /*#__PURE__*/_jsx(CollapsibleSection, {
|
|
588
641
|
title: "Response Body",
|
|
@@ -687,7 +740,7 @@ ${JSON.stringify(requestDetails.responseData, null, 2)}
|
|
|
687
740
|
benefits: ["Copy full request details including headers and body", "Export to JSON, Markdown, or plain text", "Share request data with teammates", "Feed data to AI assistants for debugging"]
|
|
688
741
|
})]
|
|
689
742
|
});
|
|
690
|
-
}
|
|
743
|
+
});
|
|
691
744
|
const styles = StyleSheet.create({
|
|
692
745
|
container: {
|
|
693
746
|
flex: 1,
|
|
@@ -754,6 +807,20 @@ const styles = StyleSheet.create({
|
|
|
754
807
|
color: macOSColors.text.secondary,
|
|
755
808
|
fontSize: 11
|
|
756
809
|
},
|
|
810
|
+
overrideBadge: {
|
|
811
|
+
flexDirection: "row",
|
|
812
|
+
alignItems: "center",
|
|
813
|
+
gap: 4,
|
|
814
|
+
paddingHorizontal: 6,
|
|
815
|
+
paddingVertical: 3,
|
|
816
|
+
borderRadius: 4,
|
|
817
|
+
backgroundColor: macOSColors.semantic.warningBackground
|
|
818
|
+
},
|
|
819
|
+
overrideBadgeText: {
|
|
820
|
+
color: macOSColors.semantic.warning,
|
|
821
|
+
fontSize: 10,
|
|
822
|
+
fontWeight: "700"
|
|
823
|
+
},
|
|
757
824
|
copyFullButton: {
|
|
758
825
|
marginLeft: "auto",
|
|
759
826
|
flexShrink: 0,
|
|
@@ -906,7 +973,8 @@ const styles = StyleSheet.create({
|
|
|
906
973
|
height: 7,
|
|
907
974
|
borderRadius: 4,
|
|
908
975
|
backgroundColor: macOSColors.background.hover,
|
|
909
|
-
justifyContent: "center"
|
|
976
|
+
justifyContent: "center",
|
|
977
|
+
overflow: "hidden"
|
|
910
978
|
},
|
|
911
979
|
phaseBar: {
|
|
912
980
|
height: 7,
|
|
@@ -963,6 +1031,10 @@ const styles = StyleSheet.create({
|
|
|
963
1031
|
marginHorizontal: -12,
|
|
964
1032
|
marginBottom: -12
|
|
965
1033
|
},
|
|
1034
|
+
/** Placeholder for a not-yet-mounted body tree. See BodyDeferred. */
|
|
1035
|
+
bodyDeferred: {
|
|
1036
|
+
height: 120
|
|
1037
|
+
},
|
|
966
1038
|
// Error box
|
|
967
1039
|
errorBox: {
|
|
968
1040
|
flexDirection: "row",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { memo } from "react";
|
|
4
4
|
import { StyleSheet, View, Text } from "react-native";
|
|
5
|
-
import { ChevronRight, Upload, Download, Clock, AlertCircle, Bookmark, Pin, DevToolsCard, MethodBadge, TypeBadge, macOSColors } from "@buoy-gg/shared-ui";
|
|
5
|
+
import { ChevronRight, Upload, Download, Clock, AlertCircle, Bookmark, FlaskConical, Pin, DevToolsCard, MethodBadge, TypeBadge, macOSColors } from "@buoy-gg/shared-ui";
|
|
6
6
|
import { formatBytes, formatDuration } from "../utils/formatting";
|
|
7
7
|
import { formatRelativeTime } from "@buoy-gg/shared-ui";
|
|
8
8
|
import { useTickEveryMinute } from "../hooks/useTickEveryMinute";
|
|
@@ -170,6 +170,7 @@ function NetworkEventItemCompact({
|
|
|
170
170
|
onPress,
|
|
171
171
|
pinned = false,
|
|
172
172
|
saved = false,
|
|
173
|
+
overridden = false,
|
|
173
174
|
onLongPress
|
|
174
175
|
}) {
|
|
175
176
|
const statusColor = getStatusColor(event.status, event.error);
|
|
@@ -208,6 +209,9 @@ function NetworkEventItemCompact({
|
|
|
208
209
|
}) : null, saved ? /*#__PURE__*/_jsx(Bookmark, {
|
|
209
210
|
size: 10,
|
|
210
211
|
color: macOSColors.semantic.debug
|
|
212
|
+
}) : null, overridden || event.override ? /*#__PURE__*/_jsx(FlaskConical, {
|
|
213
|
+
size: 10,
|
|
214
|
+
color: macOSColors.semantic.warning
|
|
211
215
|
}) : null, /*#__PURE__*/_jsx(StatusIndicator, {
|
|
212
216
|
event: event,
|
|
213
217
|
isPending: isPending,
|
|
@@ -23,6 +23,7 @@ import { Bookmark, CheckCircle, XCircle, Clock, Copy, Pin, Trash2, CopyButton, m
|
|
|
23
23
|
import { networkEventStore } from "../utils/networkEventStore";
|
|
24
24
|
import { flagsForEventId, networkSavedStore, FREE_TIER_SAVED_LIMIT, MAX_PINNED, MAX_SAVED } from "../utils/networkSavedStore";
|
|
25
25
|
import { useNetworkSaved } from "../hooks/useNetworkSaved";
|
|
26
|
+
import { useSelectedNetworkEventId } from "../hooks/useNetworkSelection";
|
|
26
27
|
import { useNetworkBadgeCounts } from "../hooks/useNetworkBadgeCounts";
|
|
27
28
|
import { useNetworkHasEvents, useNetworkHasMatches } from "../hooks/useNetworkHasMatches";
|
|
28
29
|
import { generateNetworkCopyText } from "../utils/generateNetworkCopyText";
|
|
@@ -141,12 +142,16 @@ export function NetworkSavedButton({
|
|
|
141
142
|
* The event object is resolved at PRESS time rather than held as a prop: the
|
|
142
143
|
* live store has the fresh copy while the request is in flight, and the saved
|
|
143
144
|
* store is the only copy once it has been cleared or aged out.
|
|
145
|
+
*
|
|
146
|
+
* The selected id is SUBSCRIBED here rather than passed down, so stepping
|
|
147
|
+
* through requests doesn't have to re-render the modal root just to rebuild
|
|
148
|
+
* the header around a new prop.
|
|
144
149
|
*/
|
|
145
150
|
export function NetworkDetailPinActions({
|
|
146
|
-
eventId,
|
|
147
151
|
isPro,
|
|
148
152
|
onUpgradePress
|
|
149
153
|
}) {
|
|
154
|
+
const eventId = useSelectedNetworkEventId();
|
|
150
155
|
const state = useNetworkSaved();
|
|
151
156
|
const {
|
|
152
157
|
pinned,
|
|
@@ -209,7 +214,8 @@ export function NetworkHeaderCopyButton({
|
|
|
209
214
|
ignoredPatterns,
|
|
210
215
|
copySettings,
|
|
211
216
|
paused,
|
|
212
|
-
onUpgradePress
|
|
217
|
+
onUpgradePress,
|
|
218
|
+
label
|
|
213
219
|
}) {
|
|
214
220
|
const hasEvents = useNetworkHasMatches({
|
|
215
221
|
filter,
|
|
@@ -217,15 +223,18 @@ export function NetworkHeaderCopyButton({
|
|
|
217
223
|
paused
|
|
218
224
|
});
|
|
219
225
|
if (!isPro) {
|
|
220
|
-
return /*#__PURE__*/
|
|
226
|
+
return /*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
221
227
|
"sentry-label": "ignore copy pro",
|
|
222
228
|
onPress: onUpgradePress,
|
|
223
|
-
style: [styles.headerActionButton, !hasEvents && styles.headerActionButtonDisabled],
|
|
229
|
+
style: [label ? styles.copyMenuRow : styles.headerActionButton, !hasEvents && styles.headerActionButtonDisabled],
|
|
224
230
|
disabled: !hasEvents,
|
|
225
|
-
children: /*#__PURE__*/_jsx(Copy, {
|
|
231
|
+
children: [/*#__PURE__*/_jsx(Copy, {
|
|
226
232
|
size: 14,
|
|
227
233
|
color: hasEvents ? macOSColors.text.secondary : macOSColors.text.disabled
|
|
228
|
-
})
|
|
234
|
+
}), label ? /*#__PURE__*/_jsx(Text, {
|
|
235
|
+
style: styles.copyMenuLabel,
|
|
236
|
+
children: label
|
|
237
|
+
}) : null]
|
|
229
238
|
});
|
|
230
239
|
}
|
|
231
240
|
return /*#__PURE__*/_jsx(CopyButton
|
|
@@ -234,7 +243,9 @@ export function NetworkHeaderCopyButton({
|
|
|
234
243
|
, {
|
|
235
244
|
value: () => generateNetworkCopyText(filterNetworkEvents(applyIgnoredPatterns(networkEventStore.getEvents(), ignoredPatterns), filter), copySettings),
|
|
236
245
|
size: 14,
|
|
237
|
-
|
|
246
|
+
label: label,
|
|
247
|
+
buttonStyle: label ? styles.copyMenuRow : styles.headerActionButton,
|
|
248
|
+
labelStyle: styles.copyMenuLabel,
|
|
238
249
|
colors: {
|
|
239
250
|
idle: hasEvents ? macOSColors.text.secondary : macOSColors.text.disabled,
|
|
240
251
|
success: macOSColors.semantic.success,
|
|
@@ -244,6 +255,20 @@ export function NetworkHeaderCopyButton({
|
|
|
244
255
|
});
|
|
245
256
|
}
|
|
246
257
|
const styles = StyleSheet.create({
|
|
258
|
+
/** The overflow-menu variant: a full-width row, matching the other items. */
|
|
259
|
+
copyMenuRow: {
|
|
260
|
+
flexDirection: "row",
|
|
261
|
+
alignItems: "center",
|
|
262
|
+
gap: 10,
|
|
263
|
+
paddingHorizontal: 6,
|
|
264
|
+
paddingVertical: 11,
|
|
265
|
+
justifyContent: "flex-start"
|
|
266
|
+
},
|
|
267
|
+
copyMenuLabel: {
|
|
268
|
+
fontSize: 13,
|
|
269
|
+
fontWeight: "600",
|
|
270
|
+
color: macOSColors.text.primary
|
|
271
|
+
},
|
|
247
272
|
headerChipRow: {
|
|
248
273
|
flexDirection: "row",
|
|
249
274
|
alignItems: "center",
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
|
4
|
+
import { absoluteFill, macOSColors } from "@buoy-gg/shared-ui";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The header's overflow menu.
|
|
8
|
+
*
|
|
9
|
+
* The toolbar had grown to three status badges and six icon buttons, which on a
|
|
10
|
+
* 402pt screen meant the pending badge was being overlapped by the search
|
|
11
|
+
* button. Something had to leave, and the rule for deciding what is:
|
|
12
|
+
*
|
|
13
|
+
* **A control that COMMUNICATES STATE stays visible. A destination or a rare
|
|
14
|
+
* action goes in the menu.**
|
|
15
|
+
*
|
|
16
|
+
* That keeps the power toggle (are we capturing?), the overrides flask (is the
|
|
17
|
+
* app being lied to, and how many rules?), the status badges (what happened)
|
|
18
|
+
* and Clear (the reproduce loop is clear → repro → read, and burying the first
|
|
19
|
+
* step doubles it). Search stays because it's the only way through 500 rows.
|
|
20
|
+
*
|
|
21
|
+
* Filters, Saved and Copy leave. Filters is the interesting one — it does show
|
|
22
|
+
* state, so the ⋯ carries a dot when a filter is applied rather than hiding
|
|
23
|
+
* that fact.
|
|
24
|
+
*/
|
|
25
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
26
|
+
export function NetworkHeaderMenuButton({
|
|
27
|
+
onPress,
|
|
28
|
+
isOpen,
|
|
29
|
+
hasIndicator
|
|
30
|
+
}) {
|
|
31
|
+
return /*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
32
|
+
onPress: onPress,
|
|
33
|
+
"sentry-label": "ignore toggle header menu",
|
|
34
|
+
accessibilityLabel: isOpen ? "Close menu" : "More actions",
|
|
35
|
+
style: [styles.button, isOpen && styles.buttonOpen],
|
|
36
|
+
children: [/*#__PURE__*/_jsxs(View, {
|
|
37
|
+
style: styles.dots,
|
|
38
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
39
|
+
style: [styles.dot, isOpen && styles.dotOpen]
|
|
40
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
41
|
+
style: [styles.dot, isOpen && styles.dotOpen]
|
|
42
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
43
|
+
style: [styles.dot, isOpen && styles.dotOpen]
|
|
44
|
+
})]
|
|
45
|
+
}), hasIndicator ? /*#__PURE__*/_jsx(View, {
|
|
46
|
+
style: styles.indicator
|
|
47
|
+
}) : null]
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The dropdown itself, rendered in the modal BODY rather than the header —
|
|
52
|
+
* the header is a fixed-height row and anything overflowing it is clipped, so
|
|
53
|
+
* a panel anchored to the top-right of the body lands exactly where a dropdown
|
|
54
|
+
* from the ⋯ should appear.
|
|
55
|
+
*/
|
|
56
|
+
export function NetworkHeaderMenu({
|
|
57
|
+
onClose,
|
|
58
|
+
children
|
|
59
|
+
}) {
|
|
60
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
61
|
+
style: styles.overlay,
|
|
62
|
+
children: [/*#__PURE__*/_jsx(TouchableOpacity, {
|
|
63
|
+
style: styles.backdrop,
|
|
64
|
+
activeOpacity: 1,
|
|
65
|
+
onPress: onClose,
|
|
66
|
+
"sentry-label": "ignore dismiss header menu"
|
|
67
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
68
|
+
style: styles.panel,
|
|
69
|
+
children: children
|
|
70
|
+
})]
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export function NetworkHeaderMenuItem({
|
|
74
|
+
icon,
|
|
75
|
+
label,
|
|
76
|
+
detail,
|
|
77
|
+
onPress
|
|
78
|
+
}) {
|
|
79
|
+
return /*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
80
|
+
onPress: onPress,
|
|
81
|
+
"sentry-label": "ignore header menu item",
|
|
82
|
+
style: styles.item,
|
|
83
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
84
|
+
style: styles.itemIcon,
|
|
85
|
+
children: icon
|
|
86
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
87
|
+
style: styles.itemLabel,
|
|
88
|
+
children: label
|
|
89
|
+
}), detail ? /*#__PURE__*/_jsx(Text, {
|
|
90
|
+
style: styles.itemDetail,
|
|
91
|
+
children: detail
|
|
92
|
+
}) : null]
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const styles = StyleSheet.create({
|
|
96
|
+
// The same 32×32 box every other header action uses, minus the fill and
|
|
97
|
+
// border. Padding alone gave a 3pt-wide hit area AND a shorter box than its
|
|
98
|
+
// neighbours, which is why the dots sat high in the row; a fixed square
|
|
99
|
+
// centres the glyph on the same baseline as the search/power/clear icons.
|
|
100
|
+
button: {
|
|
101
|
+
width: 32,
|
|
102
|
+
height: 32,
|
|
103
|
+
borderRadius: 8,
|
|
104
|
+
alignItems: "center",
|
|
105
|
+
justifyContent: "center"
|
|
106
|
+
},
|
|
107
|
+
// Only lit while the menu is down — the button is the one thing not covered
|
|
108
|
+
// by the backdrop, so it has to look like the thing that is currently open.
|
|
109
|
+
buttonOpen: {
|
|
110
|
+
backgroundColor: macOSColors.background.hover
|
|
111
|
+
},
|
|
112
|
+
dots: {
|
|
113
|
+
flexDirection: "column",
|
|
114
|
+
gap: 2.5,
|
|
115
|
+
alignItems: "center"
|
|
116
|
+
},
|
|
117
|
+
dot: {
|
|
118
|
+
width: 3,
|
|
119
|
+
height: 3,
|
|
120
|
+
borderRadius: 2,
|
|
121
|
+
backgroundColor: macOSColors.text.secondary
|
|
122
|
+
},
|
|
123
|
+
dotOpen: {
|
|
124
|
+
backgroundColor: macOSColors.text.primary
|
|
125
|
+
},
|
|
126
|
+
indicator: {
|
|
127
|
+
position: "absolute",
|
|
128
|
+
// Sits just up-and-right of the top dot. Anchored to the 32pt box's corner
|
|
129
|
+
// it would float off on its own, since the dot column is only 3pt wide.
|
|
130
|
+
top: 6,
|
|
131
|
+
right: 8,
|
|
132
|
+
width: 6,
|
|
133
|
+
height: 6,
|
|
134
|
+
borderRadius: 3,
|
|
135
|
+
backgroundColor: macOSColors.semantic.info
|
|
136
|
+
},
|
|
137
|
+
overlay: {
|
|
138
|
+
...absoluteFill,
|
|
139
|
+
zIndex: 50
|
|
140
|
+
},
|
|
141
|
+
backdrop: {
|
|
142
|
+
...absoluteFill,
|
|
143
|
+
backgroundColor: "rgba(0,0,0,0.5)"
|
|
144
|
+
},
|
|
145
|
+
panel: {
|
|
146
|
+
position: "absolute",
|
|
147
|
+
top: 6,
|
|
148
|
+
right: 8,
|
|
149
|
+
minWidth: 196,
|
|
150
|
+
paddingVertical: 4,
|
|
151
|
+
borderRadius: 8,
|
|
152
|
+
borderWidth: 1,
|
|
153
|
+
borderColor: macOSColors.border.hover,
|
|
154
|
+
backgroundColor: macOSColors.background.card
|
|
155
|
+
},
|
|
156
|
+
item: {
|
|
157
|
+
flexDirection: "row",
|
|
158
|
+
alignItems: "center",
|
|
159
|
+
gap: 10,
|
|
160
|
+
paddingHorizontal: 12,
|
|
161
|
+
paddingVertical: 11
|
|
162
|
+
},
|
|
163
|
+
itemIcon: {
|
|
164
|
+
width: 16,
|
|
165
|
+
alignItems: "center"
|
|
166
|
+
},
|
|
167
|
+
itemLabel: {
|
|
168
|
+
flex: 1,
|
|
169
|
+
fontSize: 13,
|
|
170
|
+
fontWeight: "600",
|
|
171
|
+
color: macOSColors.text.primary
|
|
172
|
+
},
|
|
173
|
+
itemDetail: {
|
|
174
|
+
fontSize: 11,
|
|
175
|
+
color: macOSColors.text.muted
|
|
176
|
+
}
|
|
177
|
+
});
|
|
@@ -14,11 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
import { useCallback } from "react";
|
|
16
16
|
import { FlatList, StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
|
17
|
-
import { Globe, Pin, Power, macOSColors } from "@buoy-gg/shared-ui";
|
|
17
|
+
import { FlaskConical, Globe, Pin, Power, macOSColors } from "@buoy-gg/shared-ui";
|
|
18
18
|
import { NetworkEventItemCompact } from "./NetworkEventItemCompact";
|
|
19
19
|
import { NetworkUpgradeBanner } from "./NetworkUpgradeBanner";
|
|
20
20
|
import { useNetworkEventList } from "../hooks/useNetworkEventList";
|
|
21
21
|
import { useNetworkSaved } from "../hooks/useNetworkSaved";
|
|
22
|
+
import { useOverrideRules } from "../hooks/useOverrideRules";
|
|
23
|
+
import { ruleMatches } from "../overrides/matchRule";
|
|
22
24
|
import { splitPinned } from "../utils/withPinnedFirst";
|
|
23
25
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
24
26
|
function EmptyState({
|
|
@@ -87,6 +89,62 @@ function PinnedSection({
|
|
|
87
89
|
}, event.id))]
|
|
88
90
|
});
|
|
89
91
|
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The OVERRIDDEN strip, above the pins.
|
|
95
|
+
*
|
|
96
|
+
* An overridden request is the one thing in this list that isn't true — the app
|
|
97
|
+
* got something the server never sent. That has to be impossible to miss, and a
|
|
98
|
+
* glyph on a row twenty scroll-positions down isn't. It sits ABOVE pins because
|
|
99
|
+
* a stale override explains a bug, whereas a pin only marks one.
|
|
100
|
+
*
|
|
101
|
+
* Rows are matched against the RULES rather than filtered on the `override`
|
|
102
|
+
* mark, so the request you built a rule from hoists immediately instead of
|
|
103
|
+
* waiting for the endpoint to be called again.
|
|
104
|
+
*
|
|
105
|
+
* The header button is PAUSE, not "Manage". Flipping overrides off and on is by
|
|
106
|
+
* far the most repeated action in a testing session — force the failure, check
|
|
107
|
+
* the UI, turn it off, check the happy path, turn it back on — and it used to
|
|
108
|
+
* cost a trip to another screen each way. The manager is still one tap away on
|
|
109
|
+
* the toolbar; it just isn't the thing you reach for twenty times an hour.
|
|
110
|
+
*/
|
|
111
|
+
function OverriddenSection({
|
|
112
|
+
events,
|
|
113
|
+
onEventPress,
|
|
114
|
+
onLongPress,
|
|
115
|
+
savedLiveIds,
|
|
116
|
+
paused,
|
|
117
|
+
onTogglePaused
|
|
118
|
+
}) {
|
|
119
|
+
if (events.length === 0) return null;
|
|
120
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
121
|
+
style: [styles.overriddenSection, paused && styles.overriddenSectionOff],
|
|
122
|
+
children: [/*#__PURE__*/_jsxs(View, {
|
|
123
|
+
style: styles.overriddenHeader,
|
|
124
|
+
children: [/*#__PURE__*/_jsx(FlaskConical, {
|
|
125
|
+
size: 11,
|
|
126
|
+
color: paused ? macOSColors.text.muted : macOSColors.semantic.warning
|
|
127
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
128
|
+
style: [styles.overriddenTitle, paused && styles.overriddenTitleOff],
|
|
129
|
+
children: paused ? `PAUSED · ${events.length}` : `OVERRIDDEN · ${events.length}`
|
|
130
|
+
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
131
|
+
onPress: onTogglePaused,
|
|
132
|
+
"sentry-label": "ignore pause overrides",
|
|
133
|
+
style: styles.overriddenManage,
|
|
134
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
135
|
+
style: [styles.overriddenManageText, paused && styles.overriddenTitleOff],
|
|
136
|
+
children: paused ? "Resume" : "Pause"
|
|
137
|
+
})
|
|
138
|
+
})]
|
|
139
|
+
}), events.map(event => /*#__PURE__*/_jsx(NetworkEventItemCompact, {
|
|
140
|
+
event: event,
|
|
141
|
+
onPress: onEventPress,
|
|
142
|
+
onLongPress: onLongPress,
|
|
143
|
+
overridden: true,
|
|
144
|
+
saved: savedLiveIds.has(event.id)
|
|
145
|
+
}, event.id))]
|
|
146
|
+
});
|
|
147
|
+
}
|
|
90
148
|
export function NetworkListScreen({
|
|
91
149
|
visible,
|
|
92
150
|
paused,
|
|
@@ -117,16 +175,41 @@ export function NetworkListScreen({
|
|
|
117
175
|
togglePin,
|
|
118
176
|
clearPinned
|
|
119
177
|
} = useNetworkSaved();
|
|
178
|
+
|
|
179
|
+
// Which rules are live right now — the strip below reflects the rules, not
|
|
180
|
+
// the history, so it's correct the moment a rule is made or removed.
|
|
120
181
|
const {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
182
|
+
rules,
|
|
183
|
+
enabled: overridesEnabled,
|
|
184
|
+
setEnabled,
|
|
185
|
+
isRuleSpent
|
|
186
|
+
} = useOverrideRules();
|
|
124
187
|
|
|
125
188
|
// Stable identity: handed to memoized rows.
|
|
126
189
|
const handleLongPress = useCallback(event => {
|
|
127
190
|
togglePin(event);
|
|
128
191
|
}, [togglePin]);
|
|
192
|
+
|
|
193
|
+
// Everything above is a hook and must run unconditionally; everything below
|
|
194
|
+
// is work. `splitPinned` is an O(n) pass over the whole list, and this screen
|
|
195
|
+
// re-renders on every modal-root state change — including every prev/next
|
|
196
|
+
// step, where it is hidden and the result is thrown away.
|
|
129
197
|
if (!visible) return null;
|
|
198
|
+
const {
|
|
199
|
+
pinned,
|
|
200
|
+
rest
|
|
201
|
+
} = splitPinned(visibleEvents, pinnedEvents, pinnedLiveIds);
|
|
202
|
+
|
|
203
|
+
// Hoist anything an active rule covers. Done after `splitPinned` so a request
|
|
204
|
+
// that is both pinned and overridden appears once, in the louder section.
|
|
205
|
+
// Paused rules still populate the strip — that's how you find the thing you
|
|
206
|
+
// paused in order to resume it. The header says PAUSED instead.
|
|
207
|
+
const activeRules = rules.filter(rule => rule.enabled && !isRuleSpent(rule));
|
|
208
|
+
const isOverridden = event => activeRules.some(rule => ruleMatches(rule, event.url, String(event.method || "GET")));
|
|
209
|
+
const overridden = activeRules.length ? [...pinned, ...rest].filter(isOverridden) : [];
|
|
210
|
+
const overriddenIds = new Set(overridden.map(event => event.id));
|
|
211
|
+
const pinnedRows = pinned.filter(event => !overriddenIds.has(event.id));
|
|
212
|
+
const restRows = overriddenIds.size ? rest.filter(event => !overriddenIds.has(event.id)) : rest;
|
|
130
213
|
const isEnabled = !paused;
|
|
131
214
|
const renderItem = ({
|
|
132
215
|
item
|
|
@@ -158,14 +241,21 @@ export function NetworkListScreen({
|
|
|
158
241
|
style: styles.disabledText,
|
|
159
242
|
children: "Network interception is disabled"
|
|
160
243
|
})]
|
|
161
|
-
}) : null, /*#__PURE__*/_jsx(
|
|
162
|
-
events:
|
|
244
|
+
}) : null, /*#__PURE__*/_jsx(OverriddenSection, {
|
|
245
|
+
events: overridden,
|
|
246
|
+
onEventPress: onEventPress,
|
|
247
|
+
onLongPress: handleLongPress,
|
|
248
|
+
savedLiveIds: savedLiveIds,
|
|
249
|
+
paused: !overridesEnabled,
|
|
250
|
+
onTogglePaused: () => setEnabled(!overridesEnabled)
|
|
251
|
+
}), /*#__PURE__*/_jsx(PinnedSection, {
|
|
252
|
+
events: pinnedRows,
|
|
163
253
|
onEventPress: onEventPress,
|
|
164
254
|
onLongPress: handleLongPress,
|
|
165
255
|
savedLiveIds: savedLiveIds,
|
|
166
256
|
onClearPinned: clearPinned
|
|
167
|
-
}),
|
|
168
|
-
data:
|
|
257
|
+
}), restRows.length > 0 || hasLockedEvents ? /*#__PURE__*/_jsx(FlatList, {
|
|
258
|
+
data: restRows,
|
|
169
259
|
renderItem: renderItem,
|
|
170
260
|
keyExtractor: keyExtractor,
|
|
171
261
|
contentContainerStyle: styles.listContent,
|
|
@@ -194,7 +284,7 @@ export function NetworkListScreen({
|
|
|
194
284
|
extraData: savedLiveIds,
|
|
195
285
|
"sentry-label": "ignore network events list",
|
|
196
286
|
ListFooterComponent: renderListFooter
|
|
197
|
-
}) :
|
|
287
|
+
}) : pinnedRows.length > 0 || overridden.length > 0 ? null : /*#__PURE__*/_jsx(EmptyState, {
|
|
198
288
|
isEnabled: isEnabled
|
|
199
289
|
})]
|
|
200
290
|
});
|
|
@@ -209,6 +299,42 @@ const styles = StyleSheet.create({
|
|
|
209
299
|
* these rows do NOT obey the filters, and the boundary is what tells the
|
|
210
300
|
* user why a request they just filtered out is still on screen.
|
|
211
301
|
*/
|
|
302
|
+
overriddenSection: {
|
|
303
|
+
borderBottomWidth: 1,
|
|
304
|
+
borderBottomColor: macOSColors.semantic.warning + "44",
|
|
305
|
+
backgroundColor: macOSColors.semantic.warningBackground
|
|
306
|
+
},
|
|
307
|
+
overriddenSectionOff: {
|
|
308
|
+
borderBottomColor: macOSColors.border.default,
|
|
309
|
+
backgroundColor: macOSColors.background.card
|
|
310
|
+
},
|
|
311
|
+
overriddenTitleOff: {
|
|
312
|
+
color: macOSColors.text.muted
|
|
313
|
+
},
|
|
314
|
+
overriddenHeader: {
|
|
315
|
+
flexDirection: "row",
|
|
316
|
+
alignItems: "center",
|
|
317
|
+
gap: 6,
|
|
318
|
+
paddingHorizontal: 12,
|
|
319
|
+
paddingTop: 8,
|
|
320
|
+
paddingBottom: 4
|
|
321
|
+
},
|
|
322
|
+
overriddenTitle: {
|
|
323
|
+
flex: 1,
|
|
324
|
+
fontSize: 10,
|
|
325
|
+
fontWeight: "700",
|
|
326
|
+
letterSpacing: 0.8,
|
|
327
|
+
color: macOSColors.semantic.warning
|
|
328
|
+
},
|
|
329
|
+
overriddenManage: {
|
|
330
|
+
paddingHorizontal: 6,
|
|
331
|
+
paddingVertical: 2
|
|
332
|
+
},
|
|
333
|
+
overriddenManageText: {
|
|
334
|
+
fontSize: 10,
|
|
335
|
+
fontWeight: "600",
|
|
336
|
+
color: macOSColors.semantic.warning
|
|
337
|
+
},
|
|
212
338
|
pinnedSection: {
|
|
213
339
|
borderBottomWidth: 1,
|
|
214
340
|
borderBottomColor: macOSColors.border.default,
|