@buoy-gg/storage 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 +607 -0
- package/lib/commonjs/index.js +34 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/preset.js +94 -0
- package/lib/commonjs/storage/components/DiffViewer/DiffOptionsPanel.js +356 -0
- package/lib/commonjs/storage/components/DiffViewer/TreeDiffViewer.js +29 -0
- package/lib/commonjs/storage/components/DiffViewer/components/DiffSummary.js +121 -0
- package/lib/commonjs/storage/components/DiffViewer/modes/ThemedSplitView.js +419 -0
- package/lib/commonjs/storage/components/DiffViewer/themes/diffThemes.js +122 -0
- package/lib/commonjs/storage/components/GameUIStorageBrowser.js +924 -0
- package/lib/commonjs/storage/components/GameUIStorageStats.js +746 -0
- package/lib/commonjs/storage/components/MMKVInstanceInfoPanel.js +257 -0
- package/lib/commonjs/storage/components/MMKVInstanceSelector.js +418 -0
- package/lib/commonjs/storage/components/SelectionActionBar.js +224 -0
- package/lib/commonjs/storage/components/StorageActionButtons.js +239 -0
- package/lib/commonjs/storage/components/StorageActions.js +192 -0
- package/lib/commonjs/storage/components/StorageBrowserMode.js +31 -0
- package/lib/commonjs/storage/components/StorageEventDetailContent.js +1025 -0
- package/lib/commonjs/storage/components/StorageEventFilterView.js +141 -0
- package/lib/commonjs/storage/components/StorageEventListener.js +357 -0
- package/lib/commonjs/storage/components/StorageEventsSection.js +24 -0
- package/lib/commonjs/storage/components/StorageFilterCards.js +345 -0
- package/lib/commonjs/storage/components/StorageFilterViewV2.js +42 -0
- package/lib/commonjs/storage/components/StorageKeyCard.js +516 -0
- package/lib/commonjs/storage/components/StorageKeyRow.js +356 -0
- package/lib/commonjs/storage/components/StorageKeySection.js +105 -0
- package/lib/commonjs/storage/components/StorageKeyStats.js +344 -0
- package/lib/commonjs/storage/components/StorageModalWithTabs.js +871 -0
- package/lib/commonjs/storage/components/StorageSection.js +43 -0
- package/lib/commonjs/storage/hooks/useAsyncStorageKeys.js +126 -0
- package/lib/commonjs/storage/hooks/useMMKVInstances.js +221 -0
- package/lib/commonjs/storage/hooks/useMMKVKeys.js +362 -0
- package/lib/commonjs/storage/hooks/useTickEverySecond.js +21 -0
- package/lib/commonjs/storage/index.js +148 -0
- package/lib/commonjs/storage/types.js +5 -0
- package/lib/commonjs/storage/utils/AsyncStorageListener.js +510 -0
- package/lib/commonjs/storage/utils/MMKVInstanceRegistry.js +202 -0
- package/lib/commonjs/storage/utils/MMKVListener.js +380 -0
- package/lib/commonjs/storage/utils/clearAllStorage.js +47 -0
- package/lib/commonjs/storage/utils/index.js +180 -0
- package/lib/commonjs/storage/utils/lineDiff.js +363 -0
- package/lib/commonjs/storage/utils/mmkvAvailability.js +62 -0
- package/lib/commonjs/storage/utils/mmkvTypeDetection.js +139 -0
- package/lib/commonjs/storage/utils/objectDiff.js +157 -0
- package/lib/commonjs/storage/utils/safeAsyncStorage.js +140 -0
- package/lib/commonjs/storage/utils/storageActionHelpers.js +46 -0
- package/lib/commonjs/storage/utils/storageQueryUtils.js +35 -0
- package/lib/commonjs/storage/utils/valueType.js +18 -0
- package/lib/module/index.js +7 -0
- package/lib/module/preset.js +89 -0
- package/lib/module/storage/components/DiffViewer/DiffOptionsPanel.js +352 -0
- package/lib/module/storage/components/DiffViewer/TreeDiffViewer.js +25 -0
- package/lib/module/storage/components/DiffViewer/components/DiffSummary.js +117 -0
- package/lib/module/storage/components/DiffViewer/modes/ThemedSplitView.js +415 -0
- package/lib/module/storage/components/DiffViewer/themes/diffThemes.js +118 -0
- package/lib/module/storage/components/GameUIStorageBrowser.js +922 -0
- package/lib/module/storage/components/GameUIStorageStats.js +742 -0
- package/lib/module/storage/components/MMKVInstanceInfoPanel.js +253 -0
- package/lib/module/storage/components/MMKVInstanceSelector.js +414 -0
- package/lib/module/storage/components/SelectionActionBar.js +221 -0
- package/lib/module/storage/components/StorageActionButtons.js +236 -0
- package/lib/module/storage/components/StorageActions.js +189 -0
- package/lib/module/storage/components/StorageBrowserMode.js +27 -0
- package/lib/module/storage/components/StorageEventDetailContent.js +1020 -0
- package/lib/module/storage/components/StorageEventFilterView.js +137 -0
- package/lib/module/storage/components/StorageEventListener.js +354 -0
- package/lib/module/storage/components/StorageEventsSection.js +20 -0
- package/lib/module/storage/components/StorageFilterCards.js +341 -0
- package/lib/module/storage/components/StorageFilterViewV2.js +38 -0
- package/lib/module/storage/components/StorageKeyCard.js +513 -0
- package/lib/module/storage/components/StorageKeyRow.js +353 -0
- package/lib/module/storage/components/StorageKeySection.js +101 -0
- package/lib/module/storage/components/StorageKeyStats.js +340 -0
- package/lib/module/storage/components/StorageModalWithTabs.js +867 -0
- package/lib/module/storage/components/StorageSection.js +40 -0
- package/lib/module/storage/hooks/useAsyncStorageKeys.js +121 -0
- package/lib/module/storage/hooks/useMMKVInstances.js +216 -0
- package/lib/module/storage/hooks/useMMKVKeys.js +359 -0
- package/lib/module/storage/hooks/useTickEverySecond.js +18 -0
- package/lib/module/storage/index.js +25 -0
- package/lib/module/storage/types.js +3 -0
- package/lib/module/storage/utils/AsyncStorageListener.js +500 -0
- package/lib/module/storage/utils/MMKVInstanceRegistry.js +196 -0
- package/lib/module/storage/utils/MMKVListener.js +367 -0
- package/lib/module/storage/utils/clearAllStorage.js +42 -0
- package/lib/module/storage/utils/index.js +22 -0
- package/lib/module/storage/utils/lineDiff.js +359 -0
- package/lib/module/storage/utils/mmkvAvailability.js +56 -0
- package/lib/module/storage/utils/mmkvTypeDetection.js +133 -0
- package/lib/module/storage/utils/objectDiff.js +153 -0
- package/lib/module/storage/utils/safeAsyncStorage.js +134 -0
- package/lib/module/storage/utils/storageActionHelpers.js +42 -0
- package/lib/module/storage/utils/storageQueryUtils.js +30 -0
- package/lib/module/storage/utils/valueType.js +14 -0
- package/lib/typescript/index.d.ts +3 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/preset.d.ts +90 -0
- package/lib/typescript/preset.d.ts.map +1 -0
- package/lib/typescript/storage/components/DiffViewer/DiffOptionsPanel.d.ts +18 -0
- package/lib/typescript/storage/components/DiffViewer/DiffOptionsPanel.d.ts.map +1 -0
- package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts +7 -0
- package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts.map +1 -0
- package/lib/typescript/storage/components/DiffViewer/components/DiffSummary.d.ts +12 -0
- package/lib/typescript/storage/components/DiffViewer/components/DiffSummary.d.ts.map +1 -0
- package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts +13 -0
- package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts.map +1 -0
- package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts +64 -0
- package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts.map +1 -0
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts +16 -0
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts.map +1 -0
- package/lib/typescript/storage/components/GameUIStorageStats.d.ts +7 -0
- package/lib/typescript/storage/components/GameUIStorageStats.d.ts.map +1 -0
- package/lib/typescript/storage/components/MMKVInstanceInfoPanel.d.ts +42 -0
- package/lib/typescript/storage/components/MMKVInstanceInfoPanel.d.ts.map +1 -0
- package/lib/typescript/storage/components/MMKVInstanceSelector.d.ts +35 -0
- package/lib/typescript/storage/components/MMKVInstanceSelector.d.ts.map +1 -0
- package/lib/typescript/storage/components/SelectionActionBar.d.ts +21 -0
- package/lib/typescript/storage/components/SelectionActionBar.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageActionButtons.d.ts +21 -0
- package/lib/typescript/storage/components/StorageActionButtons.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageActions.d.ts +10 -0
- package/lib/typescript/storage/components/StorageActions.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageBrowserMode.d.ts +18 -0
- package/lib/typescript/storage/components/StorageBrowserMode.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageEventDetailContent.d.ts +40 -0
- package/lib/typescript/storage/components/StorageEventDetailContent.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageEventFilterView.d.ts +11 -0
- package/lib/typescript/storage/components/StorageEventFilterView.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageEventListener.d.ts +6 -0
- package/lib/typescript/storage/components/StorageEventListener.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageEventsSection.d.ts +7 -0
- package/lib/typescript/storage/components/StorageEventsSection.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageFilterCards.d.ts +36 -0
- package/lib/typescript/storage/components/StorageFilterCards.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageFilterViewV2.d.ts +9 -0
- package/lib/typescript/storage/components/StorageFilterViewV2.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageKeyCard.d.ts +17 -0
- package/lib/typescript/storage/components/StorageKeyCard.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageKeyRow.d.ts +15 -0
- package/lib/typescript/storage/components/StorageKeyRow.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageKeySection.d.ts +25 -0
- package/lib/typescript/storage/components/StorageKeySection.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageKeyStats.d.ts +15 -0
- package/lib/typescript/storage/components/StorageKeyStats.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts +13 -0
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageSection.d.ts +10 -0
- package/lib/typescript/storage/components/StorageSection.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts +10 -0
- package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useMMKVInstances.d.ts +114 -0
- package/lib/typescript/storage/hooks/useMMKVInstances.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useMMKVKeys.d.ts +94 -0
- package/lib/typescript/storage/hooks/useMMKVKeys.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useTickEverySecond.d.ts +6 -0
- package/lib/typescript/storage/hooks/useTickEverySecond.d.ts.map +1 -0
- package/lib/typescript/storage/index.d.ts +15 -0
- package/lib/typescript/storage/index.d.ts.map +1 -0
- package/lib/typescript/storage/types.d.ts +41 -0
- package/lib/typescript/storage/types.d.ts.map +1 -0
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts +195 -0
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts.map +1 -0
- package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts +224 -0
- package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts.map +1 -0
- package/lib/typescript/storage/utils/MMKVListener.d.ts +218 -0
- package/lib/typescript/storage/utils/MMKVListener.d.ts.map +1 -0
- package/lib/typescript/storage/utils/clearAllStorage.d.ts +11 -0
- package/lib/typescript/storage/utils/clearAllStorage.d.ts.map +1 -0
- package/lib/typescript/storage/utils/index.d.ts +8 -0
- package/lib/typescript/storage/utils/index.d.ts.map +1 -0
- package/lib/typescript/storage/utils/lineDiff.d.ts +34 -0
- package/lib/typescript/storage/utils/lineDiff.d.ts.map +1 -0
- package/lib/typescript/storage/utils/mmkvAvailability.d.ts +23 -0
- package/lib/typescript/storage/utils/mmkvAvailability.d.ts.map +1 -0
- package/lib/typescript/storage/utils/mmkvTypeDetection.d.ts +71 -0
- package/lib/typescript/storage/utils/mmkvTypeDetection.d.ts.map +1 -0
- package/lib/typescript/storage/utils/objectDiff.d.ts +35 -0
- package/lib/typescript/storage/utils/objectDiff.d.ts.map +1 -0
- package/lib/typescript/storage/utils/safeAsyncStorage.d.ts +56 -0
- package/lib/typescript/storage/utils/safeAsyncStorage.d.ts.map +1 -0
- package/lib/typescript/storage/utils/storageActionHelpers.d.ts +5 -0
- package/lib/typescript/storage/utils/storageActionHelpers.d.ts.map +1 -0
- package/lib/typescript/storage/utils/storageQueryUtils.d.ts +6 -0
- package/lib/typescript/storage/utils/storageQueryUtils.d.ts.map +1 -0
- package/lib/typescript/storage/utils/valueType.d.ts +3 -0
- package/lib/typescript/storage/utils/valueType.d.ts.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,867 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useState, useCallback, useEffect, useRef, useMemo } from "react";
|
|
4
|
+
import { Text, View, TouchableOpacity, StyleSheet, FlatList, Alert } from "react-native";
|
|
5
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
6
|
+
import { JsModal, ModalHeader, TabSelector, ValueTypeBadge, StorageTypeBadge, formatRelativeTime, parseValue, devToolsStorageKeys, macOSColors, Database, Pause, Play, Trash2, Filter, Search, SearchBar } from "@buoy-gg/shared-ui";
|
|
7
|
+
import { StorageBrowserMode } from "./StorageBrowserMode";
|
|
8
|
+
import { clearAllAppStorage, clearAllStorageIncludingDevTools } from "../utils/clearAllStorage";
|
|
9
|
+
import { ProFeatureBanner } from "@buoy-gg/shared-ui";
|
|
10
|
+
import { startListening, stopListening, addListener, isListening as checkIsListening } from "../utils/AsyncStorageListener";
|
|
11
|
+
import { StorageEventDetailContent, StorageEventDetailFooter } from "./StorageEventDetailContent";
|
|
12
|
+
import { StorageFilterViewV2 } from "./StorageFilterViewV2";
|
|
13
|
+
import { StorageEventFilterView } from "./StorageEventFilterView";
|
|
14
|
+
import { translateStorageAction } from "../utils/storageActionHelpers";
|
|
15
|
+
import { isMMKVAvailable } from "../utils/mmkvAvailability";
|
|
16
|
+
|
|
17
|
+
// Conditionally import MMKV listener
|
|
18
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
19
|
+
let addMMKVListener;
|
|
20
|
+
if (isMMKVAvailable()) {
|
|
21
|
+
const mmkvListener = require("../utils/MMKVListener");
|
|
22
|
+
addMMKVListener = mmkvListener.addMMKVListener;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Unified storage event type
|
|
26
|
+
|
|
27
|
+
// Lazy load the license hooks to avoid circular dependencies
|
|
28
|
+
let _useIsPro = null;
|
|
29
|
+
let _licenseLoadAttempted = false;
|
|
30
|
+
function loadLicenseModule() {
|
|
31
|
+
if (_licenseLoadAttempted) return;
|
|
32
|
+
_licenseLoadAttempted = true;
|
|
33
|
+
try {
|
|
34
|
+
const mod = require("@buoy-gg/license");
|
|
35
|
+
if (mod) {
|
|
36
|
+
_useIsPro = mod.useIsPro ?? null;
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
// License package not available
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function getUseIsPro() {
|
|
43
|
+
loadLicenseModule();
|
|
44
|
+
return _useIsPro ?? (() => false);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Free tier limit for storage events/conversations
|
|
48
|
+
export const FREE_TIER_EVENT_LIMIT = 25;
|
|
49
|
+
export function StorageModalWithTabs({
|
|
50
|
+
visible,
|
|
51
|
+
onClose,
|
|
52
|
+
onBack,
|
|
53
|
+
onMinimize,
|
|
54
|
+
enableSharedModalDimensions = false,
|
|
55
|
+
requiredStorageKeys = []
|
|
56
|
+
}) {
|
|
57
|
+
// Check Pro status internally
|
|
58
|
+
const useIsPro = getUseIsPro();
|
|
59
|
+
const isPro = useIsPro();
|
|
60
|
+
const [activeTab, setActiveTab] = useState("browser");
|
|
61
|
+
|
|
62
|
+
// Storage Browser state
|
|
63
|
+
const [showStorageFilters, setShowStorageFilters] = useState(false);
|
|
64
|
+
const [storageIgnoredPatterns, setStorageIgnoredPatterns] = useState(new Set(["@react_buoy"]) // Auto-hide dev tool keys by default
|
|
65
|
+
);
|
|
66
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
67
|
+
const [isSearchActive, setIsSearchActive] = useState(false);
|
|
68
|
+
const hasLoadedStorageFilters = useRef(false);
|
|
69
|
+
|
|
70
|
+
// Event Listener state
|
|
71
|
+
const [events, setEvents] = useState([]);
|
|
72
|
+
const [isListening, setIsListening] = useState(false);
|
|
73
|
+
const [selectedConversationKey, setSelectedConversationKey] = useState(null);
|
|
74
|
+
const [selectedEventIndex, setSelectedEventIndex] = useState(0);
|
|
75
|
+
const [showFilters, setShowFilters] = useState(false);
|
|
76
|
+
const [ignoredPatterns, setIgnoredPatterns] = useState(new Set(["@RNAsyncStorage", "redux-persist", "persist:"]) // Only show @react_buoy events by default
|
|
77
|
+
);
|
|
78
|
+
const [enabledStorageTypes, setEnabledStorageTypes] = useState(new Set(['async', 'mmkv', 'secure']) // All enabled by default
|
|
79
|
+
);
|
|
80
|
+
const lastEventRef = useRef(null);
|
|
81
|
+
const hasLoadedFilters = useRef(false);
|
|
82
|
+
const hasLoadedTabState = useRef(false);
|
|
83
|
+
const hasLoadedMonitoringState = useRef(false);
|
|
84
|
+
const handleModeChange = useCallback(_mode => {
|
|
85
|
+
// Mode changes handled by JsModal
|
|
86
|
+
}, []);
|
|
87
|
+
|
|
88
|
+
// Timer removed - using useTickEveryMinute hook instead
|
|
89
|
+
|
|
90
|
+
// Load persisted tab state on mount
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
if (!visible || hasLoadedTabState.current) return;
|
|
93
|
+
const loadTabState = async () => {
|
|
94
|
+
try {
|
|
95
|
+
const storedTab = await AsyncStorage.getItem(devToolsStorageKeys.storage.activeTab());
|
|
96
|
+
if (storedTab && (storedTab === "browser" || storedTab === "events")) {
|
|
97
|
+
setActiveTab(storedTab);
|
|
98
|
+
}
|
|
99
|
+
hasLoadedTabState.current = true;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
// Failed to load tab state
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
loadTabState();
|
|
105
|
+
}, [visible]);
|
|
106
|
+
|
|
107
|
+
// Load persisted monitoring state on mount
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (!visible || hasLoadedMonitoringState.current) return;
|
|
110
|
+
const loadMonitoringState = async () => {
|
|
111
|
+
try {
|
|
112
|
+
const storedMonitoring = await AsyncStorage.getItem(devToolsStorageKeys.storage.isMonitoring());
|
|
113
|
+
if (storedMonitoring !== null) {
|
|
114
|
+
const shouldMonitor = storedMonitoring === "true";
|
|
115
|
+
if (shouldMonitor && !checkIsListening()) {
|
|
116
|
+
await startListening();
|
|
117
|
+
setIsListening(true);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
hasLoadedMonitoringState.current = true;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
// Failed to load monitoring state
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
loadMonitoringState();
|
|
126
|
+
}, [visible]);
|
|
127
|
+
|
|
128
|
+
// Note: Conversations will appear when storage events are triggered
|
|
129
|
+
// Click on any conversation to see the unified view with toggle cards
|
|
130
|
+
|
|
131
|
+
// Save tab state when it changes
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
if (!hasLoadedTabState.current) return; // Don't save on initial load
|
|
134
|
+
|
|
135
|
+
const saveTabState = async () => {
|
|
136
|
+
try {
|
|
137
|
+
await AsyncStorage.setItem(devToolsStorageKeys.storage.activeTab(), activeTab);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
// Failed to save tab state
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
saveTabState();
|
|
143
|
+
}, [activeTab]);
|
|
144
|
+
|
|
145
|
+
// Save monitoring state when it changes
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
if (!hasLoadedMonitoringState.current) return; // Don't save on initial load
|
|
148
|
+
|
|
149
|
+
const saveMonitoringState = async () => {
|
|
150
|
+
try {
|
|
151
|
+
await AsyncStorage.setItem(devToolsStorageKeys.storage.isMonitoring(), isListening.toString());
|
|
152
|
+
} catch (error) {
|
|
153
|
+
// Failed to save monitoring state
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
saveMonitoringState();
|
|
157
|
+
}, [isListening]);
|
|
158
|
+
|
|
159
|
+
// Load persisted filters on mount
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
if (!visible || hasLoadedFilters.current) return;
|
|
162
|
+
const loadFilters = async () => {
|
|
163
|
+
try {
|
|
164
|
+
const storedFilters = await AsyncStorage.getItem(devToolsStorageKeys.storage.eventFilters());
|
|
165
|
+
if (storedFilters) {
|
|
166
|
+
const filters = JSON.parse(storedFilters);
|
|
167
|
+
setIgnoredPatterns(new Set(filters));
|
|
168
|
+
}
|
|
169
|
+
hasLoadedFilters.current = true;
|
|
170
|
+
} catch (error) {
|
|
171
|
+
// Failed to load filters
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
loadFilters();
|
|
175
|
+
}, [visible]);
|
|
176
|
+
|
|
177
|
+
// Save filters when they change
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
if (!hasLoadedFilters.current) return; // Don't save on initial load
|
|
180
|
+
|
|
181
|
+
const saveFilters = async () => {
|
|
182
|
+
try {
|
|
183
|
+
const filters = Array.from(ignoredPatterns);
|
|
184
|
+
await AsyncStorage.setItem(devToolsStorageKeys.storage.eventFilters(), JSON.stringify(filters));
|
|
185
|
+
} catch (error) {
|
|
186
|
+
// Failed to save filters
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
saveFilters();
|
|
190
|
+
}, [ignoredPatterns]);
|
|
191
|
+
|
|
192
|
+
// Sync isListening state with actual listener state on mount
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
if (!visible) return;
|
|
195
|
+
|
|
196
|
+
// Check if already listening and sync state
|
|
197
|
+
const listening = checkIsListening();
|
|
198
|
+
setIsListening(listening);
|
|
199
|
+
}, [visible]);
|
|
200
|
+
|
|
201
|
+
// Event listener setup - only collect events when isListening is true
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
if (!visible || !isListening) return;
|
|
204
|
+
|
|
205
|
+
// Set up AsyncStorage event listener
|
|
206
|
+
const unsubscribeAsync = addListener(event => {
|
|
207
|
+
const storageEvent = {
|
|
208
|
+
...event,
|
|
209
|
+
storageType: 'async'
|
|
210
|
+
};
|
|
211
|
+
lastEventRef.current = storageEvent;
|
|
212
|
+
setEvents(prev => {
|
|
213
|
+
const updated = [storageEvent, ...prev];
|
|
214
|
+
return updated.slice(0, 500);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Set up MMKV event listener (if available)
|
|
219
|
+
let unsubscribeMMKV = () => {};
|
|
220
|
+
if (isMMKVAvailable() && addMMKVListener) {
|
|
221
|
+
unsubscribeMMKV = addMMKVListener(event => {
|
|
222
|
+
const storageEvent = {
|
|
223
|
+
...event,
|
|
224
|
+
storageType: 'mmkv'
|
|
225
|
+
};
|
|
226
|
+
lastEventRef.current = storageEvent;
|
|
227
|
+
setEvents(prev => {
|
|
228
|
+
const updated = [storageEvent, ...prev];
|
|
229
|
+
return updated.slice(0, 500);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return () => {
|
|
234
|
+
unsubscribeAsync();
|
|
235
|
+
unsubscribeMMKV();
|
|
236
|
+
};
|
|
237
|
+
}, [visible, isListening]);
|
|
238
|
+
const handleToggleListening = useCallback(async () => {
|
|
239
|
+
if (isListening) {
|
|
240
|
+
stopListening();
|
|
241
|
+
setIsListening(false);
|
|
242
|
+
} else {
|
|
243
|
+
await startListening();
|
|
244
|
+
setIsListening(true);
|
|
245
|
+
}
|
|
246
|
+
}, [isListening]);
|
|
247
|
+
const handleClearEvents = useCallback(() => {
|
|
248
|
+
setEvents([]);
|
|
249
|
+
setSelectedConversationKey(null);
|
|
250
|
+
}, []);
|
|
251
|
+
const handleConversationPress = useCallback(conversation => {
|
|
252
|
+
setSelectedConversationKey(conversation.key);
|
|
253
|
+
setSelectedEventIndex(0);
|
|
254
|
+
}, []);
|
|
255
|
+
const handleTogglePattern = useCallback(pattern => {
|
|
256
|
+
setIgnoredPatterns(prev => {
|
|
257
|
+
const next = new Set(prev);
|
|
258
|
+
if (next.has(pattern)) {
|
|
259
|
+
next.delete(pattern);
|
|
260
|
+
} else {
|
|
261
|
+
next.add(pattern);
|
|
262
|
+
}
|
|
263
|
+
return next;
|
|
264
|
+
});
|
|
265
|
+
}, []);
|
|
266
|
+
const handleAddPattern = useCallback(pattern => {
|
|
267
|
+
setIgnoredPatterns(prev => new Set([...prev, pattern]));
|
|
268
|
+
}, []);
|
|
269
|
+
const handleToggleFilters = useCallback(() => {
|
|
270
|
+
setShowFilters(!showFilters);
|
|
271
|
+
}, [showFilters]);
|
|
272
|
+
const handleToggleStorageType = useCallback(type => {
|
|
273
|
+
setEnabledStorageTypes(prev => {
|
|
274
|
+
const next = new Set(prev);
|
|
275
|
+
if (next.has(type)) {
|
|
276
|
+
next.delete(type);
|
|
277
|
+
} else {
|
|
278
|
+
next.add(type);
|
|
279
|
+
}
|
|
280
|
+
return next;
|
|
281
|
+
});
|
|
282
|
+
}, []);
|
|
283
|
+
|
|
284
|
+
// Storage Browser handlers
|
|
285
|
+
const storageDataRef = useRef([]);
|
|
286
|
+
const handleToggleStorageFilters = useCallback(() => {
|
|
287
|
+
setShowStorageFilters(!showStorageFilters);
|
|
288
|
+
}, [showStorageFilters]);
|
|
289
|
+
const handleToggleStoragePattern = useCallback(pattern => {
|
|
290
|
+
setStorageIgnoredPatterns(prev => {
|
|
291
|
+
const next = new Set(prev);
|
|
292
|
+
if (next.has(pattern)) {
|
|
293
|
+
next.delete(pattern);
|
|
294
|
+
} else {
|
|
295
|
+
next.add(pattern);
|
|
296
|
+
}
|
|
297
|
+
return next;
|
|
298
|
+
});
|
|
299
|
+
}, []);
|
|
300
|
+
const handleAddStoragePattern = useCallback(pattern => {
|
|
301
|
+
setStorageIgnoredPatterns(prev => new Set([...prev, pattern]));
|
|
302
|
+
}, []);
|
|
303
|
+
const handlePurgeStorage = useCallback(async () => {
|
|
304
|
+
Alert.alert("Clear Storage", "Choose what to clear:", [{
|
|
305
|
+
text: "Cancel",
|
|
306
|
+
style: "cancel"
|
|
307
|
+
}, {
|
|
308
|
+
text: "Clear App Storage",
|
|
309
|
+
onPress: async () => {
|
|
310
|
+
try {
|
|
311
|
+
await clearAllAppStorage();
|
|
312
|
+
// Refresh will be handled by GameUIStorageBrowser
|
|
313
|
+
} catch (error) {
|
|
314
|
+
Alert.alert("Error", "Failed to clear app storage");
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}, {
|
|
318
|
+
text: "Clear All (Including Dev Tools)",
|
|
319
|
+
style: "destructive",
|
|
320
|
+
onPress: async () => {
|
|
321
|
+
try {
|
|
322
|
+
await clearAllStorageIncludingDevTools();
|
|
323
|
+
// Refresh will be handled by GameUIStorageBrowser
|
|
324
|
+
} catch (error) {
|
|
325
|
+
Alert.alert("Error", "Failed to clear all storage");
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}]);
|
|
329
|
+
}, []);
|
|
330
|
+
const getValueType = value => {
|
|
331
|
+
const parsed = parseValue(value);
|
|
332
|
+
if (parsed === null) return "null";
|
|
333
|
+
if (parsed === undefined) return "undefined";
|
|
334
|
+
if (Array.isArray(parsed)) return "array";
|
|
335
|
+
if (typeof parsed === "boolean") return "boolean";
|
|
336
|
+
if (typeof parsed === "number") return "number";
|
|
337
|
+
if (typeof parsed === "string") return "string";
|
|
338
|
+
if (typeof parsed === "object") return "object";
|
|
339
|
+
return "undefined";
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// Get all unique keys from events AND from AsyncStorage for filter view
|
|
343
|
+
const [allStorageKeys, setAllStorageKeys] = useState([]);
|
|
344
|
+
useEffect(() => {
|
|
345
|
+
const fetchAllKeys = async () => {
|
|
346
|
+
try {
|
|
347
|
+
const keys = await AsyncStorage.getAllKeys();
|
|
348
|
+
setAllStorageKeys([...keys].sort());
|
|
349
|
+
} catch (error) {
|
|
350
|
+
// Failed to fetch keys
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
// Fetch all keys for both tabs when visible
|
|
355
|
+
if (visible) {
|
|
356
|
+
fetchAllKeys();
|
|
357
|
+
}
|
|
358
|
+
}, [visible]);
|
|
359
|
+
const allEventKeys = useMemo(() => {
|
|
360
|
+
// Combine storage keys with event keys for comprehensive filter view
|
|
361
|
+
const keys = new Set(allStorageKeys);
|
|
362
|
+
events.forEach(event => {
|
|
363
|
+
if (event.data?.key) {
|
|
364
|
+
keys.add(event.data.key);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
return Array.from(keys).sort();
|
|
368
|
+
}, [events, allStorageKeys]);
|
|
369
|
+
|
|
370
|
+
// Group events by key and create conversations
|
|
371
|
+
const conversations = useMemo(() => {
|
|
372
|
+
const keyMap = new Map();
|
|
373
|
+
events.forEach(event => {
|
|
374
|
+
if (!event.data?.key) return;
|
|
375
|
+
const key = event.data.key;
|
|
376
|
+
|
|
377
|
+
// Filter by enabled storage types
|
|
378
|
+
if (!enabledStorageTypes.has(event.storageType)) return;
|
|
379
|
+
|
|
380
|
+
// Filter out keys that match ignored patterns
|
|
381
|
+
const shouldIgnore = Array.from(ignoredPatterns).some(pattern => key.includes(pattern));
|
|
382
|
+
if (shouldIgnore) return;
|
|
383
|
+
const existing = keyMap.get(key);
|
|
384
|
+
if (!existing) {
|
|
385
|
+
keyMap.set(key, {
|
|
386
|
+
key,
|
|
387
|
+
lastEvent: event,
|
|
388
|
+
events: [event],
|
|
389
|
+
totalOperations: 1,
|
|
390
|
+
currentValue: event.data.value,
|
|
391
|
+
valueType: getValueType(event.data.value),
|
|
392
|
+
storageTypes: new Set([event.storageType])
|
|
393
|
+
});
|
|
394
|
+
} else {
|
|
395
|
+
existing.events.push(event);
|
|
396
|
+
existing.totalOperations++;
|
|
397
|
+
existing.storageTypes.add(event.storageType);
|
|
398
|
+
|
|
399
|
+
// Update last event if this one is newer
|
|
400
|
+
if (event.timestamp > existing.lastEvent.timestamp) {
|
|
401
|
+
existing.lastEvent = event;
|
|
402
|
+
existing.currentValue = event.data.value;
|
|
403
|
+
existing.valueType = getValueType(event.data.value);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// Convert to array and sort by last updated
|
|
409
|
+
return Array.from(keyMap.values()).sort((a, b) => b.lastEvent.timestamp.getTime() - a.lastEvent.timestamp.getTime());
|
|
410
|
+
}, [events, ignoredPatterns, enabledStorageTypes]);
|
|
411
|
+
|
|
412
|
+
// Get the live selected conversation from the current conversations array
|
|
413
|
+
const selectedConversation = useMemo(() => {
|
|
414
|
+
if (!selectedConversationKey) return null;
|
|
415
|
+
return conversations.find(c => c.key === selectedConversationKey) || null;
|
|
416
|
+
}, [selectedConversationKey, conversations]);
|
|
417
|
+
|
|
418
|
+
// For free users, limit visible conversations
|
|
419
|
+
const visibleConversations = useMemo(() => {
|
|
420
|
+
if (isPro) return conversations;
|
|
421
|
+
return conversations.slice(0, FREE_TIER_EVENT_LIMIT);
|
|
422
|
+
}, [conversations, isPro]);
|
|
423
|
+
const lockedConversationCount = useMemo(() => {
|
|
424
|
+
if (isPro) return 0;
|
|
425
|
+
return Math.max(0, conversations.length - FREE_TIER_EVENT_LIMIT);
|
|
426
|
+
}, [conversations.length, isPro]);
|
|
427
|
+
const getActionColor = action => {
|
|
428
|
+
switch (action) {
|
|
429
|
+
// AsyncStorage - Set operations
|
|
430
|
+
case "setItem":
|
|
431
|
+
case "multiSet":
|
|
432
|
+
// MMKV - Set operations
|
|
433
|
+
// falls through
|
|
434
|
+
case "set.string":
|
|
435
|
+
case "set.number":
|
|
436
|
+
case "set.boolean":
|
|
437
|
+
case "set.buffer":
|
|
438
|
+
return macOSColors.semantic.success;
|
|
439
|
+
|
|
440
|
+
// AsyncStorage - Remove operations
|
|
441
|
+
case "removeItem":
|
|
442
|
+
case "multiRemove":
|
|
443
|
+
case "clear":
|
|
444
|
+
// MMKV - Delete operations
|
|
445
|
+
// falls through
|
|
446
|
+
case "delete":
|
|
447
|
+
case "clearAll":
|
|
448
|
+
return macOSColors.semantic.error;
|
|
449
|
+
|
|
450
|
+
// AsyncStorage - Merge operations
|
|
451
|
+
case "mergeItem":
|
|
452
|
+
case "multiMerge":
|
|
453
|
+
return macOSColors.semantic.info;
|
|
454
|
+
|
|
455
|
+
// MMKV - Get operations
|
|
456
|
+
case "get.string":
|
|
457
|
+
case "get.number":
|
|
458
|
+
case "get.boolean":
|
|
459
|
+
case "get.buffer":
|
|
460
|
+
return macOSColors.semantic.warning;
|
|
461
|
+
default:
|
|
462
|
+
return macOSColors.text.muted;
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
// FlatList optimization constants
|
|
467
|
+
const END_REACHED_THRESHOLD = 0.8;
|
|
468
|
+
|
|
469
|
+
// Stable keyExtractor for FlatList
|
|
470
|
+
const keyExtractor = useCallback(item => {
|
|
471
|
+
return item.key;
|
|
472
|
+
}, []);
|
|
473
|
+
|
|
474
|
+
// Removed getItemType as it's FlatList-specific
|
|
475
|
+
|
|
476
|
+
// Create stable ref for event handler
|
|
477
|
+
const selectConversationRef = useRef(undefined);
|
|
478
|
+
selectConversationRef.current = handleConversationPress;
|
|
479
|
+
|
|
480
|
+
// Stable renderItem with ref pattern
|
|
481
|
+
const renderConversationItem = useCallback(({
|
|
482
|
+
item
|
|
483
|
+
}) => {
|
|
484
|
+
return /*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
485
|
+
onPress: () => selectConversationRef.current?.(item),
|
|
486
|
+
style: styles.conversationItem,
|
|
487
|
+
children: [/*#__PURE__*/_jsxs(View, {
|
|
488
|
+
style: styles.conversationHeader,
|
|
489
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
490
|
+
style: styles.keyText,
|
|
491
|
+
numberOfLines: 1,
|
|
492
|
+
children: item.key
|
|
493
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
494
|
+
style: [styles.actionText, {
|
|
495
|
+
color: getActionColor(item.lastEvent.action)
|
|
496
|
+
}],
|
|
497
|
+
children: translateStorageAction(item.lastEvent.action)
|
|
498
|
+
})]
|
|
499
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
500
|
+
style: styles.conversationDetails,
|
|
501
|
+
children: [item.storageTypes && Array.from(item.storageTypes).map(storageType => /*#__PURE__*/_jsx(StorageTypeBadge, {
|
|
502
|
+
type: storageType
|
|
503
|
+
}, storageType)), /*#__PURE__*/_jsx(ValueTypeBadge, {
|
|
504
|
+
type: item.valueType
|
|
505
|
+
}), /*#__PURE__*/_jsxs(Text, {
|
|
506
|
+
style: styles.operationCount,
|
|
507
|
+
children: [item.totalOperations, " operation", item.totalOperations !== 1 ? "s" : ""]
|
|
508
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
509
|
+
style: styles.timestamp,
|
|
510
|
+
children: formatRelativeTime(item.lastEvent.timestamp)
|
|
511
|
+
})]
|
|
512
|
+
})]
|
|
513
|
+
});
|
|
514
|
+
}, []);
|
|
515
|
+
if (!visible) return null;
|
|
516
|
+
const persistenceKey = enableSharedModalDimensions ? devToolsStorageKeys.modal.root() : devToolsStorageKeys.storage.modal();
|
|
517
|
+
const renderContent = () => {
|
|
518
|
+
if (activeTab === "browser") {
|
|
519
|
+
if (showStorageFilters) {
|
|
520
|
+
return /*#__PURE__*/_jsx(StorageFilterViewV2, {
|
|
521
|
+
ignoredPatterns: storageIgnoredPatterns,
|
|
522
|
+
onTogglePattern: handleToggleStoragePattern,
|
|
523
|
+
onAddPattern: handleAddStoragePattern,
|
|
524
|
+
availableKeys: allStorageKeys
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
return /*#__PURE__*/_jsx(StorageBrowserMode, {
|
|
528
|
+
requiredStorageKeys: requiredStorageKeys,
|
|
529
|
+
showFilters: showStorageFilters,
|
|
530
|
+
ignoredPatterns: storageIgnoredPatterns,
|
|
531
|
+
onTogglePattern: handleToggleStoragePattern,
|
|
532
|
+
onAddPattern: handleAddStoragePattern,
|
|
533
|
+
searchQuery: searchQuery,
|
|
534
|
+
storageDataRef: storageDataRef
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Events tab content
|
|
539
|
+
if (selectedConversation) {
|
|
540
|
+
return /*#__PURE__*/_jsx(View, {
|
|
541
|
+
style: styles.contentWrapper,
|
|
542
|
+
children: /*#__PURE__*/_jsx(StorageEventDetailContent, {
|
|
543
|
+
conversation: selectedConversation,
|
|
544
|
+
selectedEventIndex: selectedEventIndex,
|
|
545
|
+
onEventIndexChange: setSelectedEventIndex,
|
|
546
|
+
disableInternalFooter: true
|
|
547
|
+
})
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
if (showFilters) {
|
|
551
|
+
return /*#__PURE__*/_jsx(StorageEventFilterView, {
|
|
552
|
+
ignoredPatterns: ignoredPatterns,
|
|
553
|
+
onTogglePattern: handleTogglePattern,
|
|
554
|
+
onAddPattern: handleAddPattern,
|
|
555
|
+
availableKeys: allEventKeys,
|
|
556
|
+
enabledStorageTypes: enabledStorageTypes,
|
|
557
|
+
onToggleStorageType: handleToggleStorageType
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
if (conversations.length === 0) {
|
|
561
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
562
|
+
style: styles.emptyState,
|
|
563
|
+
children: [/*#__PURE__*/_jsx(Database, {
|
|
564
|
+
size: 48,
|
|
565
|
+
color: macOSColors.text.muted
|
|
566
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
567
|
+
style: styles.emptyTitle,
|
|
568
|
+
children: isListening ? "No storage events yet" : "Event listener is paused"
|
|
569
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
570
|
+
style: styles.emptySubtitle,
|
|
571
|
+
children: isListening ? "Storage operations will appear here" : "Press play to start monitoring"
|
|
572
|
+
})]
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
return /*#__PURE__*/_jsx(FlatList, {
|
|
576
|
+
data: visibleConversations,
|
|
577
|
+
renderItem: renderConversationItem,
|
|
578
|
+
keyExtractor: keyExtractor,
|
|
579
|
+
onEndReachedThreshold: END_REACHED_THRESHOLD,
|
|
580
|
+
contentContainerStyle: styles.listContent,
|
|
581
|
+
ItemSeparatorComponent: () => /*#__PURE__*/_jsx(View, {
|
|
582
|
+
style: styles.separator
|
|
583
|
+
}),
|
|
584
|
+
ListFooterComponent: lockedConversationCount > 0 ? /*#__PURE__*/_jsx(View, {
|
|
585
|
+
style: styles.lockedBannerContainer,
|
|
586
|
+
children: /*#__PURE__*/_jsx(ProFeatureBanner, {
|
|
587
|
+
featureName: `${lockedConversationCount} event${lockedConversationCount > 1 ? 's' : ''} locked`,
|
|
588
|
+
description: "Upgrade to Pro to unlock full event history"
|
|
589
|
+
})
|
|
590
|
+
}) : null,
|
|
591
|
+
initialNumToRender: 10,
|
|
592
|
+
maxToRenderPerBatch: 10,
|
|
593
|
+
windowSize: 10,
|
|
594
|
+
scrollEnabled: false
|
|
595
|
+
});
|
|
596
|
+
};
|
|
597
|
+
const footerNode = selectedConversation ? /*#__PURE__*/_jsx(StorageEventDetailFooter, {
|
|
598
|
+
conversation: selectedConversation,
|
|
599
|
+
selectedEventIndex: selectedEventIndex,
|
|
600
|
+
onEventIndexChange: setSelectedEventIndex
|
|
601
|
+
}) : null;
|
|
602
|
+
|
|
603
|
+
// Determine the appropriate back handler based on current view state
|
|
604
|
+
const currentBackHandler = showStorageFilters ? () => setShowStorageFilters(false) : showFilters ? () => setShowFilters(false) : selectedConversation ? () => {
|
|
605
|
+
setSelectedConversationKey(null);
|
|
606
|
+
setSelectedEventIndex(0);
|
|
607
|
+
} : onBack;
|
|
608
|
+
return /*#__PURE__*/_jsx(JsModal, {
|
|
609
|
+
visible: visible,
|
|
610
|
+
onClose: onClose,
|
|
611
|
+
onBack: currentBackHandler,
|
|
612
|
+
onMinimize: onMinimize,
|
|
613
|
+
persistenceKey: persistenceKey,
|
|
614
|
+
header: {
|
|
615
|
+
showToggleButton: true,
|
|
616
|
+
customContent: showStorageFilters ? /*#__PURE__*/_jsxs(ModalHeader, {
|
|
617
|
+
children: [/*#__PURE__*/_jsx(ModalHeader.Navigation, {
|
|
618
|
+
onBack: () => setShowStorageFilters(false)
|
|
619
|
+
}), /*#__PURE__*/_jsx(ModalHeader.Content, {
|
|
620
|
+
title: "Filters"
|
|
621
|
+
})]
|
|
622
|
+
}) : showFilters ? /*#__PURE__*/_jsxs(ModalHeader, {
|
|
623
|
+
children: [/*#__PURE__*/_jsx(ModalHeader.Navigation, {
|
|
624
|
+
onBack: () => setShowFilters(false)
|
|
625
|
+
}), /*#__PURE__*/_jsx(ModalHeader.Content, {
|
|
626
|
+
title: "Event Filters"
|
|
627
|
+
})]
|
|
628
|
+
}) : selectedConversation ? /*#__PURE__*/_jsxs(ModalHeader, {
|
|
629
|
+
children: [/*#__PURE__*/_jsx(ModalHeader.Navigation, {
|
|
630
|
+
onBack: () => {
|
|
631
|
+
setSelectedConversationKey(null);
|
|
632
|
+
setSelectedEventIndex(0);
|
|
633
|
+
}
|
|
634
|
+
}), /*#__PURE__*/_jsx(ModalHeader.Content, {
|
|
635
|
+
title: selectedConversation.key
|
|
636
|
+
})]
|
|
637
|
+
}) : /*#__PURE__*/_jsxs(ModalHeader, {
|
|
638
|
+
children: [onBack && /*#__PURE__*/_jsx(ModalHeader.Navigation, {
|
|
639
|
+
onBack: onBack
|
|
640
|
+
}), /*#__PURE__*/_jsx(ModalHeader.Content, {
|
|
641
|
+
title: "",
|
|
642
|
+
children: isSearchActive ? /*#__PURE__*/_jsx(SearchBar, {
|
|
643
|
+
value: searchQuery,
|
|
644
|
+
onChange: setSearchQuery,
|
|
645
|
+
onClear: () => {
|
|
646
|
+
setSearchQuery("");
|
|
647
|
+
setIsSearchActive(false);
|
|
648
|
+
},
|
|
649
|
+
placeholder: "Search storage keys...",
|
|
650
|
+
autoFocus: true,
|
|
651
|
+
onSubmitEditing: () => setIsSearchActive(false),
|
|
652
|
+
returnKeyType: "search",
|
|
653
|
+
suggestions: allStorageKeys,
|
|
654
|
+
containerStyle: styles.headerSearchContainer
|
|
655
|
+
}) : /*#__PURE__*/_jsx(TabSelector, {
|
|
656
|
+
tabs: [{
|
|
657
|
+
key: "browser",
|
|
658
|
+
label: "Storage"
|
|
659
|
+
}, {
|
|
660
|
+
key: "events",
|
|
661
|
+
label: `Events${events.length > 0 && activeTab !== "events" ? ` (${events.length})` : ""}`
|
|
662
|
+
}],
|
|
663
|
+
activeTab: activeTab,
|
|
664
|
+
onTabChange: tab => setActiveTab(tab)
|
|
665
|
+
})
|
|
666
|
+
}), /*#__PURE__*/_jsxs(ModalHeader.Actions, {
|
|
667
|
+
children: [activeTab === "browser" && !isSearchActive && /*#__PURE__*/_jsxs(_Fragment, {
|
|
668
|
+
children: [/*#__PURE__*/_jsx(TouchableOpacity, {
|
|
669
|
+
onPress: () => setIsSearchActive(true),
|
|
670
|
+
style: styles.iconButton,
|
|
671
|
+
children: /*#__PURE__*/_jsx(Search, {
|
|
672
|
+
size: 14,
|
|
673
|
+
color: macOSColors.text.secondary
|
|
674
|
+
})
|
|
675
|
+
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
676
|
+
onPress: handleToggleStorageFilters,
|
|
677
|
+
style: [styles.iconButton, storageIgnoredPatterns.size > 0 && styles.activeFilterButton],
|
|
678
|
+
children: /*#__PURE__*/_jsx(Filter, {
|
|
679
|
+
size: 14,
|
|
680
|
+
color: storageIgnoredPatterns.size > 0 ? macOSColors.semantic.debug : macOSColors.text.secondary
|
|
681
|
+
})
|
|
682
|
+
})]
|
|
683
|
+
}), activeTab === "events" && /*#__PURE__*/_jsxs(_Fragment, {
|
|
684
|
+
children: [/*#__PURE__*/_jsx(TouchableOpacity, {
|
|
685
|
+
onPress: handleToggleFilters,
|
|
686
|
+
style: [styles.iconButton, ignoredPatterns.size > 0 && styles.activeFilterButton],
|
|
687
|
+
children: /*#__PURE__*/_jsx(Filter, {
|
|
688
|
+
size: 14,
|
|
689
|
+
color: ignoredPatterns.size > 0 ? macOSColors.semantic.debug : macOSColors.text.secondary
|
|
690
|
+
})
|
|
691
|
+
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
692
|
+
onPress: handleToggleListening,
|
|
693
|
+
style: [styles.iconButton, isListening && styles.activeButton],
|
|
694
|
+
children: isListening ? /*#__PURE__*/_jsx(Pause, {
|
|
695
|
+
size: 14,
|
|
696
|
+
color: macOSColors.semantic.success
|
|
697
|
+
}) : /*#__PURE__*/_jsx(Play, {
|
|
698
|
+
size: 14,
|
|
699
|
+
color: macOSColors.semantic.success
|
|
700
|
+
})
|
|
701
|
+
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
702
|
+
onPress: handleClearEvents,
|
|
703
|
+
style: styles.iconButton,
|
|
704
|
+
children: /*#__PURE__*/_jsx(Trash2, {
|
|
705
|
+
size: 14,
|
|
706
|
+
color: macOSColors.semantic.error
|
|
707
|
+
})
|
|
708
|
+
})]
|
|
709
|
+
})]
|
|
710
|
+
})]
|
|
711
|
+
})
|
|
712
|
+
},
|
|
713
|
+
onModeChange: handleModeChange,
|
|
714
|
+
enablePersistence: true,
|
|
715
|
+
initialMode: "bottomSheet",
|
|
716
|
+
enableGlitchEffects: true,
|
|
717
|
+
styles: {},
|
|
718
|
+
footer: footerNode,
|
|
719
|
+
footerHeight: footerNode ? 68 : 0,
|
|
720
|
+
children: renderContent()
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
const styles = StyleSheet.create({
|
|
724
|
+
headerSearchContainer: {
|
|
725
|
+
flex: 1
|
|
726
|
+
},
|
|
727
|
+
iconButton: {
|
|
728
|
+
width: 32,
|
|
729
|
+
height: 32,
|
|
730
|
+
borderRadius: 8,
|
|
731
|
+
backgroundColor: macOSColors.background.hover,
|
|
732
|
+
borderWidth: 1,
|
|
733
|
+
borderColor: macOSColors.border.default,
|
|
734
|
+
alignItems: "center",
|
|
735
|
+
justifyContent: "center"
|
|
736
|
+
},
|
|
737
|
+
activeButton: {
|
|
738
|
+
backgroundColor: macOSColors.semantic.successBackground
|
|
739
|
+
},
|
|
740
|
+
activeFilterButton: {
|
|
741
|
+
backgroundColor: macOSColors.semantic.infoBackground
|
|
742
|
+
},
|
|
743
|
+
conversationItem: {
|
|
744
|
+
padding: 12,
|
|
745
|
+
backgroundColor: macOSColors.background.card,
|
|
746
|
+
borderRadius: 8,
|
|
747
|
+
marginHorizontal: 16
|
|
748
|
+
},
|
|
749
|
+
conversationHeader: {
|
|
750
|
+
flexDirection: "row",
|
|
751
|
+
justifyContent: "space-between",
|
|
752
|
+
alignItems: "center",
|
|
753
|
+
marginBottom: 8
|
|
754
|
+
},
|
|
755
|
+
keyText: {
|
|
756
|
+
color: macOSColors.text.primary,
|
|
757
|
+
fontSize: 14,
|
|
758
|
+
fontWeight: "600",
|
|
759
|
+
flex: 1,
|
|
760
|
+
marginRight: 8,
|
|
761
|
+
fontFamily: "monospace"
|
|
762
|
+
},
|
|
763
|
+
actionText: {
|
|
764
|
+
fontSize: 11,
|
|
765
|
+
fontWeight: "600",
|
|
766
|
+
fontFamily: "monospace",
|
|
767
|
+
textTransform: "uppercase"
|
|
768
|
+
},
|
|
769
|
+
conversationDetails: {
|
|
770
|
+
flexDirection: "row",
|
|
771
|
+
alignItems: "center",
|
|
772
|
+
gap: 8
|
|
773
|
+
},
|
|
774
|
+
operationCount: {
|
|
775
|
+
color: macOSColors.text.secondary,
|
|
776
|
+
fontSize: 11,
|
|
777
|
+
flex: 1,
|
|
778
|
+
fontFamily: "monospace"
|
|
779
|
+
},
|
|
780
|
+
timestamp: {
|
|
781
|
+
color: macOSColors.text.muted,
|
|
782
|
+
fontSize: 11,
|
|
783
|
+
fontFamily: "monospace"
|
|
784
|
+
},
|
|
785
|
+
separator: {
|
|
786
|
+
height: 8
|
|
787
|
+
},
|
|
788
|
+
listContent: {
|
|
789
|
+
paddingVertical: 16
|
|
790
|
+
},
|
|
791
|
+
lockedBannerContainer: {
|
|
792
|
+
marginTop: 8,
|
|
793
|
+
marginHorizontal: 16
|
|
794
|
+
},
|
|
795
|
+
emptyState: {
|
|
796
|
+
flex: 1,
|
|
797
|
+
justifyContent: "center",
|
|
798
|
+
alignItems: "center",
|
|
799
|
+
padding: 32
|
|
800
|
+
},
|
|
801
|
+
emptyTitle: {
|
|
802
|
+
color: macOSColors.text.primary,
|
|
803
|
+
fontSize: 16,
|
|
804
|
+
fontWeight: "600",
|
|
805
|
+
marginTop: 16,
|
|
806
|
+
marginBottom: 8,
|
|
807
|
+
fontFamily: "monospace",
|
|
808
|
+
letterSpacing: 0.5,
|
|
809
|
+
textTransform: "uppercase"
|
|
810
|
+
},
|
|
811
|
+
emptySubtitle: {
|
|
812
|
+
color: macOSColors.text.secondary,
|
|
813
|
+
fontSize: 14,
|
|
814
|
+
textAlign: "center",
|
|
815
|
+
fontFamily: "monospace"
|
|
816
|
+
},
|
|
817
|
+
eventNavigation: {
|
|
818
|
+
flexDirection: "row",
|
|
819
|
+
alignItems: "center",
|
|
820
|
+
gap: 8,
|
|
821
|
+
paddingHorizontal: 8
|
|
822
|
+
},
|
|
823
|
+
navButton: {
|
|
824
|
+
padding: 4,
|
|
825
|
+
borderRadius: 4
|
|
826
|
+
},
|
|
827
|
+
navButtonDisabled: {
|
|
828
|
+
opacity: 0.3
|
|
829
|
+
},
|
|
830
|
+
eventCounter: {
|
|
831
|
+
color: macOSColors.text.primary,
|
|
832
|
+
fontSize: 12,
|
|
833
|
+
fontWeight: "600",
|
|
834
|
+
fontFamily: "monospace",
|
|
835
|
+
paddingHorizontal: 8
|
|
836
|
+
},
|
|
837
|
+
headerTopRow: {
|
|
838
|
+
flexDirection: "row",
|
|
839
|
+
alignItems: "center",
|
|
840
|
+
gap: 8,
|
|
841
|
+
marginBottom: 12
|
|
842
|
+
},
|
|
843
|
+
keyNameContainer: {
|
|
844
|
+
flex: 1,
|
|
845
|
+
flexDirection: "row",
|
|
846
|
+
alignItems: "center",
|
|
847
|
+
gap: 6,
|
|
848
|
+
backgroundColor: macOSColors.background.input,
|
|
849
|
+
paddingHorizontal: 10,
|
|
850
|
+
paddingVertical: 4,
|
|
851
|
+
borderRadius: 6,
|
|
852
|
+
borderWidth: 1,
|
|
853
|
+
borderColor: macOSColors.border.input,
|
|
854
|
+
height: 28
|
|
855
|
+
},
|
|
856
|
+
keyNameText: {
|
|
857
|
+
flex: 1,
|
|
858
|
+
fontSize: 13,
|
|
859
|
+
fontWeight: "600",
|
|
860
|
+
color: macOSColors.semantic.debug,
|
|
861
|
+
fontFamily: "monospace",
|
|
862
|
+
letterSpacing: 0.5
|
|
863
|
+
},
|
|
864
|
+
contentWrapper: {
|
|
865
|
+
flex: 1
|
|
866
|
+
}
|
|
867
|
+
});
|