@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
|
@@ -11,6 +11,8 @@ var _NetworkEventItemCompact = require("./NetworkEventItemCompact");
|
|
|
11
11
|
var _NetworkUpgradeBanner = require("./NetworkUpgradeBanner");
|
|
12
12
|
var _useNetworkEventList = require("../hooks/useNetworkEventList");
|
|
13
13
|
var _useNetworkSaved = require("../hooks/useNetworkSaved");
|
|
14
|
+
var _useOverrideRules = require("../hooks/useOverrideRules");
|
|
15
|
+
var _matchRule = require("../overrides/matchRule");
|
|
14
16
|
var _withPinnedFirst = require("../utils/withPinnedFirst");
|
|
15
17
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
16
18
|
/**
|
|
@@ -91,6 +93,62 @@ function PinnedSection({
|
|
|
91
93
|
}, event.id))]
|
|
92
94
|
});
|
|
93
95
|
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The OVERRIDDEN strip, above the pins.
|
|
99
|
+
*
|
|
100
|
+
* An overridden request is the one thing in this list that isn't true — the app
|
|
101
|
+
* got something the server never sent. That has to be impossible to miss, and a
|
|
102
|
+
* glyph on a row twenty scroll-positions down isn't. It sits ABOVE pins because
|
|
103
|
+
* a stale override explains a bug, whereas a pin only marks one.
|
|
104
|
+
*
|
|
105
|
+
* Rows are matched against the RULES rather than filtered on the `override`
|
|
106
|
+
* mark, so the request you built a rule from hoists immediately instead of
|
|
107
|
+
* waiting for the endpoint to be called again.
|
|
108
|
+
*
|
|
109
|
+
* The header button is PAUSE, not "Manage". Flipping overrides off and on is by
|
|
110
|
+
* far the most repeated action in a testing session — force the failure, check
|
|
111
|
+
* the UI, turn it off, check the happy path, turn it back on — and it used to
|
|
112
|
+
* cost a trip to another screen each way. The manager is still one tap away on
|
|
113
|
+
* the toolbar; it just isn't the thing you reach for twenty times an hour.
|
|
114
|
+
*/
|
|
115
|
+
function OverriddenSection({
|
|
116
|
+
events,
|
|
117
|
+
onEventPress,
|
|
118
|
+
onLongPress,
|
|
119
|
+
savedLiveIds,
|
|
120
|
+
paused,
|
|
121
|
+
onTogglePaused
|
|
122
|
+
}) {
|
|
123
|
+
if (events.length === 0) return null;
|
|
124
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
125
|
+
style: [styles.overriddenSection, paused && styles.overriddenSectionOff],
|
|
126
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
127
|
+
style: styles.overriddenHeader,
|
|
128
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.FlaskConical, {
|
|
129
|
+
size: 11,
|
|
130
|
+
color: paused ? _sharedUi.macOSColors.text.muted : _sharedUi.macOSColors.semantic.warning
|
|
131
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
132
|
+
style: [styles.overriddenTitle, paused && styles.overriddenTitleOff],
|
|
133
|
+
children: paused ? `PAUSED · ${events.length}` : `OVERRIDDEN · ${events.length}`
|
|
134
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
135
|
+
onPress: onTogglePaused,
|
|
136
|
+
"sentry-label": "ignore pause overrides",
|
|
137
|
+
style: styles.overriddenManage,
|
|
138
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
139
|
+
style: [styles.overriddenManageText, paused && styles.overriddenTitleOff],
|
|
140
|
+
children: paused ? "Resume" : "Pause"
|
|
141
|
+
})
|
|
142
|
+
})]
|
|
143
|
+
}), events.map(event => /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkEventItemCompact.NetworkEventItemCompact, {
|
|
144
|
+
event: event,
|
|
145
|
+
onPress: onEventPress,
|
|
146
|
+
onLongPress: onLongPress,
|
|
147
|
+
overridden: true,
|
|
148
|
+
saved: savedLiveIds.has(event.id)
|
|
149
|
+
}, event.id))]
|
|
150
|
+
});
|
|
151
|
+
}
|
|
94
152
|
function NetworkListScreen({
|
|
95
153
|
visible,
|
|
96
154
|
paused,
|
|
@@ -121,16 +179,41 @@ function NetworkListScreen({
|
|
|
121
179
|
togglePin,
|
|
122
180
|
clearPinned
|
|
123
181
|
} = (0, _useNetworkSaved.useNetworkSaved)();
|
|
182
|
+
|
|
183
|
+
// Which rules are live right now — the strip below reflects the rules, not
|
|
184
|
+
// the history, so it's correct the moment a rule is made or removed.
|
|
124
185
|
const {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
186
|
+
rules,
|
|
187
|
+
enabled: overridesEnabled,
|
|
188
|
+
setEnabled,
|
|
189
|
+
isRuleSpent
|
|
190
|
+
} = (0, _useOverrideRules.useOverrideRules)();
|
|
128
191
|
|
|
129
192
|
// Stable identity: handed to memoized rows.
|
|
130
193
|
const handleLongPress = (0, _react.useCallback)(event => {
|
|
131
194
|
togglePin(event);
|
|
132
195
|
}, [togglePin]);
|
|
196
|
+
|
|
197
|
+
// Everything above is a hook and must run unconditionally; everything below
|
|
198
|
+
// is work. `splitPinned` is an O(n) pass over the whole list, and this screen
|
|
199
|
+
// re-renders on every modal-root state change — including every prev/next
|
|
200
|
+
// step, where it is hidden and the result is thrown away.
|
|
133
201
|
if (!visible) return null;
|
|
202
|
+
const {
|
|
203
|
+
pinned,
|
|
204
|
+
rest
|
|
205
|
+
} = (0, _withPinnedFirst.splitPinned)(visibleEvents, pinnedEvents, pinnedLiveIds);
|
|
206
|
+
|
|
207
|
+
// Hoist anything an active rule covers. Done after `splitPinned` so a request
|
|
208
|
+
// that is both pinned and overridden appears once, in the louder section.
|
|
209
|
+
// Paused rules still populate the strip — that's how you find the thing you
|
|
210
|
+
// paused in order to resume it. The header says PAUSED instead.
|
|
211
|
+
const activeRules = rules.filter(rule => rule.enabled && !isRuleSpent(rule));
|
|
212
|
+
const isOverridden = event => activeRules.some(rule => (0, _matchRule.ruleMatches)(rule, event.url, String(event.method || "GET")));
|
|
213
|
+
const overridden = activeRules.length ? [...pinned, ...rest].filter(isOverridden) : [];
|
|
214
|
+
const overriddenIds = new Set(overridden.map(event => event.id));
|
|
215
|
+
const pinnedRows = pinned.filter(event => !overriddenIds.has(event.id));
|
|
216
|
+
const restRows = overriddenIds.size ? rest.filter(event => !overriddenIds.has(event.id)) : rest;
|
|
134
217
|
const isEnabled = !paused;
|
|
135
218
|
const renderItem = ({
|
|
136
219
|
item
|
|
@@ -162,14 +245,21 @@ function NetworkListScreen({
|
|
|
162
245
|
style: styles.disabledText,
|
|
163
246
|
children: "Network interception is disabled"
|
|
164
247
|
})]
|
|
165
|
-
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
166
|
-
events:
|
|
248
|
+
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(OverriddenSection, {
|
|
249
|
+
events: overridden,
|
|
250
|
+
onEventPress: onEventPress,
|
|
251
|
+
onLongPress: handleLongPress,
|
|
252
|
+
savedLiveIds: savedLiveIds,
|
|
253
|
+
paused: !overridesEnabled,
|
|
254
|
+
onTogglePaused: () => setEnabled(!overridesEnabled)
|
|
255
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(PinnedSection, {
|
|
256
|
+
events: pinnedRows,
|
|
167
257
|
onEventPress: onEventPress,
|
|
168
258
|
onLongPress: handleLongPress,
|
|
169
259
|
savedLiveIds: savedLiveIds,
|
|
170
260
|
onClearPinned: clearPinned
|
|
171
|
-
}),
|
|
172
|
-
data:
|
|
261
|
+
}), restRows.length > 0 || hasLockedEvents ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
|
|
262
|
+
data: restRows,
|
|
173
263
|
renderItem: renderItem,
|
|
174
264
|
keyExtractor: keyExtractor,
|
|
175
265
|
contentContainerStyle: styles.listContent,
|
|
@@ -198,7 +288,7 @@ function NetworkListScreen({
|
|
|
198
288
|
extraData: savedLiveIds,
|
|
199
289
|
"sentry-label": "ignore network events list",
|
|
200
290
|
ListFooterComponent: renderListFooter
|
|
201
|
-
}) :
|
|
291
|
+
}) : pinnedRows.length > 0 || overridden.length > 0 ? null : /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyState, {
|
|
202
292
|
isEnabled: isEnabled
|
|
203
293
|
})]
|
|
204
294
|
});
|
|
@@ -213,6 +303,42 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
213
303
|
* these rows do NOT obey the filters, and the boundary is what tells the
|
|
214
304
|
* user why a request they just filtered out is still on screen.
|
|
215
305
|
*/
|
|
306
|
+
overriddenSection: {
|
|
307
|
+
borderBottomWidth: 1,
|
|
308
|
+
borderBottomColor: _sharedUi.macOSColors.semantic.warning + "44",
|
|
309
|
+
backgroundColor: _sharedUi.macOSColors.semantic.warningBackground
|
|
310
|
+
},
|
|
311
|
+
overriddenSectionOff: {
|
|
312
|
+
borderBottomColor: _sharedUi.macOSColors.border.default,
|
|
313
|
+
backgroundColor: _sharedUi.macOSColors.background.card
|
|
314
|
+
},
|
|
315
|
+
overriddenTitleOff: {
|
|
316
|
+
color: _sharedUi.macOSColors.text.muted
|
|
317
|
+
},
|
|
318
|
+
overriddenHeader: {
|
|
319
|
+
flexDirection: "row",
|
|
320
|
+
alignItems: "center",
|
|
321
|
+
gap: 6,
|
|
322
|
+
paddingHorizontal: 12,
|
|
323
|
+
paddingTop: 8,
|
|
324
|
+
paddingBottom: 4
|
|
325
|
+
},
|
|
326
|
+
overriddenTitle: {
|
|
327
|
+
flex: 1,
|
|
328
|
+
fontSize: 10,
|
|
329
|
+
fontWeight: "700",
|
|
330
|
+
letterSpacing: 0.8,
|
|
331
|
+
color: _sharedUi.macOSColors.semantic.warning
|
|
332
|
+
},
|
|
333
|
+
overriddenManage: {
|
|
334
|
+
paddingHorizontal: 6,
|
|
335
|
+
paddingVertical: 2
|
|
336
|
+
},
|
|
337
|
+
overriddenManageText: {
|
|
338
|
+
fontSize: 10,
|
|
339
|
+
fontWeight: "600",
|
|
340
|
+
color: _sharedUi.macOSColors.semantic.warning
|
|
341
|
+
},
|
|
216
342
|
pinnedSection: {
|
|
217
343
|
borderBottomWidth: 1,
|
|
218
344
|
borderBottomColor: _sharedUi.macOSColors.border.default,
|
|
@@ -15,10 +15,17 @@ var _NetworkCopySettingsView = require("./NetworkCopySettingsView");
|
|
|
15
15
|
var _NetworkHeaderLive = require("./NetworkHeaderLive");
|
|
16
16
|
var _NetworkListScreen = require("./NetworkListScreen");
|
|
17
17
|
var _NetworkSavedScreen = require("./NetworkSavedScreen");
|
|
18
|
+
var _NetworkOverridesScreen = require("./NetworkOverridesScreen");
|
|
19
|
+
var _NetworkOverridesButton = require("./NetworkOverridesButton");
|
|
20
|
+
var _NetworkOverrideHeaderButton = require("./NetworkOverrideHeaderButton");
|
|
21
|
+
var _NetworkHeaderMenu = require("./NetworkHeaderMenu");
|
|
18
22
|
var _NetworkDetailStepper = require("./NetworkDetailStepper");
|
|
19
23
|
var _useNetworkEventList = require("../hooks/useNetworkEventList");
|
|
20
24
|
var _useLiveNetworkEvent = require("../hooks/useLiveNetworkEvent");
|
|
25
|
+
var _useNetworkSelection = require("../hooks/useNetworkSelection");
|
|
26
|
+
var _networkSelectionStore = require("../utils/networkSelectionStore");
|
|
21
27
|
var _networkSavedStore = require("../utils/networkSavedStore");
|
|
28
|
+
var _types = require("../overrides/types");
|
|
22
29
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
23
30
|
// ============================================================================
|
|
24
31
|
// Screens (rule4 stable router: each gates itself with `return null`; the
|
|
@@ -29,7 +36,6 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
29
36
|
|
|
30
37
|
function NetworkDetailScreen({
|
|
31
38
|
visible,
|
|
32
|
-
eventId,
|
|
33
39
|
paused,
|
|
34
40
|
ignoredPatternValues,
|
|
35
41
|
onTogglePattern,
|
|
@@ -38,34 +44,66 @@ function NetworkDetailScreen({
|
|
|
38
44
|
ignoredPatterns,
|
|
39
45
|
fromSaved,
|
|
40
46
|
savedSearch,
|
|
41
|
-
onSelectEvent,
|
|
42
47
|
applySafeAreaInset
|
|
43
48
|
}) {
|
|
49
|
+
/**
|
|
50
|
+
* The detail renders at the IMMEDIATE selection — every step, no delay.
|
|
51
|
+
* Measured, 100 steps at a 150ms tap interval over 64KB payloads:
|
|
52
|
+
*
|
|
53
|
+
* whole detail, bodies included ... 647ms/step
|
|
54
|
+
* detail with no bodies at all .... 43ms/step (over the 150ms tap gap)
|
|
55
|
+
*
|
|
56
|
+
* So ~93% of a step is the request/response BODY trees, and everything else
|
|
57
|
+
* — status, URL breakdown, timing, header counts — is affordable at any tap
|
|
58
|
+
* rate. Deferring the whole detail (which is what this used to do) therefore
|
|
59
|
+
* bought nothing a user could feel: it made the cheap 43ms wait alongside
|
|
60
|
+
* the expensive 450ms instead of splitting them.
|
|
61
|
+
*
|
|
62
|
+
* So only the expensive part waits. `bodyId` trails `selectedId` by the
|
|
63
|
+
* settle window, so `heavyReady` is false exactly while the cursor is still
|
|
64
|
+
* moving — the JSON trees are skipped during a burst and mount once you land.
|
|
65
|
+
*/
|
|
66
|
+
const eventId = (0, _useNetworkSelection.useSelectedNetworkEventId)();
|
|
67
|
+
const settledId = (0, _useNetworkSelection.useNetworkBodyEventId)();
|
|
68
|
+
const heavyReady = eventId != null && eventId === settledId;
|
|
44
69
|
// Resolve the ID to the live event so a request opened while pending picks
|
|
45
70
|
// up its response/error in place instead of freezing on the snapshot taken
|
|
46
71
|
// when the row was tapped.
|
|
47
72
|
const event = (0, _useLiveNetworkEvent.useLiveNetworkEvent)(eventId, {
|
|
48
73
|
paused: paused || !visible
|
|
49
74
|
});
|
|
50
|
-
|
|
75
|
+
|
|
76
|
+
// Instrumentation for the benchmark harness. Gated on `heavyReady` on
|
|
77
|
+
// purpose: the cheap chrome now renders on every step, so reporting here
|
|
78
|
+
// unconditionally would make `bodyMs` a duplicate of `cursorMs`. What the
|
|
79
|
+
// harness needs to know is when the expensive TREES landed.
|
|
80
|
+
(0, _react.useEffect)(() => {
|
|
81
|
+
if (visible && event && heavyReady) {
|
|
82
|
+
_networkSelectionStore.networkSelectionStore.reportRendered(event.id);
|
|
83
|
+
}
|
|
84
|
+
}, [visible, event, heavyReady]);
|
|
85
|
+
if (!visible) return null;
|
|
51
86
|
// Column: the detail body scrolls, the stepper stays pinned under it. The
|
|
52
87
|
// body owns its scroll here (see `bodyOwnsScroll`) — inside JsModal's
|
|
53
|
-
// wrapper the footer would scroll away with the content.
|
|
88
|
+
// wrapper the footer would scroll away with the content. The spacer keeps
|
|
89
|
+
// the footer at the bottom on the rare frame where the ID resolves to
|
|
90
|
+
// nothing (cleared, aged out, and not saved).
|
|
54
91
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
55
92
|
style: styles.detailRoot,
|
|
56
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkEventDetailView.NetworkEventDetailView, {
|
|
93
|
+
children: [event ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkEventDetailView.NetworkEventDetailView, {
|
|
57
94
|
event: event,
|
|
58
95
|
ignoredPatterns: ignoredPatternValues,
|
|
59
|
-
onTogglePattern: onTogglePattern
|
|
96
|
+
onTogglePattern: onTogglePattern,
|
|
97
|
+
showBodies: heavyReady
|
|
98
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
99
|
+
style: styles.detailBodyFallback
|
|
60
100
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkDetailStepper.NetworkDetailStepper, {
|
|
61
|
-
eventId: event.id,
|
|
62
101
|
paused: paused,
|
|
63
102
|
filter: filter,
|
|
64
103
|
ignoredPatterns: ignoredPatterns,
|
|
65
104
|
isPro: isPro,
|
|
66
105
|
fromSaved: fromSaved,
|
|
67
106
|
savedSearch: savedSearch,
|
|
68
|
-
onSelect: onSelectEvent,
|
|
69
107
|
applySafeAreaInset: applySafeAreaInset
|
|
70
108
|
})]
|
|
71
109
|
});
|
|
@@ -160,11 +198,38 @@ function NetworkModalInner({
|
|
|
160
198
|
if (controlledPause) onPausedChange(value);else setPausedState(value);
|
|
161
199
|
};
|
|
162
200
|
const [filter, setFilter] = (0, _react.useState)({});
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
201
|
+
/**
|
|
202
|
+
* The cursor lives in `networkSelectionStore`, and the root subscribes to
|
|
203
|
+
* the BOOLEAN only. That is the whole point: this component re-renders
|
|
204
|
+
* `JsModal` (which can never bail — its `header` prop is a fresh object
|
|
205
|
+
* every render), the entire header, and all five screens. None of them care
|
|
206
|
+
* WHICH request is selected, only THAT one is, and this flips twice a
|
|
207
|
+
* session instead of once per tap.
|
|
208
|
+
*/
|
|
209
|
+
const hasSelection = (0, _useNetworkSelection.useHasNetworkSelection)();
|
|
166
210
|
const [showFilterView, setShowFilterView] = (0, _react.useState)(false);
|
|
167
211
|
const [showSavedView, setShowSavedView] = (0, _react.useState)(false);
|
|
212
|
+
const [showOverridesView, setShowOverridesView] = (0, _react.useState)(false);
|
|
213
|
+
const [showHeaderMenu, setShowHeaderMenu] = (0, _react.useState)(false);
|
|
214
|
+
/**
|
|
215
|
+
* Overrides are a DEVICE capability — a rule runs inside the app's own
|
|
216
|
+
* `fetch`/`XMLHttpRequest`, which the dashboard doesn't have.
|
|
217
|
+
*
|
|
218
|
+
* That doesn't mean the dashboard can't AUTHOR them: in `inline` mode the
|
|
219
|
+
* rule store runs as a mirror of the connected device (see
|
|
220
|
+
* `overrideRulesStore.enableRemoteMode`), so the screens below are the same
|
|
221
|
+
* ones the phone renders and every edit is forwarded. The one thing the
|
|
222
|
+
* dashboard never does is apply a rule to its own traffic —
|
|
223
|
+
* `disableEngine()` guarantees that.
|
|
224
|
+
*/
|
|
225
|
+
const overridesAvailable = true;
|
|
226
|
+
/**
|
|
227
|
+
* A rule prefilled from a request the user was looking at, handed to the
|
|
228
|
+
* Overrides screen when it mounts. Lives here rather than in that screen
|
|
229
|
+
* because the request that seeds it is on a DIFFERENT screen — this is the
|
|
230
|
+
* one place both are in scope.
|
|
231
|
+
*/
|
|
232
|
+
const [pendingOverrideDraft, setPendingOverrideDraft] = (0, _react.useState)(null);
|
|
168
233
|
const [activeTab, setActiveTab] = (0, _react.useState)("filters");
|
|
169
234
|
const [searchText, setSearchText] = (0, _react.useState)("");
|
|
170
235
|
const [isSearchActive, setIsSearchActive] = (0, _react.useState)(false);
|
|
@@ -236,13 +301,32 @@ function NetworkModalInner({
|
|
|
236
301
|
|
|
237
302
|
// Simple handlers - no useCallback needed per rule2
|
|
238
303
|
const handleBack = () => {
|
|
239
|
-
|
|
304
|
+
_networkSelectionStore.networkSelectionStore.clear();
|
|
240
305
|
};
|
|
241
306
|
|
|
242
307
|
// Stable identity: this is passed down to the memoized list rows.
|
|
243
308
|
const handleEventPress = (0, _react.useCallback)(event => {
|
|
244
|
-
|
|
309
|
+
_networkSelectionStore.networkSelectionStore.select(event.id);
|
|
310
|
+
}, []);
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* "Custom…" in a request's Override section. Stable identity because the
|
|
314
|
+
* detail view is memoized on its props and an unstable callback would defeat
|
|
315
|
+
* the bail-out that keeps prev/next stepping cheap.
|
|
316
|
+
*/
|
|
317
|
+
const handleOverridePress = (0, _react.useCallback)((draft, ruleId) => {
|
|
318
|
+
setPendingOverrideDraft(ruleId ? {
|
|
319
|
+
...draft,
|
|
320
|
+
id: ruleId
|
|
321
|
+
} : draft);
|
|
322
|
+
setShowOverridesView(true);
|
|
323
|
+
// Leave the detail view, or its header would sit on top of the editor.
|
|
324
|
+
_networkSelectionStore.networkSelectionStore.clear();
|
|
245
325
|
}, []);
|
|
326
|
+
|
|
327
|
+
// Stable identity: the Overrides screen adopts the draft in an effect keyed
|
|
328
|
+
// on both, so an unstable callback would re-run it every render.
|
|
329
|
+
const handlePendingOverrideConsumed = (0, _react.useCallback)(() => setPendingOverrideDraft(null), []);
|
|
246
330
|
const handleSearch = text => {
|
|
247
331
|
setSearchText(text);
|
|
248
332
|
setFilter(prev => ({
|
|
@@ -299,19 +383,35 @@ function NetworkModalInner({
|
|
|
299
383
|
}
|
|
300
384
|
|
|
301
385
|
// Event detail view header
|
|
302
|
-
if (
|
|
386
|
+
if (hasSelection) {
|
|
303
387
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
|
|
304
388
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
|
|
305
389
|
onBack: handleBack
|
|
306
390
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
|
|
307
391
|
title: "Request Details",
|
|
308
392
|
centered: true
|
|
309
|
-
}), /*#__PURE__*/(0, _jsxRuntime.
|
|
310
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
311
|
-
|
|
393
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions, {
|
|
394
|
+
children: [overridesAvailable ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkOverrideHeaderButton.NetworkOverrideHeaderButton, {
|
|
395
|
+
onOpen: handleOverridePress
|
|
396
|
+
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkDetailPinActions, {
|
|
312
397
|
isPro: isPro,
|
|
313
398
|
onUpgradePress: () => showUpgrade("saved")
|
|
314
|
-
})
|
|
399
|
+
})]
|
|
400
|
+
})]
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Overrides manager header.
|
|
405
|
+
if (showOverridesView && overridesAvailable) {
|
|
406
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
|
|
407
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
|
|
408
|
+
onBack: () => {
|
|
409
|
+
setShowOverridesView(false);
|
|
410
|
+
setPendingOverrideDraft(null);
|
|
411
|
+
}
|
|
412
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
|
|
413
|
+
title: "Response Overrides",
|
|
414
|
+
centered: true
|
|
315
415
|
})]
|
|
316
416
|
});
|
|
317
417
|
}
|
|
@@ -383,35 +483,26 @@ function NetworkModalInner({
|
|
|
383
483
|
size: 14,
|
|
384
484
|
color: _sharedUi.macOSColors.text.secondary
|
|
385
485
|
})
|
|
386
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
setShowFilterView(true);
|
|
390
|
-
},
|
|
391
|
-
style: [styles.headerActionButton, (filter.status || filter.method || filter.contentType) && styles.activeFilterButton],
|
|
392
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Filter, {
|
|
393
|
-
size: 14,
|
|
394
|
-
color: filter.status || filter.method || filter.contentType ? _sharedUi.macOSColors.semantic.info : _sharedUi.macOSColors.text.muted
|
|
395
|
-
})
|
|
396
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkSavedButton, {
|
|
397
|
-
onPress: () => setShowSavedView(true)
|
|
398
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkHeaderCopyButton, {
|
|
399
|
-
isPro: isPro,
|
|
400
|
-
filter: filter,
|
|
401
|
-
ignoredPatterns: ignoredPatterns,
|
|
402
|
-
copySettings: copySettings,
|
|
403
|
-
paused: paused,
|
|
404
|
-
onUpgradePress: () => showUpgrade("export")
|
|
405
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PowerToggleButton, {
|
|
486
|
+
}), overridesAvailable ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkOverridesButton.NetworkOverridesButton, {
|
|
487
|
+
onPress: () => setShowOverridesView(true)
|
|
488
|
+
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PowerToggleButton, {
|
|
406
489
|
isEnabled: !paused,
|
|
407
490
|
onToggle: () => setPaused(prev => !prev),
|
|
408
491
|
accessibilityLabel: "Toggle network interception"
|
|
409
492
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkClearButton, {
|
|
410
493
|
paused: paused
|
|
494
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuButton, {
|
|
495
|
+
onPress: () => setShowHeaderMenu(prev => !prev),
|
|
496
|
+
isOpen: showHeaderMenu,
|
|
497
|
+
hasIndicator: hasActiveFilter
|
|
411
498
|
})]
|
|
412
499
|
})]
|
|
413
500
|
});
|
|
414
501
|
};
|
|
502
|
+
|
|
503
|
+
// Surfaced on the ⋯ so moving Filters into the menu doesn't hide the one
|
|
504
|
+
// thing that button was communicating.
|
|
505
|
+
const hasActiveFilter = !!(filter.status || filter.method || filter.contentType);
|
|
415
506
|
const persistenceKey = enableSharedModalDimensions ? _sharedUi.devToolsStorageKeys.modal.root() : _sharedUi.devToolsStorageKeys.network.modal();
|
|
416
507
|
if (!visible) return null;
|
|
417
508
|
|
|
@@ -422,13 +513,12 @@ function NetworkModalInner({
|
|
|
422
513
|
// same deal. The DETAIL screen owns it as well, so its prev/next footer
|
|
423
514
|
// stays pinned instead of scrolling away with the body. Filter/copy still
|
|
424
515
|
// use the wrapper.
|
|
425
|
-
const bodyOwnsScroll =
|
|
516
|
+
const bodyOwnsScroll = hasSelection || !showFilterView;
|
|
426
517
|
const body = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
427
518
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
428
519
|
style: styles.container,
|
|
429
520
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(NetworkDetailScreen, {
|
|
430
|
-
visible:
|
|
431
|
-
eventId: selectedEventId,
|
|
521
|
+
visible: hasSelection,
|
|
432
522
|
paused: paused,
|
|
433
523
|
ignoredPatternValues: ignoredPatternValues,
|
|
434
524
|
onTogglePattern: toggleIgnoredPattern,
|
|
@@ -439,13 +529,12 @@ function NetworkModalInner({
|
|
|
439
529
|
// the user came from — and therefore which one to step through.
|
|
440
530
|
,
|
|
441
531
|
fromSaved: showSavedView,
|
|
442
|
-
savedSearch: savedSearch
|
|
443
|
-
onSelectEvent: setSelectedEventId
|
|
532
|
+
savedSearch: savedSearch
|
|
444
533
|
// Inline (desktop panel) has no home indicator to clear.
|
|
445
534
|
,
|
|
446
535
|
applySafeAreaInset: !inline && modalMode === "bottomSheet"
|
|
447
536
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(NetworkFilterScreen, {
|
|
448
|
-
visible: showFilterView && activeTab === "filters" && !
|
|
537
|
+
visible: showFilterView && activeTab === "filters" && !hasSelection,
|
|
449
538
|
paused: paused,
|
|
450
539
|
isPro: isPro,
|
|
451
540
|
filter: filter,
|
|
@@ -455,15 +544,27 @@ function NetworkModalInner({
|
|
|
455
544
|
onAddPattern: addIgnoredPattern,
|
|
456
545
|
onTogglePatternMode: toggleIgnoredPatternMode
|
|
457
546
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(NetworkCopyScreen, {
|
|
458
|
-
visible: showFilterView && activeTab === "copy" && !
|
|
547
|
+
visible: showFilterView && activeTab === "copy" && !hasSelection,
|
|
459
548
|
paused: paused,
|
|
460
549
|
isPro: isPro,
|
|
461
550
|
filter: filter,
|
|
462
551
|
ignoredPatterns: ignoredPatterns,
|
|
463
552
|
settings: copySettings,
|
|
464
553
|
onSettingsChange: setCopySettings
|
|
554
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkOverridesScreen.NetworkOverridesScreen, {
|
|
555
|
+
visible: overridesAvailable && showOverridesView && !hasSelection && !showFilterView,
|
|
556
|
+
isPro: isPro,
|
|
557
|
+
onUpgradePress: () => showUpgrade("overrides"),
|
|
558
|
+
pendingDraft: pendingOverrideDraft,
|
|
559
|
+
onPendingConsumed: handlePendingOverrideConsumed
|
|
560
|
+
// Inline (desktop panel) has no home indicator to clear.
|
|
561
|
+
,
|
|
562
|
+
applySafeAreaInset: !inline && modalMode === "bottomSheet"
|
|
465
563
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkSavedScreen.NetworkSavedScreen, {
|
|
466
|
-
visible: showSavedView &&
|
|
564
|
+
visible: showSavedView && !hasSelection && !showFilterView &&
|
|
565
|
+
// Overrides wins in the header branch too — the two must agree, or
|
|
566
|
+
// one screen renders under the other's header.
|
|
567
|
+
!(showOverridesView && overridesAvailable),
|
|
467
568
|
isPro: isPro,
|
|
468
569
|
copySettings: copySettings,
|
|
469
570
|
search: savedSearch,
|
|
@@ -471,7 +572,7 @@ function NetworkModalInner({
|
|
|
471
572
|
onEventPress: handleEventPress,
|
|
472
573
|
onUpgradePress: () => showUpgrade("saved")
|
|
473
574
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkListScreen.NetworkListScreen, {
|
|
474
|
-
visible:
|
|
575
|
+
visible: !hasSelection && !showFilterView && !showSavedView && !(showOverridesView && overridesAvailable),
|
|
475
576
|
paused: paused,
|
|
476
577
|
filter: filter,
|
|
477
578
|
ignoredPatterns: ignoredPatterns,
|
|
@@ -480,12 +581,51 @@ function NetworkModalInner({
|
|
|
480
581
|
onEventPress: handleEventPress,
|
|
481
582
|
onUpgradePress: () => showUpgrade("export")
|
|
482
583
|
})]
|
|
483
|
-
}), /*#__PURE__*/(0, _jsxRuntime.
|
|
584
|
+
}), showHeaderMenu ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_NetworkHeaderMenu.NetworkHeaderMenu, {
|
|
585
|
+
onClose: () => setShowHeaderMenu(false),
|
|
586
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuItem, {
|
|
587
|
+
icon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Filter, {
|
|
588
|
+
size: 14,
|
|
589
|
+
color: hasActiveFilter ? _sharedUi.macOSColors.semantic.info : _sharedUi.macOSColors.text.secondary
|
|
590
|
+
}),
|
|
591
|
+
label: "Filters",
|
|
592
|
+
detail: hasActiveFilter ? "Active" : undefined,
|
|
593
|
+
onPress: () => {
|
|
594
|
+
setShowHeaderMenu(false);
|
|
595
|
+
setActiveTab("filters");
|
|
596
|
+
setShowFilterView(true);
|
|
597
|
+
}
|
|
598
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuItem, {
|
|
599
|
+
icon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Bookmark, {
|
|
600
|
+
size: 14,
|
|
601
|
+
color: _sharedUi.macOSColors.text.secondary
|
|
602
|
+
}),
|
|
603
|
+
label: "Saved requests",
|
|
604
|
+
onPress: () => {
|
|
605
|
+
setShowHeaderMenu(false);
|
|
606
|
+
setShowSavedView(true);
|
|
607
|
+
}
|
|
608
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
609
|
+
style: styles.menuCopyRow,
|
|
610
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkHeaderCopyButton, {
|
|
611
|
+
isPro: isPro,
|
|
612
|
+
filter: filter,
|
|
613
|
+
ignoredPatterns: ignoredPatterns,
|
|
614
|
+
copySettings: copySettings,
|
|
615
|
+
paused: paused,
|
|
616
|
+
onUpgradePress: () => {
|
|
617
|
+
setShowHeaderMenu(false);
|
|
618
|
+
showUpgrade("export");
|
|
619
|
+
},
|
|
620
|
+
label: "Copy requests"
|
|
621
|
+
})
|
|
622
|
+
})]
|
|
623
|
+
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.UpgradeModal, {
|
|
484
624
|
visible: showUpgradeModal,
|
|
485
625
|
onClose: () => setShowUpgradeModal(false),
|
|
486
|
-
featureName: upgradeReason === "saved" ? "Saved Requests" : "Network Export",
|
|
487
|
-
description: upgradeReason === "saved" ? "Keep the requests that matter. Saved requests survive Clear, app restarts, and the 500-request history cap." : "Export network requests to share with your team, debug APIs, or feed into AI tools.",
|
|
488
|
-
benefits: upgradeReason === "saved" ? [`Save up to ${_networkSavedStore.MAX_SAVED} requests (free keeps ${_networkSavedStore.FREE_TIER_SAVED_LIMIT})`, "Failed requests stay put through a Clear", "Snapshots survive an app restart", "Export saved requests to teammates or AI assistants"] : ["Export to JSON, Markdown, or plain text", "Customizable copy presets (URLs only, LLM-ready, full data)", "Share request details with teammates", "Feed network data directly to AI assistants"]
|
|
626
|
+
featureName: upgradeReason === "saved" ? "Saved Requests" : upgradeReason === "overrides" ? "Response Overrides" : "Network Export",
|
|
627
|
+
description: upgradeReason === "saved" ? "Keep the requests that matter. Saved requests survive Clear, app restarts, and the 500-request history cap." : upgradeReason === "overrides" ? "Force any endpoint to fail, stall or return something else — no backend changes, no code changes. Free keeps one active rule." : "Export network requests to share with your team, debug APIs, or feed into AI tools.",
|
|
628
|
+
benefits: upgradeReason === "overrides" ? [`Run ${_types.MAX_RULES} rules at once (free keeps ${_types.FREE_TIER_RULE_LIMIT})`, "Force a 500, a 401 or an empty list in one tap", "Simulate offline, timeouts and slow connections", "Rules survive an app reload, so you can test the boot path"] : upgradeReason === "saved" ? [`Save up to ${_networkSavedStore.MAX_SAVED} requests (free keeps ${_networkSavedStore.FREE_TIER_SAVED_LIMIT})`, "Failed requests stay put through a Clear", "Snapshots survive an app restart", "Export saved requests to teammates or AI assistants"] : ["Export to JSON, Markdown, or plain text", "Customizable copy presets (URLs only, LLM-ready, full data)", "Share request details with teammates", "Feed network data directly to AI assistants"]
|
|
489
629
|
})]
|
|
490
630
|
});
|
|
491
631
|
|
|
@@ -529,6 +669,10 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
529
669
|
flex: 1,
|
|
530
670
|
minHeight: 0
|
|
531
671
|
},
|
|
672
|
+
/** Holds the footer down when the selected ID resolves to no event. */
|
|
673
|
+
detailBodyFallback: {
|
|
674
|
+
flex: 1
|
|
675
|
+
},
|
|
532
676
|
/** Inline shell — fills the host panel; `minHeight: 0` so the list's own
|
|
533
677
|
* FlatList can scroll instead of stretching the column. */
|
|
534
678
|
inlineRoot: {
|
|
@@ -564,6 +708,9 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
564
708
|
marginLeft: 6,
|
|
565
709
|
padding: 4
|
|
566
710
|
},
|
|
711
|
+
menuCopyRow: {
|
|
712
|
+
paddingHorizontal: 6
|
|
713
|
+
},
|
|
567
714
|
headerActionButton: {
|
|
568
715
|
width: 32,
|
|
569
716
|
height: 32,
|