@buoy-gg/network 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +381 -0
- package/lib/commonjs/index.js +34 -0
- package/lib/commonjs/network/components/NetworkCopySettingsView.js +867 -0
- package/lib/commonjs/network/components/NetworkEventDetailView.js +837 -0
- package/lib/commonjs/network/components/NetworkEventItemCompact.js +323 -0
- package/lib/commonjs/network/components/NetworkFilterViewV3.js +297 -0
- package/lib/commonjs/network/components/NetworkModal.js +937 -0
- package/lib/commonjs/network/hooks/useNetworkEvents.js +320 -0
- package/lib/commonjs/network/hooks/useTickEveryMinute.js +34 -0
- package/lib/commonjs/network/index.js +102 -0
- package/lib/commonjs/network/types/index.js +1 -0
- package/lib/commonjs/network/utils/extractOperationName.js +80 -0
- package/lib/commonjs/network/utils/formatGraphQLVariables.js +219 -0
- package/lib/commonjs/network/utils/formatting.js +30 -0
- package/lib/commonjs/network/utils/networkEventStore.js +269 -0
- package/lib/commonjs/network/utils/networkListener.js +801 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/preset.js +83 -0
- package/lib/module/index.js +7 -0
- package/lib/module/network/components/NetworkCopySettingsView.js +862 -0
- package/lib/module/network/components/NetworkEventDetailView.js +834 -0
- package/lib/module/network/components/NetworkEventItemCompact.js +320 -0
- package/lib/module/network/components/NetworkFilterViewV3.js +293 -0
- package/lib/module/network/components/NetworkModal.js +933 -0
- package/lib/module/network/hooks/useNetworkEvents.js +316 -0
- package/lib/module/network/hooks/useTickEveryMinute.js +29 -0
- package/lib/module/network/index.js +20 -0
- package/lib/module/network/types/index.js +1 -0
- package/lib/module/network/utils/extractOperationName.js +76 -0
- package/lib/module/network/utils/formatGraphQLVariables.js +213 -0
- package/lib/module/network/utils/formatting.js +9 -0
- package/lib/module/network/utils/networkEventStore.js +265 -0
- package/lib/module/network/utils/networkListener.js +791 -0
- package/lib/module/preset.js +79 -0
- package/lib/typescript/index.d.ts +3 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkCopySettingsView.d.ts +26 -0
- package/lib/typescript/network/components/NetworkCopySettingsView.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkEventDetailView.d.ts +13 -0
- package/lib/typescript/network/components/NetworkEventDetailView.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts +12 -0
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkFilterViewV3.d.ts +22 -0
- package/lib/typescript/network/components/NetworkFilterViewV3.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkModal.d.ts +14 -0
- package/lib/typescript/network/components/NetworkModal.d.ts.map +1 -0
- package/lib/typescript/network/hooks/useNetworkEvents.d.ts +72 -0
- package/lib/typescript/network/hooks/useNetworkEvents.d.ts.map +1 -0
- package/lib/typescript/network/hooks/useTickEveryMinute.d.ts +9 -0
- package/lib/typescript/network/hooks/useTickEveryMinute.d.ts.map +1 -0
- package/lib/typescript/network/index.d.ts +12 -0
- package/lib/typescript/network/index.d.ts.map +1 -0
- package/lib/typescript/network/types/index.d.ts +88 -0
- package/lib/typescript/network/types/index.d.ts.map +1 -0
- package/lib/typescript/network/utils/extractOperationName.d.ts +41 -0
- package/lib/typescript/network/utils/extractOperationName.d.ts.map +1 -0
- package/lib/typescript/network/utils/formatGraphQLVariables.d.ts +79 -0
- package/lib/typescript/network/utils/formatGraphQLVariables.d.ts.map +1 -0
- package/lib/typescript/network/utils/formatting.d.ts +6 -0
- package/lib/typescript/network/utils/formatting.d.ts.map +1 -0
- package/lib/typescript/network/utils/networkEventStore.d.ts +81 -0
- package/lib/typescript/network/utils/networkEventStore.d.ts.map +1 -0
- package/lib/typescript/network/utils/networkListener.d.ts +191 -0
- package/lib/typescript/network/utils/networkListener.d.ts.map +1 -0
- package/lib/typescript/preset.d.ts +76 -0
- package/lib/typescript/preset.d.ts.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,937 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.NetworkModal = NetworkModal;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
|
+
var _NetworkEventItemCompact = require("./NetworkEventItemCompact");
|
|
11
|
+
var _NetworkFilterViewV = require("./NetworkFilterViewV3");
|
|
12
|
+
var _useTickEveryMinute = require("../hooks/useTickEveryMinute");
|
|
13
|
+
var _NetworkEventDetailView = require("./NetworkEventDetailView");
|
|
14
|
+
var _NetworkCopySettingsView = require("./NetworkCopySettingsView");
|
|
15
|
+
var _useNetworkEvents = require("../hooks/useNetworkEvents");
|
|
16
|
+
var _formatting = require("../utils/formatting");
|
|
17
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
18
|
+
// Decompose by Responsibility: Extract empty state component
|
|
19
|
+
function EmptyState({
|
|
20
|
+
isEnabled
|
|
21
|
+
}) {
|
|
22
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
23
|
+
style: styles.emptyState,
|
|
24
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Globe, {
|
|
25
|
+
size: 32,
|
|
26
|
+
color: _sharedUi.macOSColors.text.muted
|
|
27
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
28
|
+
style: styles.emptyTitle,
|
|
29
|
+
children: "No network events"
|
|
30
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
31
|
+
style: styles.emptyText,
|
|
32
|
+
children: isEnabled ? "Network requests will appear here" : "Enable interception to start capturing"
|
|
33
|
+
})]
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function NetworkModalInner({
|
|
37
|
+
visible,
|
|
38
|
+
onClose,
|
|
39
|
+
onBack,
|
|
40
|
+
onMinimize,
|
|
41
|
+
enableSharedModalDimensions = false
|
|
42
|
+
}) {
|
|
43
|
+
const {
|
|
44
|
+
isPro
|
|
45
|
+
} = (0, _sharedUi.useFeatureGate)();
|
|
46
|
+
const {
|
|
47
|
+
events,
|
|
48
|
+
stats,
|
|
49
|
+
filter,
|
|
50
|
+
setFilter,
|
|
51
|
+
clearEvents,
|
|
52
|
+
isEnabled,
|
|
53
|
+
toggleInterception,
|
|
54
|
+
hasLockedEvents,
|
|
55
|
+
lockedEventCount,
|
|
56
|
+
isEventLocked,
|
|
57
|
+
requestLimit
|
|
58
|
+
} = (0, _useNetworkEvents.useNetworkEvents)({
|
|
59
|
+
isPro
|
|
60
|
+
});
|
|
61
|
+
const handleModeChange = (0, _react.useCallback)(_mode => {
|
|
62
|
+
// Mode changes handled by JsModal
|
|
63
|
+
}, []);
|
|
64
|
+
const [selectedEvent, setSelectedEvent] = (0, _react.useState)(null);
|
|
65
|
+
const [showFilterView, setShowFilterView] = (0, _react.useState)(false);
|
|
66
|
+
const [activeTab, setActiveTab] = (0, _react.useState)("filters");
|
|
67
|
+
const [searchText, setSearchText] = (0, _react.useState)("");
|
|
68
|
+
const [isSearchActive, setIsSearchActive] = (0, _react.useState)(false);
|
|
69
|
+
const searchInputRef = (0, _react.useRef)(null);
|
|
70
|
+
const [ignoredPatterns, setIgnoredPatterns] = (0, _react.useState)(new Set());
|
|
71
|
+
const [copySettings, setCopySettings] = (0, _react.useState)(_NetworkCopySettingsView.DEFAULT_COPY_SETTINGS);
|
|
72
|
+
const flatListRef = (0, _react.useRef)(null);
|
|
73
|
+
const hasLoadedFilters = (0, _react.useRef)(false);
|
|
74
|
+
const hasLoadedCopySettings = (0, _react.useRef)(false);
|
|
75
|
+
const {
|
|
76
|
+
getItem: safeGetItem,
|
|
77
|
+
setItem: safeSetItem
|
|
78
|
+
} = (0, _sharedUi.useSafeAsyncStorage)();
|
|
79
|
+
const [showUpgradeModal, setShowUpgradeModal] = (0, _react.useState)(false);
|
|
80
|
+
|
|
81
|
+
// Load persisted filters on mount
|
|
82
|
+
(0, _react.useEffect)(() => {
|
|
83
|
+
if (!visible || hasLoadedFilters.current) return;
|
|
84
|
+
const loadFilters = async () => {
|
|
85
|
+
try {
|
|
86
|
+
// Load ignored patterns (using domains key for now)
|
|
87
|
+
const storedPatterns = await safeGetItem(_sharedUi.devToolsStorageKeys.network.ignoredDomains());
|
|
88
|
+
if (storedPatterns) {
|
|
89
|
+
const patterns = JSON.parse(storedPatterns);
|
|
90
|
+
setIgnoredPatterns(new Set(patterns));
|
|
91
|
+
}
|
|
92
|
+
} catch (_error) {
|
|
93
|
+
// Silently fail - filters will use defaults
|
|
94
|
+
} finally {
|
|
95
|
+
hasLoadedFilters.current = true;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
loadFilters();
|
|
99
|
+
}, [visible, safeGetItem]);
|
|
100
|
+
|
|
101
|
+
// Save filters when they change
|
|
102
|
+
(0, _react.useEffect)(() => {
|
|
103
|
+
if (!hasLoadedFilters.current) return; // Don't save on initial load
|
|
104
|
+
|
|
105
|
+
const saveFilters = async () => {
|
|
106
|
+
try {
|
|
107
|
+
// Save ignored patterns
|
|
108
|
+
const patterns = Array.from(ignoredPatterns);
|
|
109
|
+
await safeSetItem(_sharedUi.devToolsStorageKeys.network.ignoredDomains(), JSON.stringify(patterns));
|
|
110
|
+
} catch (_error) {
|
|
111
|
+
// Silently fail - filters will remain in memory
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
saveFilters();
|
|
115
|
+
}, [ignoredPatterns, safeSetItem]);
|
|
116
|
+
|
|
117
|
+
// Load persisted copy settings on mount
|
|
118
|
+
(0, _react.useEffect)(() => {
|
|
119
|
+
if (!visible || hasLoadedCopySettings.current) return;
|
|
120
|
+
const loadCopySettings = async () => {
|
|
121
|
+
try {
|
|
122
|
+
const stored = await safeGetItem(_sharedUi.devToolsStorageKeys.network.copyOptions());
|
|
123
|
+
if (stored) {
|
|
124
|
+
const settings = JSON.parse(stored);
|
|
125
|
+
setCopySettings(settings);
|
|
126
|
+
}
|
|
127
|
+
} catch (_error) {
|
|
128
|
+
// Silently fail - use defaults
|
|
129
|
+
} finally {
|
|
130
|
+
hasLoadedCopySettings.current = true;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
loadCopySettings();
|
|
134
|
+
}, [visible, safeGetItem]);
|
|
135
|
+
|
|
136
|
+
// Save copy settings when they change
|
|
137
|
+
(0, _react.useEffect)(() => {
|
|
138
|
+
if (!hasLoadedCopySettings.current) return; // Don't save on initial load
|
|
139
|
+
|
|
140
|
+
const saveCopySettings = async () => {
|
|
141
|
+
try {
|
|
142
|
+
await safeSetItem(_sharedUi.devToolsStorageKeys.network.copyOptions(), JSON.stringify(copySettings));
|
|
143
|
+
} catch (_error) {
|
|
144
|
+
// Silently fail - settings will remain in memory
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
saveCopySettings();
|
|
148
|
+
}, [copySettings, safeSetItem]);
|
|
149
|
+
|
|
150
|
+
// Simple handlers - no useCallback needed per rule2
|
|
151
|
+
const handleEventPress = event => {
|
|
152
|
+
setSelectedEvent(event);
|
|
153
|
+
};
|
|
154
|
+
const handleBack = () => {
|
|
155
|
+
setSelectedEvent(null);
|
|
156
|
+
};
|
|
157
|
+
const handleSearch = text => {
|
|
158
|
+
setSearchText(text);
|
|
159
|
+
setFilter(prev => ({
|
|
160
|
+
...prev,
|
|
161
|
+
searchText: text
|
|
162
|
+
}));
|
|
163
|
+
};
|
|
164
|
+
(0, _react.useEffect)(() => {
|
|
165
|
+
if (isSearchActive) {
|
|
166
|
+
requestAnimationFrame(() => {
|
|
167
|
+
searchInputRef.current?.focus();
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}, [isSearchActive]);
|
|
171
|
+
|
|
172
|
+
// Filter events based on ignored patterns
|
|
173
|
+
const filteredEvents = (0, _react.useMemo)(() => {
|
|
174
|
+
if (ignoredPatterns.size === 0) return events;
|
|
175
|
+
return events.filter(event => {
|
|
176
|
+
const url = event.url.toLowerCase();
|
|
177
|
+
|
|
178
|
+
// Check if any pattern matches the URL
|
|
179
|
+
const isFiltered = Array.from(ignoredPatterns).some(pattern => url.includes(pattern.toLowerCase()));
|
|
180
|
+
return !isFiltered;
|
|
181
|
+
});
|
|
182
|
+
}, [events, ignoredPatterns]);
|
|
183
|
+
|
|
184
|
+
// Helper to check if payload should be included based on size
|
|
185
|
+
const shouldIncludePayload = (0, _react.useCallback)(data => {
|
|
186
|
+
if (copySettings.bodySizeThreshold === -1) return true;
|
|
187
|
+
if (!data) return true;
|
|
188
|
+
try {
|
|
189
|
+
const size = JSON.stringify(data).length;
|
|
190
|
+
return size < copySettings.bodySizeThreshold * 1024;
|
|
191
|
+
} catch {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}, [copySettings.bodySizeThreshold]);
|
|
195
|
+
|
|
196
|
+
// Generate copy text based on settings
|
|
197
|
+
const generateCopyText = (0, _react.useCallback)(() => {
|
|
198
|
+
let eventsToUse = filteredEvents;
|
|
199
|
+
|
|
200
|
+
// Apply filter mode
|
|
201
|
+
if (copySettings.filterMode === "failed") {
|
|
202
|
+
eventsToUse = eventsToUse.filter(e => e.error || e.status && e.status >= 400);
|
|
203
|
+
} else if (copySettings.filterMode === "success") {
|
|
204
|
+
eventsToUse = eventsToUse.filter(e => e.status && e.status >= 200 && e.status < 300);
|
|
205
|
+
}
|
|
206
|
+
if (eventsToUse.length === 0) {
|
|
207
|
+
return "No requests to copy";
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Plain text format (URLs only)
|
|
211
|
+
if (copySettings.format === "plaintext") {
|
|
212
|
+
return eventsToUse.map(event => `${event.method} ${event.url}`).join("\n");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// JSON format
|
|
216
|
+
if (copySettings.format === "json") {
|
|
217
|
+
const requests = eventsToUse.map(event => {
|
|
218
|
+
const obj = {};
|
|
219
|
+
if (copySettings.includeMethod) {
|
|
220
|
+
obj.method = event.method;
|
|
221
|
+
obj.url = event.url;
|
|
222
|
+
}
|
|
223
|
+
if (copySettings.includeStatus) {
|
|
224
|
+
obj.status = event.status;
|
|
225
|
+
obj.statusText = event.statusText;
|
|
226
|
+
}
|
|
227
|
+
if (copySettings.includeDuration) obj.duration = event.duration;
|
|
228
|
+
if (copySettings.includeTimestamp) obj.timestamp = event.timestamp;
|
|
229
|
+
if (copySettings.includeClient) obj.requestClient = event.requestClient;
|
|
230
|
+
if (copySettings.includeSizes) {
|
|
231
|
+
obj.requestSize = event.requestSize;
|
|
232
|
+
obj.responseSize = event.responseSize;
|
|
233
|
+
}
|
|
234
|
+
if (copySettings.includeErrors && event.error) obj.error = event.error;
|
|
235
|
+
if (copySettings.includeRequestHeaders) {
|
|
236
|
+
obj.requestHeaders = event.requestHeaders;
|
|
237
|
+
}
|
|
238
|
+
if (copySettings.includeResponseHeaders) {
|
|
239
|
+
obj.responseHeaders = event.responseHeaders;
|
|
240
|
+
}
|
|
241
|
+
if (copySettings.includeRequestBody && shouldIncludePayload(event.requestData)) {
|
|
242
|
+
obj.requestData = event.requestData;
|
|
243
|
+
}
|
|
244
|
+
if (copySettings.includeResponseBody && shouldIncludePayload(event.responseData)) {
|
|
245
|
+
obj.responseData = event.responseData;
|
|
246
|
+
}
|
|
247
|
+
return obj;
|
|
248
|
+
});
|
|
249
|
+
return JSON.stringify(requests, null, 2);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Markdown format
|
|
253
|
+
const requests = eventsToUse.map((event, index) => {
|
|
254
|
+
let md = `# Request ${index + 1}\n\n`;
|
|
255
|
+
if (copySettings.includeMethod) {
|
|
256
|
+
md += `**Method:** ${event.method}\n`;
|
|
257
|
+
md += `**URL:** ${event.url}\n`;
|
|
258
|
+
}
|
|
259
|
+
if (copySettings.includeStatus) {
|
|
260
|
+
const status = event.status || "Pending";
|
|
261
|
+
md += `**Status:** ${status}${event.statusText ? ` (${event.statusText})` : ""}\n`;
|
|
262
|
+
}
|
|
263
|
+
if (copySettings.includeClient && event.requestClient) {
|
|
264
|
+
md += `**Client:** ${event.requestClient}\n`;
|
|
265
|
+
}
|
|
266
|
+
if (copySettings.includeDuration && event.duration) {
|
|
267
|
+
md += `**Duration:** ${event.duration}ms\n`;
|
|
268
|
+
}
|
|
269
|
+
if (copySettings.includeTimestamp) {
|
|
270
|
+
md += `**Timestamp:** ${new Date(event.timestamp).toISOString()}\n`;
|
|
271
|
+
}
|
|
272
|
+
if (copySettings.includeSizes) {
|
|
273
|
+
const reqSize = event.requestSize ? (0, _formatting.formatBytes)(event.requestSize) : "N/A";
|
|
274
|
+
const resSize = event.responseSize ? (0, _formatting.formatBytes)(event.responseSize) : "N/A";
|
|
275
|
+
md += `**Request Size:** ${reqSize}\n`;
|
|
276
|
+
md += `**Response Size:** ${resSize}\n`;
|
|
277
|
+
}
|
|
278
|
+
if (copySettings.includeErrors && event.error) {
|
|
279
|
+
md += `**Error:** ${event.error}\n`;
|
|
280
|
+
}
|
|
281
|
+
if (copySettings.includeRequestHeaders && Object.keys(event.requestHeaders).length > 0) {
|
|
282
|
+
md += `\n## Request Headers\n\`\`\`json\n${JSON.stringify(event.requestHeaders, null, 2)}\n\`\`\`\n`;
|
|
283
|
+
}
|
|
284
|
+
if (copySettings.includeRequestBody) {
|
|
285
|
+
md += `\n## Request Data\n`;
|
|
286
|
+
if (shouldIncludePayload(event.requestData)) {
|
|
287
|
+
md += `\`\`\`json\n${JSON.stringify(event.requestData, null, 2)}\n\`\`\`\n`;
|
|
288
|
+
} else {
|
|
289
|
+
const size = event.requestSize ? (0, _formatting.formatBytes)(event.requestSize) : "Unknown size";
|
|
290
|
+
md += `_Payload omitted (${size}). Exceeds ${copySettings.bodySizeThreshold}KB threshold._\n`;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (copySettings.includeResponseHeaders && Object.keys(event.responseHeaders).length > 0) {
|
|
294
|
+
md += `\n## Response Headers\n\`\`\`json\n${JSON.stringify(event.responseHeaders, null, 2)}\n\`\`\`\n`;
|
|
295
|
+
}
|
|
296
|
+
if (copySettings.includeResponseBody) {
|
|
297
|
+
md += `\n## Response Data\n`;
|
|
298
|
+
if (shouldIncludePayload(event.responseData)) {
|
|
299
|
+
md += `\`\`\`json\n${JSON.stringify(event.responseData, null, 2)}\n\`\`\`\n`;
|
|
300
|
+
} else {
|
|
301
|
+
const size = event.responseSize ? (0, _formatting.formatBytes)(event.responseSize) : "Unknown size";
|
|
302
|
+
md += `_Payload omitted (${size}). Exceeds ${copySettings.bodySizeThreshold}KB threshold._\n`;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
md += `\n---\n`;
|
|
306
|
+
return md;
|
|
307
|
+
}).join("\n");
|
|
308
|
+
const header = `# Network Requests (${eventsToUse.length} total)\n\n`;
|
|
309
|
+
return header + requests;
|
|
310
|
+
}, [filteredEvents, copySettings, shouldIncludePayload]);
|
|
311
|
+
|
|
312
|
+
// Memoized copy text value for CopyButton
|
|
313
|
+
const copyTextValue = (0, _react.useMemo)(() => {
|
|
314
|
+
if (filteredEvents.length === 0) return "";
|
|
315
|
+
return generateCopyText();
|
|
316
|
+
}, [filteredEvents.length, generateCopyText]);
|
|
317
|
+
|
|
318
|
+
// FlatList optimization - only keep what's needed for FlatList performance
|
|
319
|
+
const keyExtractor = item => item.id;
|
|
320
|
+
|
|
321
|
+
// Filter to only show unlocked events in the list
|
|
322
|
+
const unlockedEvents = (0, _react.useMemo)(() => {
|
|
323
|
+
return filteredEvents.filter(event => !isEventLocked(event.id));
|
|
324
|
+
}, [filteredEvents, isEventLocked]);
|
|
325
|
+
|
|
326
|
+
// Keep renderItem memoized for FlatList performance (justified by FlatList docs)
|
|
327
|
+
const renderItem = (0, _react.useMemo)(() => {
|
|
328
|
+
return ({
|
|
329
|
+
item
|
|
330
|
+
}) => {
|
|
331
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkEventItemCompact.NetworkEventItemCompact, {
|
|
332
|
+
event: item,
|
|
333
|
+
onPress: handleEventPress
|
|
334
|
+
});
|
|
335
|
+
};
|
|
336
|
+
}, []); // handleEventPress defined inline
|
|
337
|
+
|
|
338
|
+
// Footer component showing upgrade banner when events are locked
|
|
339
|
+
const renderListFooter = (0, _react.useCallback)(() => {
|
|
340
|
+
if (!hasLockedEvents) return null;
|
|
341
|
+
const isSearching = searchText.length > 0;
|
|
342
|
+
const bannerText = isSearching ? `${lockedEventCount} matching ${lockedEventCount === 1 ? 'request' : 'requests'} in locked history` : `${lockedEventCount} requests locked`;
|
|
343
|
+
const subtextMessage = isSearching ? "Upgrade to Pro to search your full request history" : "Upgrade to Pro to unlock full request history";
|
|
344
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
345
|
+
style: styles.limitBanner,
|
|
346
|
+
onPress: () => setShowUpgradeModal(true),
|
|
347
|
+
activeOpacity: 0.8,
|
|
348
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
349
|
+
style: styles.limitBannerContent,
|
|
350
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
351
|
+
style: styles.limitBannerLeft,
|
|
352
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Zap, {
|
|
353
|
+
size: 16,
|
|
354
|
+
color: "#20C997"
|
|
355
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
356
|
+
style: styles.limitBannerText,
|
|
357
|
+
children: bannerText
|
|
358
|
+
})]
|
|
359
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ProBadge, {})]
|
|
360
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
361
|
+
style: styles.limitBannerSubtext,
|
|
362
|
+
children: subtextMessage
|
|
363
|
+
})]
|
|
364
|
+
});
|
|
365
|
+
}, [hasLockedEvents, lockedEventCount, searchText]);
|
|
366
|
+
|
|
367
|
+
// Compact header with actions (like Sentry/Storage modals)
|
|
368
|
+
const renderHeaderContent = () => {
|
|
369
|
+
// Filter view header with tabs
|
|
370
|
+
if (showFilterView) {
|
|
371
|
+
// Copy tab is always visible and clickable - gating handled inside the view
|
|
372
|
+
const tabs = [{
|
|
373
|
+
key: "filters",
|
|
374
|
+
label: "Filters"
|
|
375
|
+
}, {
|
|
376
|
+
key: "copy",
|
|
377
|
+
label: "Copy"
|
|
378
|
+
}];
|
|
379
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
|
|
380
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
|
|
381
|
+
onBack: () => setShowFilterView(false)
|
|
382
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
|
|
383
|
+
title: "",
|
|
384
|
+
noMargin: true,
|
|
385
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.TabSelector, {
|
|
386
|
+
tabs: tabs,
|
|
387
|
+
activeTab: activeTab,
|
|
388
|
+
onTabChange: tab => setActiveTab(tab)
|
|
389
|
+
})
|
|
390
|
+
})]
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Event detail view header
|
|
395
|
+
if (selectedEvent) {
|
|
396
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
|
|
397
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
|
|
398
|
+
onBack: handleBack
|
|
399
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
|
|
400
|
+
title: "Request Details",
|
|
401
|
+
centered: true
|
|
402
|
+
})]
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Main list view header with search and filters
|
|
407
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
|
|
408
|
+
children: [onBack && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
|
|
409
|
+
onBack: onBack
|
|
410
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
|
|
411
|
+
title: "",
|
|
412
|
+
children: isSearchActive ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
413
|
+
style: styles.headerSearchContainer,
|
|
414
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Search, {
|
|
415
|
+
size: 14,
|
|
416
|
+
color: _sharedUi.macOSColors.text.secondary
|
|
417
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
|
|
418
|
+
ref: searchInputRef,
|
|
419
|
+
style: styles.headerSearchInput,
|
|
420
|
+
placeholder: "Search URL, method, operation, error...",
|
|
421
|
+
placeholderTextColor: _sharedUi.macOSColors.text.muted,
|
|
422
|
+
value: searchText,
|
|
423
|
+
onChangeText: handleSearch,
|
|
424
|
+
onSubmitEditing: () => setIsSearchActive(false),
|
|
425
|
+
onBlur: () => setIsSearchActive(false),
|
|
426
|
+
"sentry-label": "ignore network search header",
|
|
427
|
+
accessibilityLabel: "Search network requests",
|
|
428
|
+
autoCapitalize: "none",
|
|
429
|
+
autoCorrect: false,
|
|
430
|
+
returnKeyType: "search"
|
|
431
|
+
}), searchText.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
432
|
+
onPress: () => {
|
|
433
|
+
handleSearch("");
|
|
434
|
+
setIsSearchActive(false);
|
|
435
|
+
},
|
|
436
|
+
"sentry-label": "ignore clear search header",
|
|
437
|
+
style: styles.headerSearchClear,
|
|
438
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
|
|
439
|
+
size: 14,
|
|
440
|
+
color: _sharedUi.macOSColors.text.secondary
|
|
441
|
+
})
|
|
442
|
+
}) : null]
|
|
443
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
444
|
+
style: styles.headerChipRow,
|
|
445
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
446
|
+
style: [styles.headerChip, filter.status === "success" && styles.headerChipActive],
|
|
447
|
+
onPress: () => setFilter({
|
|
448
|
+
...filter,
|
|
449
|
+
status: filter.status === "success" ? undefined : "success"
|
|
450
|
+
}),
|
|
451
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CheckCircle, {
|
|
452
|
+
size: 12,
|
|
453
|
+
color: _sharedUi.macOSColors.semantic.success
|
|
454
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
455
|
+
style: [styles.headerChipValue, {
|
|
456
|
+
color: _sharedUi.macOSColors.semantic.success
|
|
457
|
+
}],
|
|
458
|
+
children: stats.successfulRequests
|
|
459
|
+
})]
|
|
460
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
461
|
+
style: [styles.headerChip, filter.status === "error" && styles.headerChipActive],
|
|
462
|
+
onPress: () => setFilter({
|
|
463
|
+
...filter,
|
|
464
|
+
status: filter.status === "error" ? undefined : "error"
|
|
465
|
+
}),
|
|
466
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.XCircle, {
|
|
467
|
+
size: 12,
|
|
468
|
+
color: _sharedUi.macOSColors.semantic.error
|
|
469
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
470
|
+
style: [styles.headerChipValue, {
|
|
471
|
+
color: _sharedUi.macOSColors.semantic.error
|
|
472
|
+
}],
|
|
473
|
+
children: stats.failedRequests
|
|
474
|
+
})]
|
|
475
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
476
|
+
style: [styles.headerChip, filter.status === "pending" && styles.headerChipActive],
|
|
477
|
+
onPress: () => setFilter({
|
|
478
|
+
...filter,
|
|
479
|
+
status: filter.status === "pending" ? undefined : "pending"
|
|
480
|
+
}),
|
|
481
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Clock, {
|
|
482
|
+
size: 12,
|
|
483
|
+
color: _sharedUi.macOSColors.semantic.warning
|
|
484
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
485
|
+
style: [styles.headerChipValue, {
|
|
486
|
+
color: _sharedUi.macOSColors.semantic.warning
|
|
487
|
+
}],
|
|
488
|
+
children: stats.pendingRequests
|
|
489
|
+
})]
|
|
490
|
+
})]
|
|
491
|
+
})
|
|
492
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions, {
|
|
493
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
494
|
+
"sentry-label": "ignore open search",
|
|
495
|
+
onPress: () => setIsSearchActive(true),
|
|
496
|
+
style: styles.headerActionButton,
|
|
497
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Search, {
|
|
498
|
+
size: 14,
|
|
499
|
+
color: _sharedUi.macOSColors.text.secondary
|
|
500
|
+
})
|
|
501
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
502
|
+
"sentry-label": "ignore filter",
|
|
503
|
+
onPress: () => {
|
|
504
|
+
setShowFilterView(true);
|
|
505
|
+
},
|
|
506
|
+
style: [styles.headerActionButton, (filter.status || filter.method || filter.contentType) && styles.activeFilterButton],
|
|
507
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Filter, {
|
|
508
|
+
size: 14,
|
|
509
|
+
color: filter.status || filter.method || filter.contentType ? _sharedUi.macOSColors.semantic.info : _sharedUi.macOSColors.text.muted
|
|
510
|
+
})
|
|
511
|
+
}), isPro ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CopyButton, {
|
|
512
|
+
value: copyTextValue,
|
|
513
|
+
size: 14,
|
|
514
|
+
buttonStyle: styles.headerActionButton,
|
|
515
|
+
colors: {
|
|
516
|
+
idle: filteredEvents.length > 0 ? _sharedUi.macOSColors.text.secondary : _sharedUi.macOSColors.text.disabled,
|
|
517
|
+
success: _sharedUi.macOSColors.semantic.success,
|
|
518
|
+
error: _sharedUi.macOSColors.semantic.error
|
|
519
|
+
},
|
|
520
|
+
disabled: filteredEvents.length === 0
|
|
521
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
522
|
+
"sentry-label": "ignore copy pro",
|
|
523
|
+
onPress: () => setShowUpgradeModal(true),
|
|
524
|
+
style: [styles.headerActionButton, filteredEvents.length === 0 && styles.headerActionButtonDisabled],
|
|
525
|
+
disabled: filteredEvents.length === 0,
|
|
526
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Copy, {
|
|
527
|
+
size: 14,
|
|
528
|
+
color: filteredEvents.length > 0 ? _sharedUi.macOSColors.text.secondary : _sharedUi.macOSColors.text.disabled
|
|
529
|
+
})
|
|
530
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
531
|
+
"sentry-label": "ignore toggle interception",
|
|
532
|
+
onPress: toggleInterception,
|
|
533
|
+
style: [styles.headerActionButton, isEnabled ? styles.startButton : styles.stopButton],
|
|
534
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Power, {
|
|
535
|
+
size: 14,
|
|
536
|
+
color: isEnabled ? _sharedUi.macOSColors.semantic.success : _sharedUi.macOSColors.semantic.error
|
|
537
|
+
})
|
|
538
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
539
|
+
"sentry-label": "ignore clear events",
|
|
540
|
+
onPress: clearEvents,
|
|
541
|
+
style: [styles.headerActionButton, events.length === 0 && styles.headerActionButtonDisabled],
|
|
542
|
+
disabled: events.length === 0,
|
|
543
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
|
|
544
|
+
size: 14,
|
|
545
|
+
color: events.length > 0 ? _sharedUi.macOSColors.text.muted : _sharedUi.macOSColors.text.disabled
|
|
546
|
+
})
|
|
547
|
+
})]
|
|
548
|
+
})]
|
|
549
|
+
});
|
|
550
|
+
};
|
|
551
|
+
const persistenceKey = enableSharedModalDimensions ? _sharedUi.devToolsStorageKeys.modal.root() : _sharedUi.devToolsStorageKeys.network.modal();
|
|
552
|
+
if (!visible) return null;
|
|
553
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.JsModal, {
|
|
554
|
+
visible: visible,
|
|
555
|
+
onClose: onClose,
|
|
556
|
+
onMinimize: onMinimize,
|
|
557
|
+
persistenceKey: persistenceKey,
|
|
558
|
+
header: {
|
|
559
|
+
showToggleButton: true,
|
|
560
|
+
customContent: renderHeaderContent()
|
|
561
|
+
},
|
|
562
|
+
onModeChange: handleModeChange,
|
|
563
|
+
enablePersistence: true,
|
|
564
|
+
initialMode: "bottomSheet",
|
|
565
|
+
enableGlitchEffects: true,
|
|
566
|
+
styles: {},
|
|
567
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
568
|
+
style: styles.container,
|
|
569
|
+
children: selectedEvent ?
|
|
570
|
+
/*#__PURE__*/
|
|
571
|
+
/* Show detail view if event is selected */
|
|
572
|
+
(0, _jsxRuntime.jsx)(_NetworkEventDetailView.NetworkEventDetailView, {
|
|
573
|
+
event: selectedEvent,
|
|
574
|
+
ignoredPatterns: ignoredPatterns,
|
|
575
|
+
onTogglePattern: pattern => {
|
|
576
|
+
const newPatterns = new Set(ignoredPatterns);
|
|
577
|
+
if (newPatterns.has(pattern)) {
|
|
578
|
+
newPatterns.delete(pattern);
|
|
579
|
+
} else {
|
|
580
|
+
newPatterns.add(pattern);
|
|
581
|
+
}
|
|
582
|
+
setIgnoredPatterns(newPatterns);
|
|
583
|
+
}
|
|
584
|
+
}) : showFilterView ? (/* Show filter/copy view based on active tab */
|
|
585
|
+
activeTab === "copy" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkCopySettingsView.NetworkCopySettingsView, {
|
|
586
|
+
settings: copySettings,
|
|
587
|
+
onSettingsChange: setCopySettings,
|
|
588
|
+
events: filteredEvents
|
|
589
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkFilterViewV.NetworkFilterViewV3, {
|
|
590
|
+
events: events,
|
|
591
|
+
filter: filter,
|
|
592
|
+
onFilterChange: setFilter,
|
|
593
|
+
ignoredPatterns: ignoredPatterns,
|
|
594
|
+
onTogglePattern: pattern => {
|
|
595
|
+
const newPatterns = new Set(ignoredPatterns);
|
|
596
|
+
if (newPatterns.has(pattern)) {
|
|
597
|
+
newPatterns.delete(pattern);
|
|
598
|
+
} else {
|
|
599
|
+
newPatterns.add(pattern);
|
|
600
|
+
}
|
|
601
|
+
setIgnoredPatterns(newPatterns);
|
|
602
|
+
},
|
|
603
|
+
onAddPattern: pattern => {
|
|
604
|
+
const newPatterns = new Set(ignoredPatterns);
|
|
605
|
+
newPatterns.add(pattern);
|
|
606
|
+
setIgnoredPatterns(newPatterns);
|
|
607
|
+
}
|
|
608
|
+
})) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
609
|
+
children: [!isEnabled ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
610
|
+
style: styles.disabledBanner,
|
|
611
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Power, {
|
|
612
|
+
size: 14,
|
|
613
|
+
color: _sharedUi.macOSColors.semantic.warning
|
|
614
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
615
|
+
style: styles.disabledText,
|
|
616
|
+
children: "Network interception is disabled"
|
|
617
|
+
})]
|
|
618
|
+
}) : null, unlockedEvents.length > 0 || hasLockedEvents ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
|
|
619
|
+
ref: flatListRef,
|
|
620
|
+
data: unlockedEvents,
|
|
621
|
+
renderItem: renderItem,
|
|
622
|
+
keyExtractor: keyExtractor,
|
|
623
|
+
contentContainerStyle: styles.listContent,
|
|
624
|
+
showsVerticalScrollIndicator: true,
|
|
625
|
+
removeClippedSubviews: true,
|
|
626
|
+
onEndReachedThreshold: 0.8,
|
|
627
|
+
initialNumToRender: 10,
|
|
628
|
+
maxToRenderPerBatch: 10,
|
|
629
|
+
windowSize: 10,
|
|
630
|
+
scrollEnabled: false,
|
|
631
|
+
"sentry-label": "ignore network events list",
|
|
632
|
+
ListFooterComponent: renderListFooter
|
|
633
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyState, {
|
|
634
|
+
isEnabled: isEnabled
|
|
635
|
+
})]
|
|
636
|
+
})
|
|
637
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.UpgradeModal, {
|
|
638
|
+
visible: showUpgradeModal,
|
|
639
|
+
onClose: () => setShowUpgradeModal(false),
|
|
640
|
+
featureName: "Network Export",
|
|
641
|
+
description: "Export network requests to share with your team, debug APIs, or feed into AI tools.",
|
|
642
|
+
benefits: ["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"]
|
|
643
|
+
})]
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
const styles = _reactNative.StyleSheet.create({
|
|
647
|
+
container: {
|
|
648
|
+
flex: 1,
|
|
649
|
+
backgroundColor: _sharedUi.macOSColors.background.base
|
|
650
|
+
},
|
|
651
|
+
// Compact header styles matching Sentry/Storage modals
|
|
652
|
+
headerContainer: {
|
|
653
|
+
flexDirection: "row",
|
|
654
|
+
alignItems: "center",
|
|
655
|
+
flex: 1,
|
|
656
|
+
gap: 8,
|
|
657
|
+
minHeight: 32,
|
|
658
|
+
paddingLeft: 4
|
|
659
|
+
},
|
|
660
|
+
headerTitle: {
|
|
661
|
+
color: _sharedUi.macOSColors.text.primary,
|
|
662
|
+
fontSize: 14,
|
|
663
|
+
fontWeight: "500",
|
|
664
|
+
flex: 1,
|
|
665
|
+
marginLeft: 8
|
|
666
|
+
},
|
|
667
|
+
headerStats: {
|
|
668
|
+
display: "none"
|
|
669
|
+
},
|
|
670
|
+
headerStatsText: {
|
|
671
|
+
fontSize: 12,
|
|
672
|
+
color: _sharedUi.macOSColors.text.muted,
|
|
673
|
+
fontWeight: "500"
|
|
674
|
+
},
|
|
675
|
+
headerFilteredText: {
|
|
676
|
+
fontSize: 11,
|
|
677
|
+
color: _sharedUi.macOSColors.semantic.warning,
|
|
678
|
+
fontWeight: "500",
|
|
679
|
+
marginLeft: 4
|
|
680
|
+
},
|
|
681
|
+
headerActions: {
|
|
682
|
+
flexDirection: "row",
|
|
683
|
+
gap: 6,
|
|
684
|
+
marginLeft: "auto",
|
|
685
|
+
marginRight: 4
|
|
686
|
+
},
|
|
687
|
+
headerCenterArea: {
|
|
688
|
+
flex: 1,
|
|
689
|
+
marginHorizontal: 8
|
|
690
|
+
},
|
|
691
|
+
headerSearchContainer: {
|
|
692
|
+
flexDirection: "row",
|
|
693
|
+
alignItems: "center",
|
|
694
|
+
backgroundColor: _sharedUi.macOSColors.background.input,
|
|
695
|
+
borderRadius: 10,
|
|
696
|
+
borderWidth: 1,
|
|
697
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
698
|
+
paddingHorizontal: 12,
|
|
699
|
+
paddingVertical: 5
|
|
700
|
+
},
|
|
701
|
+
headerSearchInput: {
|
|
702
|
+
flex: 1,
|
|
703
|
+
color: _sharedUi.macOSColors.text.primary,
|
|
704
|
+
fontSize: 13,
|
|
705
|
+
marginLeft: 6,
|
|
706
|
+
paddingVertical: 2
|
|
707
|
+
},
|
|
708
|
+
headerSearchClear: {
|
|
709
|
+
marginLeft: 6,
|
|
710
|
+
padding: 4
|
|
711
|
+
},
|
|
712
|
+
headerChipRow: {
|
|
713
|
+
flexDirection: "row",
|
|
714
|
+
alignItems: "center",
|
|
715
|
+
gap: 8
|
|
716
|
+
},
|
|
717
|
+
headerChip: {
|
|
718
|
+
flexDirection: "row",
|
|
719
|
+
alignItems: "center",
|
|
720
|
+
gap: 4,
|
|
721
|
+
backgroundColor: _sharedUi.macOSColors.background.hover,
|
|
722
|
+
paddingHorizontal: 10,
|
|
723
|
+
paddingVertical: 5,
|
|
724
|
+
borderRadius: 12,
|
|
725
|
+
borderWidth: 1,
|
|
726
|
+
borderColor: _sharedUi.macOSColors.border.default
|
|
727
|
+
},
|
|
728
|
+
headerChipActive: {
|
|
729
|
+
backgroundColor: _sharedUi.macOSColors.semantic.infoBackground,
|
|
730
|
+
borderColor: _sharedUi.macOSColors.semantic.info + "50",
|
|
731
|
+
shadowColor: _sharedUi.macOSColors.semantic.info,
|
|
732
|
+
shadowOffset: {
|
|
733
|
+
width: 0,
|
|
734
|
+
height: 1
|
|
735
|
+
},
|
|
736
|
+
shadowOpacity: 0.08,
|
|
737
|
+
shadowRadius: 2,
|
|
738
|
+
elevation: 1
|
|
739
|
+
},
|
|
740
|
+
headerChipValue: {
|
|
741
|
+
fontSize: 12,
|
|
742
|
+
fontWeight: "600",
|
|
743
|
+
fontFamily: "monospace"
|
|
744
|
+
},
|
|
745
|
+
headerActionButton: {
|
|
746
|
+
width: 32,
|
|
747
|
+
height: 32,
|
|
748
|
+
borderRadius: 8,
|
|
749
|
+
backgroundColor: _sharedUi.macOSColors.background.hover,
|
|
750
|
+
borderWidth: 1,
|
|
751
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
752
|
+
alignItems: "center",
|
|
753
|
+
justifyContent: "center"
|
|
754
|
+
},
|
|
755
|
+
headerActionButtonDisabled: {
|
|
756
|
+
opacity: 0.55
|
|
757
|
+
},
|
|
758
|
+
// Shared navbar styles (matching React Query modal)
|
|
759
|
+
tabNavigationContainer: {
|
|
760
|
+
flexDirection: "row",
|
|
761
|
+
backgroundColor: _sharedUi.macOSColors.background.card,
|
|
762
|
+
borderRadius: 6,
|
|
763
|
+
padding: 2,
|
|
764
|
+
borderWidth: 1,
|
|
765
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
766
|
+
justifyContent: "space-evenly",
|
|
767
|
+
flex: 1,
|
|
768
|
+
marginLeft: 8,
|
|
769
|
+
marginRight: 8
|
|
770
|
+
},
|
|
771
|
+
tabButton: {
|
|
772
|
+
paddingHorizontal: 8,
|
|
773
|
+
paddingVertical: 5,
|
|
774
|
+
borderRadius: 4,
|
|
775
|
+
alignItems: "center",
|
|
776
|
+
justifyContent: "center",
|
|
777
|
+
flex: 1,
|
|
778
|
+
marginHorizontal: 1
|
|
779
|
+
},
|
|
780
|
+
tabButtonActive: {
|
|
781
|
+
backgroundColor: _sharedUi.macOSColors.semantic.infoBackground,
|
|
782
|
+
borderWidth: 1,
|
|
783
|
+
borderColor: _sharedUi.macOSColors.semantic.info + "40"
|
|
784
|
+
},
|
|
785
|
+
tabButtonInactive: {
|
|
786
|
+
backgroundColor: "transparent"
|
|
787
|
+
},
|
|
788
|
+
tabButtonText: {
|
|
789
|
+
fontSize: 12,
|
|
790
|
+
fontWeight: "600",
|
|
791
|
+
letterSpacing: 0.5,
|
|
792
|
+
fontFamily: "monospace",
|
|
793
|
+
textTransform: "uppercase"
|
|
794
|
+
},
|
|
795
|
+
tabButtonTextActive: {
|
|
796
|
+
color: _sharedUi.macOSColors.semantic.info
|
|
797
|
+
},
|
|
798
|
+
tabButtonTextInactive: {
|
|
799
|
+
color: _sharedUi.macOSColors.text.muted
|
|
800
|
+
},
|
|
801
|
+
startButton: {
|
|
802
|
+
backgroundColor: _sharedUi.macOSColors.semantic.successBackground,
|
|
803
|
+
borderColor: _sharedUi.macOSColors.semantic.success + "40"
|
|
804
|
+
},
|
|
805
|
+
stopButton: {
|
|
806
|
+
backgroundColor: _sharedUi.macOSColors.semantic.errorBackground,
|
|
807
|
+
borderColor: _sharedUi.macOSColors.semantic.error + "40"
|
|
808
|
+
},
|
|
809
|
+
activeFilterButton: {
|
|
810
|
+
backgroundColor: _sharedUi.macOSColors.semantic.infoBackground,
|
|
811
|
+
borderColor: _sharedUi.macOSColors.semantic.info + "40"
|
|
812
|
+
},
|
|
813
|
+
activeIgnoreButton: {
|
|
814
|
+
backgroundColor: _sharedUi.macOSColors.semantic.warningBackground,
|
|
815
|
+
borderColor: _sharedUi.macOSColors.semantic.warning + "33"
|
|
816
|
+
},
|
|
817
|
+
detailHeaderActions: {
|
|
818
|
+
flexDirection: "row",
|
|
819
|
+
gap: 6,
|
|
820
|
+
marginLeft: "auto",
|
|
821
|
+
marginRight: 4
|
|
822
|
+
},
|
|
823
|
+
// Search bar - minimal design with theme colors
|
|
824
|
+
searchContainer: {
|
|
825
|
+
display: "none"
|
|
826
|
+
},
|
|
827
|
+
searchInput: {},
|
|
828
|
+
// Stats bar - minimal design
|
|
829
|
+
statsBar: {
|
|
830
|
+
display: "none"
|
|
831
|
+
},
|
|
832
|
+
statChip: {
|
|
833
|
+
flexDirection: "row",
|
|
834
|
+
alignItems: "center",
|
|
835
|
+
gap: 4,
|
|
836
|
+
backgroundColor: _sharedUi.macOSColors.background.hover,
|
|
837
|
+
paddingHorizontal: 8,
|
|
838
|
+
paddingVertical: 4,
|
|
839
|
+
borderRadius: 12,
|
|
840
|
+
borderWidth: 1,
|
|
841
|
+
borderColor: "transparent"
|
|
842
|
+
},
|
|
843
|
+
statChipActive: {
|
|
844
|
+
backgroundColor: _sharedUi.macOSColors.semantic.info + "26",
|
|
845
|
+
borderColor: _sharedUi.macOSColors.semantic.info + "66"
|
|
846
|
+
},
|
|
847
|
+
statValue: {
|
|
848
|
+
fontSize: 14,
|
|
849
|
+
fontWeight: "600",
|
|
850
|
+
fontFamily: "monospace"
|
|
851
|
+
},
|
|
852
|
+
statLabel: {
|
|
853
|
+
fontSize: 10,
|
|
854
|
+
color: _sharedUi.macOSColors.text.muted,
|
|
855
|
+
fontWeight: "500",
|
|
856
|
+
textTransform: "uppercase"
|
|
857
|
+
},
|
|
858
|
+
disabledBanner: {
|
|
859
|
+
flexDirection: "row",
|
|
860
|
+
alignItems: "center",
|
|
861
|
+
gap: 8,
|
|
862
|
+
padding: 10,
|
|
863
|
+
marginHorizontal: 12,
|
|
864
|
+
marginTop: 8,
|
|
865
|
+
backgroundColor: _sharedUi.macOSColors.semantic.warningBackground,
|
|
866
|
+
borderRadius: 8,
|
|
867
|
+
borderWidth: 1,
|
|
868
|
+
borderColor: _sharedUi.macOSColors.semantic.warning + "20"
|
|
869
|
+
},
|
|
870
|
+
disabledText: {
|
|
871
|
+
color: _sharedUi.macOSColors.semantic.warning,
|
|
872
|
+
fontSize: 11,
|
|
873
|
+
flex: 1
|
|
874
|
+
},
|
|
875
|
+
listContent: {
|
|
876
|
+
paddingTop: 8
|
|
877
|
+
},
|
|
878
|
+
emptyState: {
|
|
879
|
+
alignItems: "center",
|
|
880
|
+
paddingVertical: 40
|
|
881
|
+
},
|
|
882
|
+
emptyTitle: {
|
|
883
|
+
color: _sharedUi.macOSColors.text.primary,
|
|
884
|
+
fontSize: 14,
|
|
885
|
+
fontWeight: "600",
|
|
886
|
+
marginTop: 12,
|
|
887
|
+
marginBottom: 6
|
|
888
|
+
},
|
|
889
|
+
emptyText: {
|
|
890
|
+
color: _sharedUi.macOSColors.text.muted,
|
|
891
|
+
fontSize: 12,
|
|
892
|
+
textAlign: "center"
|
|
893
|
+
},
|
|
894
|
+
// Free tier limit banner
|
|
895
|
+
limitBanner: {
|
|
896
|
+
backgroundColor: "#1A1A1A",
|
|
897
|
+
borderRadius: 10,
|
|
898
|
+
borderWidth: 1,
|
|
899
|
+
borderColor: "#20C997" + "40",
|
|
900
|
+
padding: 12,
|
|
901
|
+
marginHorizontal: 12,
|
|
902
|
+
marginTop: 12,
|
|
903
|
+
marginBottom: 34
|
|
904
|
+
},
|
|
905
|
+
limitBannerContent: {
|
|
906
|
+
flexDirection: "row",
|
|
907
|
+
alignItems: "center",
|
|
908
|
+
justifyContent: "space-between",
|
|
909
|
+
marginBottom: 4
|
|
910
|
+
},
|
|
911
|
+
limitBannerLeft: {
|
|
912
|
+
flexDirection: "row",
|
|
913
|
+
alignItems: "center",
|
|
914
|
+
gap: 8
|
|
915
|
+
},
|
|
916
|
+
limitBannerText: {
|
|
917
|
+
color: "#E0E0E0",
|
|
918
|
+
fontSize: 13,
|
|
919
|
+
fontWeight: "600"
|
|
920
|
+
},
|
|
921
|
+
limitBannerSubtext: {
|
|
922
|
+
color: "#888888",
|
|
923
|
+
fontSize: 11
|
|
924
|
+
}
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
/**
|
|
928
|
+
* High-level modal surface that wraps the network monitoring experience with shared timing
|
|
929
|
+
* context. Automatically injects the `TickProvider` so timestamps refresh while the modal is open.
|
|
930
|
+
*/
|
|
931
|
+
function NetworkModal(props) {
|
|
932
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_useTickEveryMinute.TickProvider, {
|
|
933
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(NetworkModalInner, {
|
|
934
|
+
...props
|
|
935
|
+
})
|
|
936
|
+
});
|
|
937
|
+
}
|