@buoy-gg/network 4.0.2 → 6.0.0
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 +14 -0
- package/lib/commonjs/network/components/NetworkEventItemCompact.js +32 -18
- package/lib/commonjs/network/components/NetworkHeaderLive.js +199 -0
- package/lib/commonjs/network/components/NetworkListScreen.js +203 -0
- package/lib/commonjs/network/components/NetworkModal.js +153 -630
- package/lib/commonjs/network/hooks/useNetworkBadgeCounts.js +83 -0
- package/lib/commonjs/network/hooks/useNetworkEventList.js +93 -0
- package/lib/commonjs/network/hooks/useNetworkHasMatches.js +56 -0
- package/lib/commonjs/network/utils/filterNetworkEvents.js +96 -0
- package/lib/commonjs/network/utils/generateNetworkCopyText.js +139 -0
- package/lib/module/index.js +5 -0
- package/lib/module/network/components/NetworkEventItemCompact.js +32 -18
- package/lib/module/network/components/NetworkHeaderLive.js +193 -0
- package/lib/module/network/components/NetworkListScreen.js +199 -0
- package/lib/module/network/components/NetworkModal.js +157 -634
- package/lib/module/network/hooks/useNetworkBadgeCounts.js +79 -0
- package/lib/module/network/hooks/useNetworkEventList.js +89 -0
- package/lib/module/network/hooks/useNetworkHasMatches.js +52 -0
- package/lib/module/network/utils/filterNetworkEvents.js +92 -0
- package/lib/module/network/utils/generateNetworkCopyText.js +135 -0
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts +0 -4
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkHeaderLive.d.ts +52 -0
- package/lib/typescript/network/components/NetworkHeaderLive.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkListScreen.d.ts +27 -0
- package/lib/typescript/network/components/NetworkListScreen.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkModal.d.ts.map +1 -1
- package/lib/typescript/network/hooks/useNetworkBadgeCounts.d.ts +24 -0
- package/lib/typescript/network/hooks/useNetworkBadgeCounts.d.ts.map +1 -0
- package/lib/typescript/network/hooks/useNetworkEventList.d.ts +34 -0
- package/lib/typescript/network/hooks/useNetworkEventList.d.ts.map +1 -0
- package/lib/typescript/network/hooks/useNetworkHasMatches.d.ts +23 -0
- package/lib/typescript/network/hooks/useNetworkHasMatches.d.ts.map +1 -0
- package/lib/typescript/network/utils/filterNetworkEvents.d.ts +13 -0
- package/lib/typescript/network/utils/filterNetworkEvents.d.ts.map +1 -0
- package/lib/typescript/network/utils/generateNetworkCopyText.d.ts +11 -0
- package/lib/typescript/network/utils/generateNetworkCopyText.d.ts.map +1 -0
- package/package.json +2 -2
|
@@ -7,32 +7,99 @@ exports.NetworkModal = NetworkModal;
|
|
|
7
7
|
var _react = require("react");
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
9
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
|
-
var _NetworkEventItemCompact = require("./NetworkEventItemCompact");
|
|
11
10
|
var _NetworkFilterViewV = require("./NetworkFilterViewV3");
|
|
12
11
|
var _useTickEveryMinute = require("../hooks/useTickEveryMinute");
|
|
13
12
|
var _NetworkEventDetailView = require("./NetworkEventDetailView");
|
|
14
13
|
var _NetworkCopySettingsView = require("./NetworkCopySettingsView");
|
|
15
|
-
var
|
|
16
|
-
var
|
|
14
|
+
var _NetworkHeaderLive = require("./NetworkHeaderLive");
|
|
15
|
+
var _NetworkListScreen = require("./NetworkListScreen");
|
|
16
|
+
var _useNetworkEventList = require("../hooks/useNetworkEventList");
|
|
17
17
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Screens (rule4 stable router: each gates itself with `return null`; the
|
|
20
|
+
// root renders all four as stable siblings instead of a nested ternary).
|
|
21
|
+
// Subscribing screens run their hooks unconditionally and pass
|
|
22
|
+
// `paused || !visible` so hidden screens don't subscribe.
|
|
23
|
+
// ============================================================================
|
|
24
|
+
|
|
25
|
+
function NetworkDetailScreen({
|
|
26
|
+
visible,
|
|
27
|
+
event,
|
|
28
|
+
ignoredPatternValues,
|
|
29
|
+
onTogglePattern
|
|
21
30
|
}) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
if (!visible || !event) return null;
|
|
32
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkEventDetailView.NetworkEventDetailView, {
|
|
33
|
+
event: event,
|
|
34
|
+
ignoredPatterns: ignoredPatternValues,
|
|
35
|
+
onTogglePattern: onTogglePattern
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function NetworkFilterScreen({
|
|
39
|
+
visible,
|
|
40
|
+
paused,
|
|
41
|
+
isPro,
|
|
42
|
+
filter,
|
|
43
|
+
onFilterChange,
|
|
44
|
+
ignoredPatterns,
|
|
45
|
+
onRemovePattern,
|
|
46
|
+
onAddPattern,
|
|
47
|
+
onTogglePatternMode
|
|
48
|
+
}) {
|
|
49
|
+
// Facet counts read the same filtered list the user is looking at.
|
|
50
|
+
const {
|
|
51
|
+
events
|
|
52
|
+
} = (0, _useNetworkEventList.useNetworkEventList)({
|
|
53
|
+
filter,
|
|
54
|
+
ignoredPatterns,
|
|
55
|
+
paused: paused || !visible,
|
|
56
|
+
isPro
|
|
57
|
+
});
|
|
58
|
+
if (!visible) return null;
|
|
59
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkFilterViewV.NetworkFilterViewV3, {
|
|
60
|
+
events: events,
|
|
61
|
+
filter: filter,
|
|
62
|
+
onFilterChange: onFilterChange,
|
|
63
|
+
ignoredPatterns: ignoredPatterns,
|
|
64
|
+
onRemovePattern: onRemovePattern,
|
|
65
|
+
onAddPattern: onAddPattern,
|
|
66
|
+
onTogglePatternMode: onTogglePatternMode
|
|
34
67
|
});
|
|
35
68
|
}
|
|
69
|
+
function NetworkCopyScreen({
|
|
70
|
+
visible,
|
|
71
|
+
paused,
|
|
72
|
+
isPro,
|
|
73
|
+
filter,
|
|
74
|
+
ignoredPatterns,
|
|
75
|
+
settings,
|
|
76
|
+
onSettingsChange
|
|
77
|
+
}) {
|
|
78
|
+
const {
|
|
79
|
+
events
|
|
80
|
+
} = (0, _useNetworkEventList.useNetworkEventList)({
|
|
81
|
+
filter,
|
|
82
|
+
ignoredPatterns,
|
|
83
|
+
paused: paused || !visible,
|
|
84
|
+
isPro
|
|
85
|
+
});
|
|
86
|
+
if (!visible) return null;
|
|
87
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkCopySettingsView.NetworkCopySettingsView, {
|
|
88
|
+
settings: settings,
|
|
89
|
+
onSettingsChange: onSettingsChange,
|
|
90
|
+
events: events
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ============================================================================
|
|
95
|
+
// Root — UI-state orchestration ONLY (rule3). No event-store subscription
|
|
96
|
+
// lives here: live data is consumed by the header leaves
|
|
97
|
+
// (NetworkHeaderLive) and the screens, so network events never re-render
|
|
98
|
+
// the modal shell/header. Profiling evidence: tool-bench 2026-07-06 —
|
|
99
|
+
// with the subscription here, 15 events re-rendered JsModal + every
|
|
100
|
+
// header button 15× and all visible rows 105×.
|
|
101
|
+
// ============================================================================
|
|
102
|
+
|
|
36
103
|
function NetworkModalInner({
|
|
37
104
|
visible,
|
|
38
105
|
onClose,
|
|
@@ -43,44 +110,19 @@ function NetworkModalInner({
|
|
|
43
110
|
const {
|
|
44
111
|
isPro
|
|
45
112
|
} = (0, _sharedUi.useFeatureGate)();
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
setFilter,
|
|
52
|
-
clearEvents,
|
|
53
|
-
isCapturing,
|
|
54
|
-
pauseCapturing,
|
|
55
|
-
resumeCapturing,
|
|
56
|
-
hasLockedEvents,
|
|
57
|
-
lockedEventCount,
|
|
58
|
-
isEventLocked,
|
|
59
|
-
requestLimit
|
|
60
|
-
} = (0, _useNetworkEvents.useNetworkEvents)({
|
|
61
|
-
isPro
|
|
62
|
-
});
|
|
63
|
-
const isEnabled = isCapturing;
|
|
64
|
-
const toggleInterception = (0, _react.useCallback)(() => {
|
|
65
|
-
if (isCapturing) {
|
|
66
|
-
pauseCapturing();
|
|
67
|
-
} else {
|
|
68
|
-
resumeCapturing();
|
|
69
|
-
}
|
|
70
|
-
}, [isCapturing, pauseCapturing, resumeCapturing]);
|
|
71
|
-
const handleModeChange = (0, _react.useCallback)(_mode => {
|
|
72
|
-
// Mode changes handled by JsModal
|
|
73
|
-
}, []);
|
|
113
|
+
|
|
114
|
+
// Capture pause (the power toggle's freeze-stream semantic) — gates
|
|
115
|
+
// every subscriber in this modal's tree via props.
|
|
116
|
+
const [paused, setPaused] = (0, _react.useState)(false);
|
|
117
|
+
const [filter, setFilter] = (0, _react.useState)({});
|
|
74
118
|
const [selectedEvent, setSelectedEvent] = (0, _react.useState)(null);
|
|
75
119
|
const [showFilterView, setShowFilterView] = (0, _react.useState)(false);
|
|
76
120
|
const [activeTab, setActiveTab] = (0, _react.useState)("filters");
|
|
77
121
|
const [searchText, setSearchText] = (0, _react.useState)("");
|
|
78
122
|
const [isSearchActive, setIsSearchActive] = (0, _react.useState)(false);
|
|
79
123
|
const searchInputRef = (0, _react.useRef)(null);
|
|
80
|
-
// Ignored domains/URL patterns
|
|
81
|
-
// (@buoy-gg/shared-ui) so the Network tool and the Events tool stay in sync
|
|
82
|
-
// share the exact same filter logic. The four handlers below are thin wrappers
|
|
83
|
-
// exposed by the hook; `values` is the derived Set used for presence checks.
|
|
124
|
+
// Ignored domains/URL patterns live in a shared, persisted singleton store
|
|
125
|
+
// (@buoy-gg/shared-ui) so the Network tool and the Events tool stay in sync.
|
|
84
126
|
const {
|
|
85
127
|
patterns: ignoredPatterns,
|
|
86
128
|
values: ignoredPatternValues,
|
|
@@ -90,7 +132,6 @@ function NetworkModalInner({
|
|
|
90
132
|
toggleMode: toggleIgnoredPatternMode
|
|
91
133
|
} = (0, _sharedUi.useIgnoredPatterns)();
|
|
92
134
|
const [copySettings, setCopySettings] = (0, _react.useState)(_NetworkCopySettingsView.DEFAULT_COPY_SETTINGS);
|
|
93
|
-
const flatListRef = (0, _react.useRef)(null);
|
|
94
135
|
const hasLoadedCopySettings = (0, _react.useRef)(false);
|
|
95
136
|
const [showUpgradeModal, setShowUpgradeModal] = (0, _react.useState)(false);
|
|
96
137
|
|
|
@@ -135,9 +176,6 @@ function NetworkModalInner({
|
|
|
135
176
|
}, [copySettings]);
|
|
136
177
|
|
|
137
178
|
// Simple handlers - no useCallback needed per rule2
|
|
138
|
-
const handleEventPress = event => {
|
|
139
|
-
setSelectedEvent(event);
|
|
140
|
-
};
|
|
141
179
|
const handleBack = () => {
|
|
142
180
|
setSelectedEvent(null);
|
|
143
181
|
};
|
|
@@ -148,6 +186,15 @@ function NetworkModalInner({
|
|
|
148
186
|
searchText: text
|
|
149
187
|
}));
|
|
150
188
|
};
|
|
189
|
+
const toggleStatusFilter = status => {
|
|
190
|
+
setFilter(prev => ({
|
|
191
|
+
...prev,
|
|
192
|
+
status: prev.status === status ? undefined : status
|
|
193
|
+
}));
|
|
194
|
+
};
|
|
195
|
+
const handleModeChange = _mode => {
|
|
196
|
+
// Mode changes handled by JsModal
|
|
197
|
+
};
|
|
151
198
|
(0, _react.useEffect)(() => {
|
|
152
199
|
if (isSearchActive) {
|
|
153
200
|
requestAnimationFrame(() => {
|
|
@@ -156,226 +203,10 @@ function NetworkModalInner({
|
|
|
156
203
|
}
|
|
157
204
|
}, [isSearchActive]);
|
|
158
205
|
|
|
159
|
-
// Filter events based on ignored patterns (mode-aware)
|
|
160
|
-
const filteredEvents = (0, _react.useMemo)(() => {
|
|
161
|
-
if (ignoredPatterns.length === 0) return events;
|
|
162
|
-
return events.filter(event => {
|
|
163
|
-
const isFiltered = ignoredPatterns.some(pattern => (0, _sharedUi.urlMatchesIgnoredPattern)(event.url, pattern));
|
|
164
|
-
return !isFiltered;
|
|
165
|
-
});
|
|
166
|
-
}, [events, ignoredPatterns]);
|
|
167
|
-
|
|
168
|
-
// Helper to check if payload should be included based on size
|
|
169
|
-
const shouldIncludePayload = (0, _react.useCallback)(data => {
|
|
170
|
-
if (copySettings.bodySizeThreshold === -1) return true;
|
|
171
|
-
if (!data) return true;
|
|
172
|
-
try {
|
|
173
|
-
const size = JSON.stringify(data).length;
|
|
174
|
-
return size < copySettings.bodySizeThreshold * 1024;
|
|
175
|
-
} catch {
|
|
176
|
-
return false;
|
|
177
|
-
}
|
|
178
|
-
}, [copySettings.bodySizeThreshold]);
|
|
179
|
-
|
|
180
|
-
// Generate copy text based on settings
|
|
181
|
-
const generateCopyText = (0, _react.useCallback)(() => {
|
|
182
|
-
let eventsToUse = filteredEvents;
|
|
183
|
-
|
|
184
|
-
// Apply filter mode
|
|
185
|
-
if (copySettings.filterMode === "failed") {
|
|
186
|
-
eventsToUse = eventsToUse.filter(e => e.error || e.status && e.status >= 400);
|
|
187
|
-
} else if (copySettings.filterMode === "success") {
|
|
188
|
-
eventsToUse = eventsToUse.filter(e => e.status && e.status >= 200 && e.status < 300);
|
|
189
|
-
}
|
|
190
|
-
if (eventsToUse.length === 0) {
|
|
191
|
-
return "No requests to copy";
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Plain text format (URLs only)
|
|
195
|
-
if (copySettings.format === "plaintext") {
|
|
196
|
-
return eventsToUse.map(event => `${event.method} ${event.url}`).join("\n");
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// JSON format
|
|
200
|
-
if (copySettings.format === "json") {
|
|
201
|
-
const requests = eventsToUse.map(event => {
|
|
202
|
-
const obj = {};
|
|
203
|
-
if (copySettings.includeMethod) {
|
|
204
|
-
obj.method = event.method;
|
|
205
|
-
obj.url = event.url;
|
|
206
|
-
}
|
|
207
|
-
if (copySettings.includeStatus) {
|
|
208
|
-
obj.status = event.status;
|
|
209
|
-
obj.statusText = event.statusText;
|
|
210
|
-
}
|
|
211
|
-
if (copySettings.includeDuration) obj.duration = event.duration;
|
|
212
|
-
if (copySettings.includeTimestamp) obj.timestamp = event.timestamp;
|
|
213
|
-
if (copySettings.includeClient) obj.requestClient = event.requestClient;
|
|
214
|
-
if (copySettings.includeSizes) {
|
|
215
|
-
obj.requestSize = event.requestSize;
|
|
216
|
-
obj.responseSize = event.responseSize;
|
|
217
|
-
}
|
|
218
|
-
if (copySettings.includeErrors && event.error) obj.error = event.error;
|
|
219
|
-
if (copySettings.includeRequestHeaders) {
|
|
220
|
-
obj.requestHeaders = event.requestHeaders;
|
|
221
|
-
}
|
|
222
|
-
if (copySettings.includeResponseHeaders) {
|
|
223
|
-
obj.responseHeaders = event.responseHeaders;
|
|
224
|
-
}
|
|
225
|
-
if (copySettings.includeRequestBody && shouldIncludePayload(event.requestData)) {
|
|
226
|
-
obj.requestData = event.requestData;
|
|
227
|
-
}
|
|
228
|
-
if (copySettings.includeResponseBody && shouldIncludePayload(event.responseData)) {
|
|
229
|
-
obj.responseData = event.responseData;
|
|
230
|
-
}
|
|
231
|
-
return obj;
|
|
232
|
-
});
|
|
233
|
-
return JSON.stringify(requests, null, 2);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Markdown format
|
|
237
|
-
const requests = eventsToUse.map((event, index) => {
|
|
238
|
-
let md = `# Request ${index + 1}\n\n`;
|
|
239
|
-
if (copySettings.includeMethod) {
|
|
240
|
-
md += `**Method:** ${event.method}\n`;
|
|
241
|
-
md += `**URL:** ${event.url}\n`;
|
|
242
|
-
}
|
|
243
|
-
if (copySettings.includeStatus) {
|
|
244
|
-
const status = event.status || "Pending";
|
|
245
|
-
md += `**Status:** ${status}${event.statusText ? ` (${event.statusText})` : ""}\n`;
|
|
246
|
-
}
|
|
247
|
-
if (copySettings.includeClient && event.requestClient) {
|
|
248
|
-
md += `**Client:** ${event.requestClient}\n`;
|
|
249
|
-
}
|
|
250
|
-
if (copySettings.includeDuration && event.duration) {
|
|
251
|
-
md += `**Duration:** ${event.duration}ms\n`;
|
|
252
|
-
}
|
|
253
|
-
if (copySettings.includeTimestamp) {
|
|
254
|
-
md += `**Timestamp:** ${new Date(event.timestamp).toISOString()}\n`;
|
|
255
|
-
}
|
|
256
|
-
if (copySettings.includeSizes) {
|
|
257
|
-
const reqSize = event.requestSize ? (0, _formatting.formatBytes)(event.requestSize) : "N/A";
|
|
258
|
-
const resSize = event.responseSize ? (0, _formatting.formatBytes)(event.responseSize) : "N/A";
|
|
259
|
-
md += `**Request Size:** ${reqSize}\n`;
|
|
260
|
-
md += `**Response Size:** ${resSize}\n`;
|
|
261
|
-
}
|
|
262
|
-
if (copySettings.includeErrors && event.error) {
|
|
263
|
-
md += `**Error:** ${event.error}\n`;
|
|
264
|
-
}
|
|
265
|
-
if (copySettings.includeRequestHeaders && Object.keys(event.requestHeaders).length > 0) {
|
|
266
|
-
md += `\n## Request Headers\n\`\`\`json\n${JSON.stringify(event.requestHeaders, null, 2)}\n\`\`\`\n`;
|
|
267
|
-
}
|
|
268
|
-
if (copySettings.includeRequestBody) {
|
|
269
|
-
md += `\n## Request Data\n`;
|
|
270
|
-
if (shouldIncludePayload(event.requestData)) {
|
|
271
|
-
md += `\`\`\`json\n${JSON.stringify(event.requestData, null, 2)}\n\`\`\`\n`;
|
|
272
|
-
} else {
|
|
273
|
-
const size = event.requestSize ? (0, _formatting.formatBytes)(event.requestSize) : "Unknown size";
|
|
274
|
-
md += `_Payload omitted (${size}). Exceeds ${copySettings.bodySizeThreshold}KB threshold._\n`;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
if (copySettings.includeResponseHeaders && Object.keys(event.responseHeaders).length > 0) {
|
|
278
|
-
md += `\n## Response Headers\n\`\`\`json\n${JSON.stringify(event.responseHeaders, null, 2)}\n\`\`\`\n`;
|
|
279
|
-
}
|
|
280
|
-
if (copySettings.includeResponseBody) {
|
|
281
|
-
md += `\n## Response Data\n`;
|
|
282
|
-
if (shouldIncludePayload(event.responseData)) {
|
|
283
|
-
md += `\`\`\`json\n${JSON.stringify(event.responseData, null, 2)}\n\`\`\`\n`;
|
|
284
|
-
} else {
|
|
285
|
-
const size = event.responseSize ? (0, _formatting.formatBytes)(event.responseSize) : "Unknown size";
|
|
286
|
-
md += `_Payload omitted (${size}). Exceeds ${copySettings.bodySizeThreshold}KB threshold._\n`;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
md += `\n---\n`;
|
|
290
|
-
return md;
|
|
291
|
-
}).join("\n");
|
|
292
|
-
const header = `# Network Requests (${eventsToUse.length} total)\n\n`;
|
|
293
|
-
return header + requests;
|
|
294
|
-
}, [filteredEvents, copySettings, shouldIncludePayload]);
|
|
295
|
-
|
|
296
|
-
// Memoized copy text value for CopyButton
|
|
297
|
-
const copyTextValue = (0, _react.useMemo)(() => {
|
|
298
|
-
if (filteredEvents.length === 0) return "";
|
|
299
|
-
return generateCopyText();
|
|
300
|
-
}, [filteredEvents.length, generateCopyText]);
|
|
301
|
-
|
|
302
|
-
// Compute badge stats from all events (before status filtering) with ignored patterns applied.
|
|
303
|
-
// This ensures counts stay stable when toggling between status filters.
|
|
304
|
-
const badgeStats = (0, _react.useMemo)(() => {
|
|
305
|
-
let successful = 0;
|
|
306
|
-
let failed = 0;
|
|
307
|
-
let pending = 0;
|
|
308
|
-
const eventsForStats = ignoredPatterns.length === 0 ? allEvents : allEvents.filter(event => !ignoredPatterns.some(pattern => (0, _sharedUi.urlMatchesIgnoredPattern)(event.url, pattern)));
|
|
309
|
-
for (const event of eventsForStats) {
|
|
310
|
-
if (event.status && event.status >= 200 && event.status < 300) {
|
|
311
|
-
successful++;
|
|
312
|
-
} else if (event.error || event.status && event.status >= 400) {
|
|
313
|
-
failed++;
|
|
314
|
-
} else if (!event.status && !event.error) {
|
|
315
|
-
pending++;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
return {
|
|
319
|
-
successful,
|
|
320
|
-
failed,
|
|
321
|
-
pending
|
|
322
|
-
};
|
|
323
|
-
}, [allEvents, ignoredPatterns]);
|
|
324
|
-
|
|
325
|
-
// FlatList optimization - only keep what's needed for FlatList performance
|
|
326
|
-
const keyExtractor = item => item.id;
|
|
327
|
-
|
|
328
|
-
// Filter to only show unlocked events in the list
|
|
329
|
-
const unlockedEvents = (0, _react.useMemo)(() => {
|
|
330
|
-
return filteredEvents.filter(event => !isEventLocked(event.id));
|
|
331
|
-
}, [filteredEvents, isEventLocked]);
|
|
332
|
-
|
|
333
|
-
// Keep renderItem memoized for FlatList performance (justified by FlatList docs)
|
|
334
|
-
const renderItem = (0, _react.useMemo)(() => {
|
|
335
|
-
return ({
|
|
336
|
-
item
|
|
337
|
-
}) => {
|
|
338
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkEventItemCompact.NetworkEventItemCompact, {
|
|
339
|
-
event: item,
|
|
340
|
-
onPress: handleEventPress
|
|
341
|
-
});
|
|
342
|
-
};
|
|
343
|
-
}, []); // handleEventPress defined inline
|
|
344
|
-
|
|
345
|
-
// Footer component showing upgrade banner when events are locked
|
|
346
|
-
const renderListFooter = (0, _react.useCallback)(() => {
|
|
347
|
-
if (!hasLockedEvents) return null;
|
|
348
|
-
const isSearching = searchText.length > 0;
|
|
349
|
-
const bannerText = isSearching ? `${lockedEventCount} matching ${lockedEventCount === 1 ? 'request' : 'requests'} in locked history` : `${lockedEventCount} requests locked`;
|
|
350
|
-
const subtextMessage = isSearching ? "Upgrade to Pro to search your full request history" : "Upgrade to Pro to unlock full request history";
|
|
351
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
352
|
-
style: styles.limitBanner,
|
|
353
|
-
onPress: () => setShowUpgradeModal(true),
|
|
354
|
-
activeOpacity: 0.8,
|
|
355
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
356
|
-
style: styles.limitBannerContent,
|
|
357
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
358
|
-
style: styles.limitBannerLeft,
|
|
359
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Zap, {
|
|
360
|
-
size: 16,
|
|
361
|
-
color: "#20C997"
|
|
362
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
363
|
-
style: styles.limitBannerText,
|
|
364
|
-
children: bannerText
|
|
365
|
-
})]
|
|
366
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ProBadge, {})]
|
|
367
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
368
|
-
style: styles.limitBannerSubtext,
|
|
369
|
-
children: subtextMessage
|
|
370
|
-
})]
|
|
371
|
-
});
|
|
372
|
-
}, [hasLockedEvents, lockedEventCount, searchText]);
|
|
373
|
-
|
|
374
206
|
// Compact header with actions (like Sentry/Storage modals)
|
|
375
207
|
const renderHeaderContent = () => {
|
|
376
208
|
// Filter view header with tabs
|
|
377
209
|
if (showFilterView) {
|
|
378
|
-
// Copy tab is always visible and clickable - gating handled inside the view
|
|
379
210
|
const tabs = [{
|
|
380
211
|
key: "filters",
|
|
381
212
|
label: "Filters"
|
|
@@ -410,7 +241,9 @@ function NetworkModalInner({
|
|
|
410
241
|
});
|
|
411
242
|
}
|
|
412
243
|
|
|
413
|
-
// Main list view header with search and filters
|
|
244
|
+
// Main list view header with search and filters. The live pieces
|
|
245
|
+
// (count chips, copy, trash) are self-subscribing leaves — this
|
|
246
|
+
// header function itself only re-runs on user interaction.
|
|
414
247
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
|
|
415
248
|
children: [onBack && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
|
|
416
249
|
onBack: onBack
|
|
@@ -447,54 +280,11 @@ function NetworkModalInner({
|
|
|
447
280
|
color: _sharedUi.macOSColors.text.secondary
|
|
448
281
|
})
|
|
449
282
|
}) : null]
|
|
450
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
...filter,
|
|
456
|
-
status: filter.status === "success" ? undefined : "success"
|
|
457
|
-
}),
|
|
458
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CheckCircle, {
|
|
459
|
-
size: 12,
|
|
460
|
-
color: _sharedUi.macOSColors.semantic.success
|
|
461
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
462
|
-
style: [styles.headerChipValue, {
|
|
463
|
-
color: _sharedUi.macOSColors.semantic.success
|
|
464
|
-
}],
|
|
465
|
-
children: badgeStats.successful
|
|
466
|
-
})]
|
|
467
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
468
|
-
style: [styles.headerChip, filter.status === "error" && styles.headerChipActive],
|
|
469
|
-
onPress: () => setFilter({
|
|
470
|
-
...filter,
|
|
471
|
-
status: filter.status === "error" ? undefined : "error"
|
|
472
|
-
}),
|
|
473
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.XCircle, {
|
|
474
|
-
size: 12,
|
|
475
|
-
color: _sharedUi.macOSColors.semantic.error
|
|
476
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
477
|
-
style: [styles.headerChipValue, {
|
|
478
|
-
color: _sharedUi.macOSColors.semantic.error
|
|
479
|
-
}],
|
|
480
|
-
children: badgeStats.failed
|
|
481
|
-
})]
|
|
482
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
483
|
-
style: [styles.headerChip, filter.status === "pending" && styles.headerChipActive],
|
|
484
|
-
onPress: () => setFilter({
|
|
485
|
-
...filter,
|
|
486
|
-
status: filter.status === "pending" ? undefined : "pending"
|
|
487
|
-
}),
|
|
488
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Clock, {
|
|
489
|
-
size: 12,
|
|
490
|
-
color: _sharedUi.macOSColors.semantic.warning
|
|
491
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
492
|
-
style: [styles.headerChipValue, {
|
|
493
|
-
color: _sharedUi.macOSColors.semantic.warning
|
|
494
|
-
}],
|
|
495
|
-
children: badgeStats.pending
|
|
496
|
-
})]
|
|
497
|
-
})]
|
|
283
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkHeaderBadges, {
|
|
284
|
+
activeStatus: filter.status,
|
|
285
|
+
onToggleStatus: toggleStatusFilter,
|
|
286
|
+
ignoredPatterns: ignoredPatterns,
|
|
287
|
+
paused: paused
|
|
498
288
|
})
|
|
499
289
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions, {
|
|
500
290
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
@@ -515,44 +305,31 @@ function NetworkModalInner({
|
|
|
515
305
|
size: 14,
|
|
516
306
|
color: filter.status || filter.method || filter.contentType ? _sharedUi.macOSColors.semantic.info : _sharedUi.macOSColors.text.muted
|
|
517
307
|
})
|
|
518
|
-
}),
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
error: _sharedUi.macOSColors.semantic.error
|
|
526
|
-
},
|
|
527
|
-
disabled: filteredEvents.length === 0
|
|
528
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
529
|
-
"sentry-label": "ignore copy pro",
|
|
530
|
-
onPress: () => setShowUpgradeModal(true),
|
|
531
|
-
style: [styles.headerActionButton, filteredEvents.length === 0 && styles.headerActionButtonDisabled],
|
|
532
|
-
disabled: filteredEvents.length === 0,
|
|
533
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Copy, {
|
|
534
|
-
size: 14,
|
|
535
|
-
color: filteredEvents.length > 0 ? _sharedUi.macOSColors.text.secondary : _sharedUi.macOSColors.text.disabled
|
|
536
|
-
})
|
|
308
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkHeaderCopyButton, {
|
|
309
|
+
isPro: isPro,
|
|
310
|
+
filter: filter,
|
|
311
|
+
ignoredPatterns: ignoredPatterns,
|
|
312
|
+
copySettings: copySettings,
|
|
313
|
+
paused: paused,
|
|
314
|
+
onUpgradePress: () => setShowUpgradeModal(true)
|
|
537
315
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PowerToggleButton, {
|
|
538
|
-
isEnabled:
|
|
539
|
-
onToggle:
|
|
316
|
+
isEnabled: !paused,
|
|
317
|
+
onToggle: () => setPaused(prev => !prev),
|
|
540
318
|
accessibilityLabel: "Toggle network interception"
|
|
541
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
542
|
-
|
|
543
|
-
onPress: clearEvents,
|
|
544
|
-
style: [styles.headerActionButton, events.length === 0 && styles.headerActionButtonDisabled],
|
|
545
|
-
disabled: events.length === 0,
|
|
546
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
|
|
547
|
-
size: 14,
|
|
548
|
-
color: events.length > 0 ? _sharedUi.macOSColors.text.muted : _sharedUi.macOSColors.text.disabled
|
|
549
|
-
})
|
|
319
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkHeaderLive.NetworkClearButton, {
|
|
320
|
+
paused: paused
|
|
550
321
|
})]
|
|
551
322
|
})]
|
|
552
323
|
});
|
|
553
324
|
};
|
|
554
325
|
const persistenceKey = enableSharedModalDimensions ? _sharedUi.devToolsStorageKeys.modal.root() : _sharedUi.devToolsStorageKeys.network.modal();
|
|
555
326
|
if (!visible) return null;
|
|
327
|
+
|
|
328
|
+
// The LIST screen owns its scrolling (FlatList virtualization requires
|
|
329
|
+
// it — inside JsModal's ScrollView wrapper every row mounts, which at
|
|
330
|
+
// the 500-event cap measured 17 JS FPS / 133% CPU / 1.4GB; see
|
|
331
|
+
// NetworkListScreen). Detail/filter/copy still use the wrapper.
|
|
332
|
+
const listOwnsScroll = selectedEvent == null && !showFilterView;
|
|
556
333
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.JsModal, {
|
|
557
334
|
visible: visible,
|
|
558
335
|
onClose: onClose,
|
|
@@ -566,58 +343,43 @@ function NetworkModalInner({
|
|
|
566
343
|
enablePersistence: true,
|
|
567
344
|
initialMode: "bottomSheet",
|
|
568
345
|
enableGlitchEffects: true,
|
|
346
|
+
disableScrollWrapper: listOwnsScroll,
|
|
569
347
|
styles: {},
|
|
570
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.
|
|
348
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
571
349
|
style: styles.container,
|
|
572
|
-
children:
|
|
573
|
-
|
|
574
|
-
/* Show detail view if event is selected */
|
|
575
|
-
(0, _jsxRuntime.jsx)(_NetworkEventDetailView.NetworkEventDetailView, {
|
|
350
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(NetworkDetailScreen, {
|
|
351
|
+
visible: selectedEvent != null,
|
|
576
352
|
event: selectedEvent,
|
|
577
|
-
|
|
353
|
+
ignoredPatternValues: ignoredPatternValues,
|
|
578
354
|
onTogglePattern: toggleIgnoredPattern
|
|
579
|
-
})
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
events: filteredEvents
|
|
584
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkFilterViewV.NetworkFilterViewV3, {
|
|
585
|
-
events: filteredEvents,
|
|
355
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(NetworkFilterScreen, {
|
|
356
|
+
visible: showFilterView && activeTab === "filters" && !selectedEvent,
|
|
357
|
+
paused: paused,
|
|
358
|
+
isPro: isPro,
|
|
586
359
|
filter: filter,
|
|
587
360
|
onFilterChange: setFilter,
|
|
588
361
|
ignoredPatterns: ignoredPatterns,
|
|
589
362
|
onRemovePattern: removeIgnoredPattern,
|
|
590
363
|
onAddPattern: addIgnoredPattern,
|
|
591
364
|
onTogglePatternMode: toggleIgnoredPatternMode
|
|
592
|
-
})
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
onEndReachedThreshold: 0.8,
|
|
611
|
-
initialNumToRender: 10,
|
|
612
|
-
maxToRenderPerBatch: 10,
|
|
613
|
-
windowSize: 10,
|
|
614
|
-
scrollEnabled: false,
|
|
615
|
-
"sentry-label": "ignore network events list",
|
|
616
|
-
ListFooterComponent: renderListFooter
|
|
617
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyState, {
|
|
618
|
-
isEnabled: isEnabled
|
|
619
|
-
})]
|
|
620
|
-
})
|
|
365
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(NetworkCopyScreen, {
|
|
366
|
+
visible: showFilterView && activeTab === "copy" && !selectedEvent,
|
|
367
|
+
paused: paused,
|
|
368
|
+
isPro: isPro,
|
|
369
|
+
filter: filter,
|
|
370
|
+
ignoredPatterns: ignoredPatterns,
|
|
371
|
+
settings: copySettings,
|
|
372
|
+
onSettingsChange: setCopySettings
|
|
373
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkListScreen.NetworkListScreen, {
|
|
374
|
+
visible: selectedEvent == null && !showFilterView,
|
|
375
|
+
paused: paused,
|
|
376
|
+
filter: filter,
|
|
377
|
+
ignoredPatterns: ignoredPatterns,
|
|
378
|
+
isPro: isPro,
|
|
379
|
+
searchText: searchText,
|
|
380
|
+
onEventPress: setSelectedEvent,
|
|
381
|
+
onUpgradePress: () => setShowUpgradeModal(true)
|
|
382
|
+
})]
|
|
621
383
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.UpgradeModal, {
|
|
622
384
|
visible: showUpgradeModal,
|
|
623
385
|
onClose: () => setShowUpgradeModal(false),
|
|
@@ -632,46 +394,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
632
394
|
flex: 1,
|
|
633
395
|
backgroundColor: _sharedUi.macOSColors.background.base
|
|
634
396
|
},
|
|
635
|
-
// Compact header styles matching Sentry/Storage modals
|
|
636
|
-
headerContainer: {
|
|
637
|
-
flexDirection: "row",
|
|
638
|
-
alignItems: "center",
|
|
639
|
-
flex: 1,
|
|
640
|
-
gap: 8,
|
|
641
|
-
minHeight: 32,
|
|
642
|
-
paddingLeft: 4
|
|
643
|
-
},
|
|
644
|
-
headerTitle: {
|
|
645
|
-
color: _sharedUi.macOSColors.text.primary,
|
|
646
|
-
fontSize: 14,
|
|
647
|
-
fontWeight: "500",
|
|
648
|
-
flex: 1,
|
|
649
|
-
marginLeft: 8
|
|
650
|
-
},
|
|
651
|
-
headerStats: {
|
|
652
|
-
display: "none"
|
|
653
|
-
},
|
|
654
|
-
headerStatsText: {
|
|
655
|
-
fontSize: 12,
|
|
656
|
-
color: _sharedUi.macOSColors.text.muted,
|
|
657
|
-
fontWeight: "500"
|
|
658
|
-
},
|
|
659
|
-
headerFilteredText: {
|
|
660
|
-
fontSize: 11,
|
|
661
|
-
color: _sharedUi.macOSColors.semantic.warning,
|
|
662
|
-
fontWeight: "500",
|
|
663
|
-
marginLeft: 4
|
|
664
|
-
},
|
|
665
|
-
headerActions: {
|
|
666
|
-
flexDirection: "row",
|
|
667
|
-
gap: 6,
|
|
668
|
-
marginLeft: "auto",
|
|
669
|
-
marginRight: 4
|
|
670
|
-
},
|
|
671
|
-
headerCenterArea: {
|
|
672
|
-
flex: 1,
|
|
673
|
-
marginHorizontal: 8
|
|
674
|
-
},
|
|
675
397
|
headerSearchContainer: {
|
|
676
398
|
flexDirection: "row",
|
|
677
399
|
alignItems: "center",
|
|
@@ -693,39 +415,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
693
415
|
marginLeft: 6,
|
|
694
416
|
padding: 4
|
|
695
417
|
},
|
|
696
|
-
headerChipRow: {
|
|
697
|
-
flexDirection: "row",
|
|
698
|
-
alignItems: "center",
|
|
699
|
-
gap: 8
|
|
700
|
-
},
|
|
701
|
-
headerChip: {
|
|
702
|
-
flexDirection: "row",
|
|
703
|
-
alignItems: "center",
|
|
704
|
-
gap: 4,
|
|
705
|
-
backgroundColor: _sharedUi.macOSColors.background.hover,
|
|
706
|
-
paddingHorizontal: 10,
|
|
707
|
-
paddingVertical: 5,
|
|
708
|
-
borderRadius: 12,
|
|
709
|
-
borderWidth: 1,
|
|
710
|
-
borderColor: _sharedUi.macOSColors.border.default
|
|
711
|
-
},
|
|
712
|
-
headerChipActive: {
|
|
713
|
-
backgroundColor: _sharedUi.macOSColors.semantic.infoBackground,
|
|
714
|
-
borderColor: _sharedUi.macOSColors.semantic.info + "50",
|
|
715
|
-
shadowColor: _sharedUi.macOSColors.semantic.info,
|
|
716
|
-
shadowOffset: {
|
|
717
|
-
width: 0,
|
|
718
|
-
height: 1
|
|
719
|
-
},
|
|
720
|
-
shadowOpacity: 0.08,
|
|
721
|
-
shadowRadius: 2,
|
|
722
|
-
elevation: 1
|
|
723
|
-
},
|
|
724
|
-
headerChipValue: {
|
|
725
|
-
fontSize: 12,
|
|
726
|
-
fontWeight: "600",
|
|
727
|
-
fontFamily: "monospace"
|
|
728
|
-
},
|
|
729
418
|
headerActionButton: {
|
|
730
419
|
width: 32,
|
|
731
420
|
height: 32,
|
|
@@ -736,175 +425,9 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
736
425
|
alignItems: "center",
|
|
737
426
|
justifyContent: "center"
|
|
738
427
|
},
|
|
739
|
-
headerActionButtonDisabled: {
|
|
740
|
-
opacity: 0.55
|
|
741
|
-
},
|
|
742
|
-
// Shared navbar styles (matching React Query modal)
|
|
743
|
-
tabNavigationContainer: {
|
|
744
|
-
flexDirection: "row",
|
|
745
|
-
backgroundColor: _sharedUi.macOSColors.background.card,
|
|
746
|
-
borderRadius: 6,
|
|
747
|
-
padding: 2,
|
|
748
|
-
borderWidth: 1,
|
|
749
|
-
borderColor: _sharedUi.macOSColors.border.default,
|
|
750
|
-
justifyContent: "space-evenly",
|
|
751
|
-
flex: 1,
|
|
752
|
-
marginLeft: 8,
|
|
753
|
-
marginRight: 8
|
|
754
|
-
},
|
|
755
|
-
tabButton: {
|
|
756
|
-
paddingHorizontal: 8,
|
|
757
|
-
paddingVertical: 5,
|
|
758
|
-
borderRadius: 4,
|
|
759
|
-
alignItems: "center",
|
|
760
|
-
justifyContent: "center",
|
|
761
|
-
flex: 1,
|
|
762
|
-
marginHorizontal: 1
|
|
763
|
-
},
|
|
764
|
-
tabButtonActive: {
|
|
765
|
-
backgroundColor: _sharedUi.macOSColors.semantic.infoBackground,
|
|
766
|
-
borderWidth: 1,
|
|
767
|
-
borderColor: _sharedUi.macOSColors.semantic.info + "40"
|
|
768
|
-
},
|
|
769
|
-
tabButtonInactive: {
|
|
770
|
-
backgroundColor: "transparent"
|
|
771
|
-
},
|
|
772
|
-
tabButtonText: {
|
|
773
|
-
fontSize: 12,
|
|
774
|
-
fontWeight: "600",
|
|
775
|
-
letterSpacing: 0.5,
|
|
776
|
-
fontFamily: "monospace",
|
|
777
|
-
textTransform: "uppercase"
|
|
778
|
-
},
|
|
779
|
-
tabButtonTextActive: {
|
|
780
|
-
color: _sharedUi.macOSColors.semantic.info
|
|
781
|
-
},
|
|
782
|
-
tabButtonTextInactive: {
|
|
783
|
-
color: _sharedUi.macOSColors.text.muted
|
|
784
|
-
},
|
|
785
|
-
startButton: {
|
|
786
|
-
backgroundColor: _sharedUi.macOSColors.semantic.successBackground,
|
|
787
|
-
borderColor: _sharedUi.macOSColors.semantic.success + "40"
|
|
788
|
-
},
|
|
789
|
-
stopButton: {
|
|
790
|
-
backgroundColor: _sharedUi.macOSColors.semantic.errorBackground,
|
|
791
|
-
borderColor: _sharedUi.macOSColors.semantic.error + "40"
|
|
792
|
-
},
|
|
793
428
|
activeFilterButton: {
|
|
794
429
|
backgroundColor: _sharedUi.macOSColors.semantic.infoBackground,
|
|
795
430
|
borderColor: _sharedUi.macOSColors.semantic.info + "40"
|
|
796
|
-
},
|
|
797
|
-
activeIgnoreButton: {
|
|
798
|
-
backgroundColor: _sharedUi.macOSColors.semantic.warningBackground,
|
|
799
|
-
borderColor: _sharedUi.macOSColors.semantic.warning + "33"
|
|
800
|
-
},
|
|
801
|
-
detailHeaderActions: {
|
|
802
|
-
flexDirection: "row",
|
|
803
|
-
gap: 6,
|
|
804
|
-
marginLeft: "auto",
|
|
805
|
-
marginRight: 4
|
|
806
|
-
},
|
|
807
|
-
// Search bar - minimal design with theme colors
|
|
808
|
-
searchContainer: {
|
|
809
|
-
display: "none"
|
|
810
|
-
},
|
|
811
|
-
searchInput: {},
|
|
812
|
-
// Stats bar - minimal design
|
|
813
|
-
statsBar: {
|
|
814
|
-
display: "none"
|
|
815
|
-
},
|
|
816
|
-
statChip: {
|
|
817
|
-
flexDirection: "row",
|
|
818
|
-
alignItems: "center",
|
|
819
|
-
gap: 4,
|
|
820
|
-
backgroundColor: _sharedUi.macOSColors.background.hover,
|
|
821
|
-
paddingHorizontal: 8,
|
|
822
|
-
paddingVertical: 4,
|
|
823
|
-
borderRadius: 12,
|
|
824
|
-
borderWidth: 1,
|
|
825
|
-
borderColor: "transparent"
|
|
826
|
-
},
|
|
827
|
-
statChipActive: {
|
|
828
|
-
backgroundColor: _sharedUi.macOSColors.semantic.info + "26",
|
|
829
|
-
borderColor: _sharedUi.macOSColors.semantic.info + "66"
|
|
830
|
-
},
|
|
831
|
-
statValue: {
|
|
832
|
-
fontSize: 14,
|
|
833
|
-
fontWeight: "600",
|
|
834
|
-
fontFamily: "monospace"
|
|
835
|
-
},
|
|
836
|
-
statLabel: {
|
|
837
|
-
fontSize: 10,
|
|
838
|
-
color: _sharedUi.macOSColors.text.muted,
|
|
839
|
-
fontWeight: "500",
|
|
840
|
-
textTransform: "uppercase"
|
|
841
|
-
},
|
|
842
|
-
disabledBanner: {
|
|
843
|
-
flexDirection: "row",
|
|
844
|
-
alignItems: "center",
|
|
845
|
-
gap: 8,
|
|
846
|
-
padding: 10,
|
|
847
|
-
marginHorizontal: 12,
|
|
848
|
-
marginTop: 8,
|
|
849
|
-
backgroundColor: _sharedUi.macOSColors.semantic.warningBackground,
|
|
850
|
-
borderRadius: 8,
|
|
851
|
-
borderWidth: 1,
|
|
852
|
-
borderColor: _sharedUi.macOSColors.semantic.warning + "20"
|
|
853
|
-
},
|
|
854
|
-
disabledText: {
|
|
855
|
-
color: _sharedUi.macOSColors.semantic.warning,
|
|
856
|
-
fontSize: 11,
|
|
857
|
-
flex: 1
|
|
858
|
-
},
|
|
859
|
-
listContent: {
|
|
860
|
-
paddingTop: 8
|
|
861
|
-
},
|
|
862
|
-
emptyState: {
|
|
863
|
-
alignItems: "center",
|
|
864
|
-
paddingVertical: 40
|
|
865
|
-
},
|
|
866
|
-
emptyTitle: {
|
|
867
|
-
color: _sharedUi.macOSColors.text.primary,
|
|
868
|
-
fontSize: 14,
|
|
869
|
-
fontWeight: "600",
|
|
870
|
-
marginTop: 12,
|
|
871
|
-
marginBottom: 6
|
|
872
|
-
},
|
|
873
|
-
emptyText: {
|
|
874
|
-
color: _sharedUi.macOSColors.text.muted,
|
|
875
|
-
fontSize: 12,
|
|
876
|
-
textAlign: "center"
|
|
877
|
-
},
|
|
878
|
-
// Free tier limit banner
|
|
879
|
-
limitBanner: {
|
|
880
|
-
backgroundColor: "#1A1A1A",
|
|
881
|
-
borderRadius: 10,
|
|
882
|
-
borderWidth: 1,
|
|
883
|
-
borderColor: "#20C997" + "40",
|
|
884
|
-
padding: 12,
|
|
885
|
-
marginHorizontal: 12,
|
|
886
|
-
marginTop: 12,
|
|
887
|
-
marginBottom: 34
|
|
888
|
-
},
|
|
889
|
-
limitBannerContent: {
|
|
890
|
-
flexDirection: "row",
|
|
891
|
-
alignItems: "center",
|
|
892
|
-
justifyContent: "space-between",
|
|
893
|
-
marginBottom: 4
|
|
894
|
-
},
|
|
895
|
-
limitBannerLeft: {
|
|
896
|
-
flexDirection: "row",
|
|
897
|
-
alignItems: "center",
|
|
898
|
-
gap: 8
|
|
899
|
-
},
|
|
900
|
-
limitBannerText: {
|
|
901
|
-
color: "#E0E0E0",
|
|
902
|
-
fontSize: 13,
|
|
903
|
-
fontWeight: "600"
|
|
904
|
-
},
|
|
905
|
-
limitBannerSubtext: {
|
|
906
|
-
color: "#888888",
|
|
907
|
-
fontSize: 11
|
|
908
431
|
}
|
|
909
432
|
});
|
|
910
433
|
|