@buoy-gg/storage 7.0.3 → 7.0.5
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 +77 -1
- package/lib/commonjs/storage/components/DiffViewer/TreeDiffViewer.js +10 -3
- package/lib/commonjs/storage/components/DiffViewer/modes/ThemedSplitView.js +26 -8
- package/lib/commonjs/storage/components/GameUIStorageBrowser.js +263 -115
- package/lib/commonjs/storage/components/GameUIStorageStats.js +7 -7
- package/lib/commonjs/storage/components/MMKVInstanceInfoPanel.js +1 -1
- package/lib/commonjs/storage/components/MMKVInstanceSelector.js +1 -1
- package/lib/commonjs/storage/components/SelectionActionBar.js +2 -36
- package/lib/commonjs/storage/components/StorageActions.js +6 -6
- package/lib/commonjs/storage/components/StorageBrowserMode.js +16 -2
- package/lib/commonjs/storage/components/StorageEventDetailContent.js +106 -149
- package/lib/commonjs/storage/components/StorageEventListener.js +13 -13
- package/lib/commonjs/storage/components/StorageFilterCards.js +13 -135
- package/lib/commonjs/storage/components/StorageKeyCard.js +1 -1
- package/lib/commonjs/storage/components/StorageKeyEditorScreen.js +392 -0
- package/lib/commonjs/storage/components/StorageKeyRow.js +53 -15
- package/lib/commonjs/storage/components/StorageKeySection.js +10 -4
- package/lib/commonjs/storage/components/StorageKeyStats.js +10 -10
- package/lib/commonjs/storage/components/StorageModalWithTabs.js +272 -129
- package/lib/commonjs/storage/components/StorageScalarKeyEditor.js +46 -0
- package/lib/commonjs/storage/components/StorageTypeFilterBar.js +141 -0
- package/lib/commonjs/storage/components/StorageValueEditModal.js +361 -0
- package/lib/commonjs/storage/hooks/useKeyEditor.js +104 -0
- package/lib/commonjs/storage/hooks/useMeasuredWidth.js +74 -0
- package/lib/commonjs/storage/hooks/useSecureStoreKeys.js +70 -15
- package/lib/commonjs/storage/hooks/useTreeDraft.js +107 -0
- package/lib/commonjs/storage/index.js +29 -0
- package/lib/commonjs/storage/stores/storageEventStore.js +4 -2
- package/lib/commonjs/storage/sync/storageSyncAdapter.js +125 -3
- package/lib/commonjs/storage/utils/AsyncStorageListener.js +76 -12
- package/lib/commonjs/storage/utils/MMKVInstanceRegistry.js +10 -9
- package/lib/commonjs/storage/utils/MMKVListener.js +40 -4
- package/lib/commonjs/storage/utils/SecureStoreRegistry.js +52 -1
- package/lib/commonjs/storage/utils/deleteStorageKeys.js +53 -0
- package/lib/commonjs/storage/utils/index.js +13 -0
- package/lib/commonjs/storage/utils/lineDiff.js +21 -354
- package/lib/commonjs/storage/utils/setStorageValue.js +218 -0
- package/lib/commonjs/storage/utils/storageBrowserRefresh.js +49 -0
- package/lib/commonjs/storage/utils/storageOps.js +53 -0
- package/lib/commonjs/storage/utils/storageTimeTravelUtils.js +60 -38
- package/lib/commonjs/storage/utils/valueType.js +24 -0
- package/lib/module/index.js +18 -1
- package/lib/module/storage/components/DiffViewer/TreeDiffViewer.js +10 -3
- package/lib/module/storage/components/DiffViewer/modes/ThemedSplitView.js +26 -8
- package/lib/module/storage/components/GameUIStorageBrowser.js +266 -118
- package/lib/module/storage/components/GameUIStorageStats.js +7 -7
- package/lib/module/storage/components/MMKVInstanceInfoPanel.js +1 -1
- package/lib/module/storage/components/MMKVInstanceSelector.js +1 -1
- package/lib/module/storage/components/SelectionActionBar.js +2 -36
- package/lib/module/storage/components/StorageActions.js +7 -7
- package/lib/module/storage/components/StorageBrowserMode.js +16 -2
- package/lib/module/storage/components/StorageEventDetailContent.js +110 -151
- package/lib/module/storage/components/StorageEventListener.js +14 -14
- package/lib/module/storage/components/StorageFilterCards.js +13 -135
- package/lib/module/storage/components/StorageKeyCard.js +1 -1
- package/lib/module/storage/components/StorageKeyEditorScreen.js +388 -0
- package/lib/module/storage/components/StorageKeyRow.js +55 -17
- package/lib/module/storage/components/StorageKeySection.js +11 -5
- package/lib/module/storage/components/StorageKeyStats.js +11 -10
- package/lib/module/storage/components/StorageModalWithTabs.js +272 -130
- package/lib/module/storage/components/StorageScalarKeyEditor.js +42 -0
- package/lib/module/storage/components/StorageTypeFilterBar.js +136 -0
- package/lib/module/storage/components/StorageValueEditModal.js +357 -0
- package/lib/module/storage/hooks/useKeyEditor.js +100 -0
- package/lib/module/storage/hooks/useMeasuredWidth.js +71 -0
- package/lib/module/storage/hooks/useSecureStoreKeys.js +71 -16
- package/lib/module/storage/hooks/useTreeDraft.js +103 -0
- package/lib/module/storage/index.js +3 -0
- package/lib/module/storage/stores/storageEventStore.js +4 -2
- package/lib/module/storage/sync/storageSyncAdapter.js +125 -3
- package/lib/module/storage/utils/AsyncStorageListener.js +76 -12
- package/lib/module/storage/utils/MMKVInstanceRegistry.js +8 -7
- package/lib/module/storage/utils/MMKVListener.js +40 -4
- package/lib/module/storage/utils/SecureStoreRegistry.js +52 -1
- package/lib/module/storage/utils/deleteStorageKeys.js +49 -0
- package/lib/module/storage/utils/index.js +3 -0
- package/lib/module/storage/utils/lineDiff.js +7 -354
- package/lib/module/storage/utils/setStorageValue.js +209 -0
- package/lib/module/storage/utils/storageBrowserRefresh.js +44 -0
- package/lib/module/storage/utils/storageOps.js +46 -0
- package/lib/module/storage/utils/storageTimeTravelUtils.js +61 -40
- package/lib/module/storage/utils/valueType.js +23 -0
- package/lib/typescript/index.d.ts +12 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts +4 -1
- package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts.map +1 -1
- package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts +7 -1
- package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts.map +1 -1
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts +27 -1
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts.map +1 -1
- package/lib/typescript/storage/components/SelectionActionBar.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageBrowserMode.d.ts +17 -1
- package/lib/typescript/storage/components/StorageBrowserMode.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageEventDetailContent.d.ts +4 -1
- package/lib/typescript/storage/components/StorageEventDetailContent.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageFilterCards.d.ts +9 -3
- package/lib/typescript/storage/components/StorageFilterCards.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageKeyEditorScreen.d.ts +42 -0
- package/lib/typescript/storage/components/StorageKeyEditorScreen.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageKeyRow.d.ts +17 -0
- package/lib/typescript/storage/components/StorageKeyRow.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageKeySection.d.ts +7 -1
- package/lib/typescript/storage/components/StorageKeySection.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageKeyStats.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts +28 -1
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageScalarKeyEditor.d.ts +24 -0
- package/lib/typescript/storage/components/StorageScalarKeyEditor.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageTypeFilterBar.d.ts +29 -0
- package/lib/typescript/storage/components/StorageTypeFilterBar.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageValueEditModal.d.ts +36 -0
- package/lib/typescript/storage/components/StorageValueEditModal.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useKeyEditor.d.ts +51 -0
- package/lib/typescript/storage/hooks/useKeyEditor.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useMeasuredWidth.d.ts +37 -0
- package/lib/typescript/storage/hooks/useMeasuredWidth.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useSecureStoreKeys.d.ts +8 -1
- package/lib/typescript/storage/hooks/useSecureStoreKeys.d.ts.map +1 -1
- package/lib/typescript/storage/hooks/useTreeDraft.d.ts +67 -0
- package/lib/typescript/storage/hooks/useTreeDraft.d.ts.map +1 -0
- package/lib/typescript/storage/index.d.ts +2 -0
- package/lib/typescript/storage/index.d.ts.map +1 -1
- package/lib/typescript/storage/sync/storageSyncAdapter.d.ts +41 -0
- package/lib/typescript/storage/sync/storageSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts +15 -0
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts.map +1 -1
- package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts.map +1 -1
- package/lib/typescript/storage/utils/MMKVListener.d.ts +7 -0
- package/lib/typescript/storage/utils/MMKVListener.d.ts.map +1 -1
- package/lib/typescript/storage/utils/SecureStoreRegistry.d.ts +20 -0
- package/lib/typescript/storage/utils/SecureStoreRegistry.d.ts.map +1 -1
- package/lib/typescript/storage/utils/deleteStorageKeys.d.ts +27 -0
- package/lib/typescript/storage/utils/deleteStorageKeys.d.ts.map +1 -0
- package/lib/typescript/storage/utils/index.d.ts +1 -0
- package/lib/typescript/storage/utils/index.d.ts.map +1 -1
- package/lib/typescript/storage/utils/lineDiff.d.ts +7 -31
- package/lib/typescript/storage/utils/lineDiff.d.ts.map +1 -1
- package/lib/typescript/storage/utils/setStorageValue.d.ts +64 -0
- package/lib/typescript/storage/utils/setStorageValue.d.ts.map +1 -0
- package/lib/typescript/storage/utils/storageBrowserRefresh.d.ts +28 -0
- package/lib/typescript/storage/utils/storageBrowserRefresh.d.ts.map +1 -0
- package/lib/typescript/storage/utils/storageOps.d.ts +25 -0
- package/lib/typescript/storage/utils/storageOps.d.ts.map +1 -0
- package/lib/typescript/storage/utils/storageTimeTravelUtils.d.ts +15 -5
- package/lib/typescript/storage/utils/storageTimeTravelUtils.d.ts.map +1 -1
- package/lib/typescript/storage/utils/valueType.d.ts +13 -0
- package/lib/typescript/storage/utils/valueType.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { View, Text, TouchableOpacity, StyleSheet, Alert } from "react-native";
|
|
4
4
|
import { useState, useCallback, useEffect } from "react";
|
|
5
5
|
import { clearAllStorageIncludingDevTools } from "../utils/clearAllStorage";
|
|
6
|
-
import { RefreshCw, Trash2, CopyButton, ProUpgradeModal } from "@buoy-gg/shared-ui";
|
|
6
|
+
import { RefreshCw, Trash2, CopyButton, ProUpgradeModal, buoyColors } from "@buoy-gg/shared-ui";
|
|
7
7
|
import { useIsPro } from "@buoy-gg/license";
|
|
8
8
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
9
9
|
export function StorageActions({
|
|
@@ -89,7 +89,7 @@ export function StorageActions({
|
|
|
89
89
|
accessibilityLabel: "Refresh storage",
|
|
90
90
|
children: /*#__PURE__*/_jsx(RefreshCw, {
|
|
91
91
|
size: 16,
|
|
92
|
-
color: isRefreshing ? "#10B981" :
|
|
92
|
+
color: isRefreshing ? "#10B981" : buoyColors.textSecondary
|
|
93
93
|
})
|
|
94
94
|
}), /*#__PURE__*/_jsx(CopyButton, {
|
|
95
95
|
value: storageKeys,
|
|
@@ -125,11 +125,11 @@ const styles = StyleSheet.create({
|
|
|
125
125
|
justifyContent: "space-between",
|
|
126
126
|
paddingHorizontal: 12,
|
|
127
127
|
paddingVertical: 8,
|
|
128
|
-
backgroundColor: "rgba(
|
|
128
|
+
backgroundColor: "rgba(128, 128, 128, 0.06)",
|
|
129
129
|
borderRadius: 8,
|
|
130
130
|
marginBottom: 12,
|
|
131
131
|
borderWidth: 1,
|
|
132
|
-
borderColor: "rgba(
|
|
132
|
+
borderColor: "rgba(128, 128, 128, 0.16)"
|
|
133
133
|
},
|
|
134
134
|
leftSection: {
|
|
135
135
|
flexDirection: "row",
|
|
@@ -137,7 +137,7 @@ const styles = StyleSheet.create({
|
|
|
137
137
|
gap: 8
|
|
138
138
|
},
|
|
139
139
|
keyCount: {
|
|
140
|
-
color:
|
|
140
|
+
color: buoyColors.textSecondary,
|
|
141
141
|
fontSize: 12,
|
|
142
142
|
fontWeight: "500"
|
|
143
143
|
},
|
|
@@ -161,9 +161,9 @@ const styles = StyleSheet.create({
|
|
|
161
161
|
width: 32,
|
|
162
162
|
height: 32,
|
|
163
163
|
borderRadius: 6,
|
|
164
|
-
backgroundColor: "rgba(
|
|
164
|
+
backgroundColor: "rgba(128, 128, 128, 0.06)",
|
|
165
165
|
borderWidth: 1,
|
|
166
|
-
borderColor: "rgba(
|
|
166
|
+
borderColor: "rgba(128, 128, 128, 0.16)",
|
|
167
167
|
alignItems: "center",
|
|
168
168
|
justifyContent: "center"
|
|
169
169
|
},
|
|
@@ -15,10 +15,17 @@ export function StorageBrowserMode({
|
|
|
15
15
|
searchQuery = "",
|
|
16
16
|
storageDataRef,
|
|
17
17
|
eventCountByKey,
|
|
18
|
+
lastWriteByKey,
|
|
18
19
|
onViewHistory,
|
|
19
20
|
enabledStorageTypes,
|
|
21
|
+
statusFilter,
|
|
22
|
+
onStatusFilterChange,
|
|
23
|
+
onStatusCountsChange,
|
|
20
24
|
pinnedKeys,
|
|
21
|
-
onTogglePin
|
|
25
|
+
onTogglePin,
|
|
26
|
+
applySafeAreaInset,
|
|
27
|
+
storageTypeFilter,
|
|
28
|
+
onStorageTypeFilterChange
|
|
22
29
|
}) {
|
|
23
30
|
return /*#__PURE__*/_jsx(GameUIStorageBrowser, {
|
|
24
31
|
requiredStorageKeys: requiredStorageKeys,
|
|
@@ -29,9 +36,16 @@ export function StorageBrowserMode({
|
|
|
29
36
|
searchQuery: searchQuery,
|
|
30
37
|
storageDataRef: storageDataRef,
|
|
31
38
|
eventCountByKey: eventCountByKey,
|
|
39
|
+
lastWriteByKey: lastWriteByKey,
|
|
32
40
|
onViewHistory: onViewHistory,
|
|
33
41
|
enabledStorageTypes: enabledStorageTypes,
|
|
42
|
+
statusFilter: statusFilter,
|
|
43
|
+
onStatusFilterChange: onStatusFilterChange,
|
|
44
|
+
onStatusCountsChange: onStatusCountsChange,
|
|
34
45
|
pinnedKeys: pinnedKeys,
|
|
35
|
-
onTogglePin: onTogglePin
|
|
46
|
+
onTogglePin: onTogglePin,
|
|
47
|
+
applySafeAreaInset: applySafeAreaInset,
|
|
48
|
+
storageTypeFilter: storageTypeFilter,
|
|
49
|
+
onStorageTypeFilterChange: onStorageTypeFilterChange
|
|
36
50
|
});
|
|
37
51
|
}
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
import { View, Text, StyleSheet } from "react-native";
|
|
10
10
|
import { useState, useCallback, useMemo, useEffect, useRef } from "react";
|
|
11
11
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
12
|
-
import { formatRelativeTime, macOSColors, buoyColors, parseValue, devToolsStorageKeys,
|
|
12
|
+
import { formatRelativeTime, macOSColors, buoyColors, parseValue, devToolsStorageKeys, GitBranch, EventStepperFooter, EventHistoryViewer, copyToClipboard, ProUpgradeModal } from "@buoy-gg/shared-ui";
|
|
13
13
|
import { useIsPro } from "@buoy-gg/license";
|
|
14
|
-
import {
|
|
14
|
+
import { ABSENT_VALUE } from "../utils/lineDiff";
|
|
15
15
|
import { ThemedSplitView } from "./DiffViewer/modes/ThemedSplitView";
|
|
16
16
|
import { diffThemes } from "./DiffViewer/themes/diffThemes";
|
|
17
17
|
import { TreeDiffViewer } from "./DiffViewer/TreeDiffViewer";
|
|
@@ -19,8 +19,40 @@ import { translateStorageAction } from "../utils/storageActionHelpers";
|
|
|
19
19
|
import { StorageEventActionButton } from "./StorageEventActionButton";
|
|
20
20
|
import { undoOperation, jumpToState, canUndo } from "../utils/storageTimeTravelUtils";
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Compare-bar index for "the state before the oldest event".
|
|
24
|
+
*
|
|
25
|
+
* Not an event — it's reconstructed from that event's own `prevValue`, which
|
|
26
|
+
* every write records. Without it a key's first event had nothing to diff
|
|
27
|
+
* against and both panes showed the same value.
|
|
28
|
+
*/
|
|
23
29
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
30
|
+
const ORIGIN_INDEX = -1;
|
|
31
|
+
|
|
32
|
+
/** Compare-bar copy for each origin state. Kept in sync with the Flutter port. */
|
|
33
|
+
const ORIGIN_LABELS = {
|
|
34
|
+
prior: {
|
|
35
|
+
label: "BEFORE #1",
|
|
36
|
+
timestamp: "value before first event",
|
|
37
|
+
relativeTime: "not captured",
|
|
38
|
+
badge: "PRIOR"
|
|
39
|
+
},
|
|
40
|
+
absent: {
|
|
41
|
+
label: "NO PRIOR VALUE",
|
|
42
|
+
timestamp: "key did not exist",
|
|
43
|
+
relativeTime: "created here",
|
|
44
|
+
badge: "ABSENT"
|
|
45
|
+
},
|
|
46
|
+
scanned: {
|
|
47
|
+
label: "ALREADY PRESENT",
|
|
48
|
+
timestamp: "value found at startup",
|
|
49
|
+
relativeTime: "not a write",
|
|
50
|
+
badge: "SCANNED"
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Unified storage event type (supports both AsyncStorage and MMKV)
|
|
55
|
+
|
|
24
56
|
/**
|
|
25
57
|
* Get color for storage action
|
|
26
58
|
*/
|
|
@@ -80,12 +112,16 @@ export function StorageEventDetailContent({
|
|
|
80
112
|
const isPro = useIsPro();
|
|
81
113
|
const [showProModal, setShowProModal] = useState(false);
|
|
82
114
|
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
115
|
+
// There is only the diff view now. The current stored value is what the Keys
|
|
116
|
+
// table shows — repeating it behind a toggle here meant two places to look for
|
|
117
|
+
// one fact, and the toggle was the first thing between you and the diff you
|
|
118
|
+
// opened this screen for.
|
|
119
|
+
const [diffMode, setDiffMode] = useState("split");
|
|
86
120
|
|
|
87
121
|
// Compare indices for diff view
|
|
88
|
-
|
|
122
|
+
// Matches what the sync effect below computes, so the first frame doesn't
|
|
123
|
+
// briefly pair the oldest event with itself.
|
|
124
|
+
const [leftIndex, setLeftIndex] = useState(Math.max(ORIGIN_INDEX, selectedEventIndex - 1));
|
|
89
125
|
const [rightIndex, setRightIndex] = useState(selectedEventIndex);
|
|
90
126
|
|
|
91
127
|
// Track if preferences have been loaded
|
|
@@ -100,10 +136,6 @@ export function StorageEventDetailContent({
|
|
|
100
136
|
if (hasLoadedPreferences.current) return;
|
|
101
137
|
const loadPreferences = async () => {
|
|
102
138
|
try {
|
|
103
|
-
const savedDetailView = await AsyncStorage.getItem(devToolsStorageKeys.storage.detailView());
|
|
104
|
-
if (savedDetailView === "current" || savedDetailView === "diff") {
|
|
105
|
-
setActiveView(savedDetailView);
|
|
106
|
-
}
|
|
107
139
|
const savedDiffMode = await AsyncStorage.getItem(devToolsStorageKeys.storage.diffViewerMode());
|
|
108
140
|
if (savedDiffMode === "split" || savedDiffMode === "tree") {
|
|
109
141
|
setDiffMode(savedDiffMode);
|
|
@@ -116,24 +148,15 @@ export function StorageEventDetailContent({
|
|
|
116
148
|
loadPreferences();
|
|
117
149
|
}, []);
|
|
118
150
|
|
|
119
|
-
// Keep compare indices synced to selection
|
|
151
|
+
// Keep compare indices synced to selection. Left may land on ORIGIN_INDEX,
|
|
152
|
+
// which is not an event — it's the state the oldest event overwrote.
|
|
120
153
|
useEffect(() => {
|
|
121
154
|
const newRight = Math.min(totalEvents - 1, Math.max(0, selectedEventIndex));
|
|
122
|
-
const newLeft = Math.max(
|
|
155
|
+
const newLeft = Math.max(ORIGIN_INDEX, Math.min(newRight - 1, selectedEventIndex - 1));
|
|
123
156
|
setLeftIndex(newLeft);
|
|
124
157
|
setRightIndex(newRight);
|
|
125
158
|
}, [selectedEventIndex, totalEvents]);
|
|
126
159
|
|
|
127
|
-
// Save view preference when changed
|
|
128
|
-
const handleViewChange = useCallback(async view => {
|
|
129
|
-
setActiveView(view);
|
|
130
|
-
try {
|
|
131
|
-
await AsyncStorage.setItem(devToolsStorageKeys.storage.detailView(), view);
|
|
132
|
-
} catch {
|
|
133
|
-
// Failed to save preference
|
|
134
|
-
}
|
|
135
|
-
}, []);
|
|
136
|
-
|
|
137
160
|
// Save diff mode preference when changed
|
|
138
161
|
const handleDiffModeChange = useCallback(async mode => {
|
|
139
162
|
setDiffMode(mode);
|
|
@@ -146,18 +169,53 @@ export function StorageEventDetailContent({
|
|
|
146
169
|
|
|
147
170
|
// Get current event
|
|
148
171
|
const selectedEvent = navigationItems[selectedEventIndex];
|
|
149
|
-
const valueToShow = selectedEvent?.data?.value ?? conversation.currentValue;
|
|
150
172
|
const action = selectedEvent?.action;
|
|
151
173
|
// Compute type from the parsed value so it matches what we actually render
|
|
152
|
-
const valueType = getValueType(parseValue(valueToShow));
|
|
153
|
-
const actionColor = getActionColor(action || "");
|
|
154
174
|
|
|
155
|
-
// Get events for diff comparison
|
|
156
|
-
|
|
175
|
+
// Get events for diff comparison. leftIndex === ORIGIN_INDEX means "the state
|
|
176
|
+
// before the oldest event", which has no event object of its own.
|
|
177
|
+
const isOriginLeft = leftIndex === ORIGIN_INDEX;
|
|
178
|
+
const leftEvent = isOriginLeft ? undefined : navigationItems[Math.max(0, Math.min(totalEvents - 1, leftIndex))];
|
|
157
179
|
const rightEvent = navigationItems[Math.max(0, Math.min(totalEvents - 1, rightIndex))];
|
|
158
180
|
|
|
181
|
+
// Every write records the value it overwrote (for time travel), so even the
|
|
182
|
+
// very first event can be diffed against what was actually there. Three
|
|
183
|
+
// distinct origins, and conflating them would misinform:
|
|
184
|
+
// PRIOR — the write replaced a real value (including `[]`, `""`, `null`)
|
|
185
|
+
// ABSENT — the write created the key; there was nothing before it
|
|
186
|
+
// SCANNED — not a write at all, just the startup snapshot of a key that
|
|
187
|
+
// already existed, so nothing changed at this event
|
|
188
|
+
const originKind = useMemo(() => {
|
|
189
|
+
const data = rightEvent?.data;
|
|
190
|
+
if (data?.initialScan) return "scanned";
|
|
191
|
+
return data?.prevValue === null || data?.prevValue === undefined ? "absent" : "prior";
|
|
192
|
+
}, [rightEvent]);
|
|
193
|
+
const originValue = useMemo(() => {
|
|
194
|
+
if (originKind === "absent") return ABSENT_VALUE;
|
|
195
|
+
// A scanned key was already holding the event's own value, so diffing
|
|
196
|
+
// against it correctly reports no change.
|
|
197
|
+
if (originKind === "scanned") return parseValue(rightEvent?.data?.value);
|
|
198
|
+
return parseValue(rightEvent?.data?.prevValue);
|
|
199
|
+
}, [originKind, rightEvent]);
|
|
200
|
+
|
|
159
201
|
// Create event display info for compare bar
|
|
160
|
-
const leftEventInfo = useMemo(() =>
|
|
202
|
+
const leftEventInfo = useMemo(() => isOriginLeft ? {
|
|
203
|
+
index: ORIGIN_INDEX,
|
|
204
|
+
label: ORIGIN_LABELS[originKind].label,
|
|
205
|
+
timestamp: ORIGIN_LABELS[originKind].timestamp,
|
|
206
|
+
relativeTime: ORIGIN_LABELS[originKind].relativeTime,
|
|
207
|
+
badge: /*#__PURE__*/_jsx(View, {
|
|
208
|
+
style: [styles.actionBadgeSmall, {
|
|
209
|
+
backgroundColor: `${macOSColors.text.muted}20`
|
|
210
|
+
}],
|
|
211
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
212
|
+
style: [styles.actionTextSmall, {
|
|
213
|
+
color: macOSColors.text.muted
|
|
214
|
+
}],
|
|
215
|
+
children: ORIGIN_LABELS[originKind].badge
|
|
216
|
+
})
|
|
217
|
+
})
|
|
218
|
+
} : {
|
|
161
219
|
index: leftIndex,
|
|
162
220
|
label: `#${leftIndex + 1} / ${totalEvents}`,
|
|
163
221
|
timestamp: leftEvent ? formatTimeWithMs(leftEvent.timestamp) : "",
|
|
@@ -173,7 +231,7 @@ export function StorageEventDetailContent({
|
|
|
173
231
|
children: translateStorageAction(leftEvent.action)
|
|
174
232
|
})
|
|
175
233
|
}) : undefined
|
|
176
|
-
}
|
|
234
|
+
}, [leftIndex, leftEvent, totalEvents, isOriginLeft, originKind]);
|
|
177
235
|
const rightEventInfo = useMemo(() => ({
|
|
178
236
|
index: rightIndex,
|
|
179
237
|
label: `#${rightIndex + 1} / ${totalEvents}`,
|
|
@@ -203,7 +261,8 @@ export function StorageEventDetailContent({
|
|
|
203
261
|
|
|
204
262
|
// Navigation handlers for compare bar
|
|
205
263
|
const handleLeftPrevious = useCallback(() => {
|
|
206
|
-
|
|
264
|
+
// Stops at ORIGIN_INDEX — one step past event #1 is the state it overwrote.
|
|
265
|
+
if (leftIndex > ORIGIN_INDEX) {
|
|
207
266
|
setLeftIndex(leftIndex - 1);
|
|
208
267
|
}
|
|
209
268
|
}, [leftIndex]);
|
|
@@ -223,54 +282,11 @@ export function StorageEventDetailContent({
|
|
|
223
282
|
}
|
|
224
283
|
}, [rightIndex, totalEvents]);
|
|
225
284
|
|
|
226
|
-
// Render current value view
|
|
227
|
-
const renderCurrentView = useCallback(() => {
|
|
228
|
-
const parsed = parseValue(valueToShow);
|
|
229
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
230
|
-
style: styles.contentCard,
|
|
231
|
-
children: [/*#__PURE__*/_jsxs(View, {
|
|
232
|
-
style: styles.valueHeader,
|
|
233
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
234
|
-
style: styles.valueLabel,
|
|
235
|
-
children: "CURRENT VALUE"
|
|
236
|
-
}), /*#__PURE__*/_jsxs(View, {
|
|
237
|
-
style: styles.valueHeaderBadges,
|
|
238
|
-
children: [action ? /*#__PURE__*/_jsx(View, {
|
|
239
|
-
style: [styles.actionBadge, {
|
|
240
|
-
backgroundColor: `${actionColor}20`
|
|
241
|
-
}],
|
|
242
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
243
|
-
style: [styles.actionText, {
|
|
244
|
-
color: actionColor
|
|
245
|
-
}],
|
|
246
|
-
children: translateStorageAction(action)
|
|
247
|
-
})
|
|
248
|
-
}) : null, /*#__PURE__*/_jsx(View, {
|
|
249
|
-
style: styles.typeBadge,
|
|
250
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
251
|
-
style: styles.typeText,
|
|
252
|
-
children: valueType.toUpperCase()
|
|
253
|
-
})
|
|
254
|
-
})]
|
|
255
|
-
})]
|
|
256
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
257
|
-
style: styles.dataViewerContainer,
|
|
258
|
-
children: /*#__PURE__*/_jsx(DataViewer, {
|
|
259
|
-
title: "",
|
|
260
|
-
data: parsed,
|
|
261
|
-
showTypeFilter: true,
|
|
262
|
-
rawMode: true,
|
|
263
|
-
initialExpanded: true
|
|
264
|
-
})
|
|
265
|
-
})]
|
|
266
|
-
});
|
|
267
|
-
}, [valueToShow, action, actionColor, valueType]);
|
|
268
|
-
|
|
269
285
|
// Memoized so the diff viewers don't see new oldValue/newValue refs on every
|
|
270
286
|
// re-render. parseValue runs JSON.parse, which would otherwise produce fresh
|
|
271
287
|
// object identities every time and force expensive recomputations downstream
|
|
272
288
|
// (line diff, tree diff, expansion-state effects, etc.).
|
|
273
|
-
const previousValue = useMemo(() => parseValue(leftEvent?.data?.value ?? null), [leftEvent]);
|
|
289
|
+
const previousValue = useMemo(() => isOriginLeft ? originValue : parseValue(leftEvent?.data?.value ?? null), [isOriginLeft, originValue, leftEvent]);
|
|
274
290
|
const currentValue = useMemo(() => parseValue(rightEvent?.data?.value), [rightEvent]);
|
|
275
291
|
|
|
276
292
|
// Render diff content
|
|
@@ -282,12 +298,17 @@ export function StorageEventDetailContent({
|
|
|
282
298
|
differences: SPLIT_VIEW_DIFFERENCES,
|
|
283
299
|
theme: diffThemes.devToolsDefault,
|
|
284
300
|
options: SPLIT_VIEW_OPTIONS,
|
|
285
|
-
showThemeName: false
|
|
301
|
+
showThemeName: false,
|
|
302
|
+
scrollEnabled: false
|
|
286
303
|
});
|
|
287
304
|
}
|
|
305
|
+
|
|
306
|
+
// Inline: the whole diff section scrolls as one page (see
|
|
307
|
+
// `scrollDiffSection` below), so the tree must not scroll itself.
|
|
288
308
|
return /*#__PURE__*/_jsx(TreeDiffViewer, {
|
|
289
309
|
oldValue: previousValue,
|
|
290
|
-
newValue: currentValue
|
|
310
|
+
newValue: currentValue,
|
|
311
|
+
scrollEnabled: false
|
|
291
312
|
});
|
|
292
313
|
}, [previousValue, currentValue, diffMode]);
|
|
293
314
|
|
|
@@ -360,25 +381,23 @@ export function StorageEventDetailContent({
|
|
|
360
381
|
onPress: handleCopy
|
|
361
382
|
})]
|
|
362
383
|
}), /*#__PURE__*/_jsx(EventHistoryViewer
|
|
363
|
-
//
|
|
384
|
+
// Diff only: no `renderCurrentView`, so the viewer drops the toggle
|
|
385
|
+
// cards entirely rather than showing a one-option switch.
|
|
364
386
|
, {
|
|
365
|
-
activeView:
|
|
366
|
-
onViewChange: handleViewChange,
|
|
367
|
-
currentViewLabel: "CURRENT VALUE",
|
|
368
|
-
currentViewDescription: "View the current stored value",
|
|
369
|
-
currentViewIcon: Database,
|
|
387
|
+
activeView: "diff",
|
|
370
388
|
diffViewLabel: "DIFF VIEW",
|
|
371
389
|
diffViewDescription: "Compare changes between versions",
|
|
372
390
|
diffViewIcon: GitBranch
|
|
373
|
-
// Current View
|
|
374
|
-
,
|
|
375
|
-
renderCurrentView: renderCurrentView
|
|
376
391
|
// Diff View
|
|
377
392
|
,
|
|
378
393
|
diffModeTabs: diffModeTabs,
|
|
379
394
|
activeDiffMode: diffMode,
|
|
380
395
|
onDiffModeChange: handleDiffModeChange,
|
|
381
396
|
renderDiffContent: renderDiffContent
|
|
397
|
+
// Both diff modes render inline now, so the whole section scrolls as
|
|
398
|
+
// one page rather than confining the rows to a nested pane.
|
|
399
|
+
,
|
|
400
|
+
scrollDiffSection: true
|
|
382
401
|
// Compare Bar
|
|
383
402
|
,
|
|
384
403
|
leftEvent: leftEventInfo,
|
|
@@ -388,7 +407,7 @@ export function StorageEventDetailContent({
|
|
|
388
407
|
onLeftNext: handleLeftNext,
|
|
389
408
|
onRightPrevious: handleRightPrevious,
|
|
390
409
|
onRightNext: handleRightNext,
|
|
391
|
-
canLeftPrevious: leftIndex >
|
|
410
|
+
canLeftPrevious: leftIndex > ORIGIN_INDEX,
|
|
392
411
|
canLeftNext: leftIndex < rightIndex - 1,
|
|
393
412
|
canRightPrevious: rightIndex > leftIndex + 1,
|
|
394
413
|
canRightNext: rightIndex < totalEvents - 1
|
|
@@ -415,7 +434,8 @@ export function StorageEventDetailContent({
|
|
|
415
434
|
export function StorageEventDetailFooter({
|
|
416
435
|
conversation,
|
|
417
436
|
selectedEventIndex = 0,
|
|
418
|
-
onEventIndexChange = () => {}
|
|
437
|
+
onEventIndexChange = () => {},
|
|
438
|
+
applySafeAreaInset = true
|
|
419
439
|
}) {
|
|
420
440
|
const navigationItems = conversation.events.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
421
441
|
const totalEvents = navigationItems.length;
|
|
@@ -425,7 +445,8 @@ export function StorageEventDetailFooter({
|
|
|
425
445
|
onPrevious: () => onEventIndexChange(Math.max(0, selectedEventIndex - 1)),
|
|
426
446
|
onNext: () => onEventIndexChange(Math.min(totalEvents - 1, selectedEventIndex + 1)),
|
|
427
447
|
itemLabel: "Event",
|
|
428
|
-
subtitle: formatRelativeTime(navigationItems[selectedEventIndex]?.timestamp)
|
|
448
|
+
subtitle: formatRelativeTime(navigationItems[selectedEventIndex]?.timestamp),
|
|
449
|
+
applySafeAreaInset: applySafeAreaInset
|
|
429
450
|
});
|
|
430
451
|
}
|
|
431
452
|
const styles = StyleSheet.create({
|
|
@@ -442,63 +463,6 @@ const styles = StyleSheet.create({
|
|
|
442
463
|
borderBottomColor: buoyColors.border
|
|
443
464
|
},
|
|
444
465
|
// Content Card
|
|
445
|
-
contentCard: {
|
|
446
|
-
backgroundColor: macOSColors.background.card,
|
|
447
|
-
borderRadius: 14,
|
|
448
|
-
padding: 14,
|
|
449
|
-
borderWidth: 1,
|
|
450
|
-
borderColor: macOSColors.border.default,
|
|
451
|
-
shadowColor: macOSColors.semantic.info,
|
|
452
|
-
shadowOffset: {
|
|
453
|
-
width: 0,
|
|
454
|
-
height: 2
|
|
455
|
-
},
|
|
456
|
-
shadowOpacity: 0.04,
|
|
457
|
-
shadowRadius: 16,
|
|
458
|
-
elevation: 2
|
|
459
|
-
},
|
|
460
|
-
valueHeader: {
|
|
461
|
-
flexDirection: "row",
|
|
462
|
-
alignItems: "center",
|
|
463
|
-
justifyContent: "space-between",
|
|
464
|
-
marginBottom: 8
|
|
465
|
-
},
|
|
466
|
-
valueLabel: {
|
|
467
|
-
fontSize: 10,
|
|
468
|
-
color: macOSColors.text.secondary,
|
|
469
|
-
fontFamily: "monospace",
|
|
470
|
-
letterSpacing: 0.5,
|
|
471
|
-
fontWeight: "600",
|
|
472
|
-
textTransform: "uppercase"
|
|
473
|
-
},
|
|
474
|
-
valueHeaderBadges: {
|
|
475
|
-
flexDirection: "row",
|
|
476
|
-
alignItems: "center",
|
|
477
|
-
gap: 6
|
|
478
|
-
},
|
|
479
|
-
actionBadge: {
|
|
480
|
-
paddingHorizontal: 8,
|
|
481
|
-
paddingVertical: 2,
|
|
482
|
-
borderRadius: 4
|
|
483
|
-
},
|
|
484
|
-
actionText: {
|
|
485
|
-
fontSize: 9,
|
|
486
|
-
fontWeight: "700",
|
|
487
|
-
fontFamily: "monospace",
|
|
488
|
-
letterSpacing: 0.3
|
|
489
|
-
},
|
|
490
|
-
typeBadge: {
|
|
491
|
-
paddingHorizontal: 8,
|
|
492
|
-
paddingVertical: 2,
|
|
493
|
-
borderRadius: 4,
|
|
494
|
-
backgroundColor: macOSColors.background.input
|
|
495
|
-
},
|
|
496
|
-
typeText: {
|
|
497
|
-
fontSize: 9,
|
|
498
|
-
fontWeight: "600",
|
|
499
|
-
color: macOSColors.text.muted,
|
|
500
|
-
fontFamily: "monospace"
|
|
501
|
-
},
|
|
502
466
|
valueBox: {
|
|
503
467
|
backgroundColor: macOSColors.background.base,
|
|
504
468
|
borderRadius: 6,
|
|
@@ -522,10 +486,5 @@ const styles = StyleSheet.create({
|
|
|
522
486
|
fontSize: 8,
|
|
523
487
|
fontWeight: "700",
|
|
524
488
|
fontFamily: "monospace"
|
|
525
|
-
},
|
|
526
|
-
dataViewerContainer: {
|
|
527
|
-
marginTop: -12,
|
|
528
|
-
marginHorizontal: -12,
|
|
529
|
-
marginBottom: -12
|
|
530
489
|
}
|
|
531
490
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect, useState, useCallback } from "react";
|
|
4
4
|
import { View, Text, StyleSheet, TouchableOpacity, ScrollView } from "react-native";
|
|
5
|
-
import { Play, Pause, Trash2 } from "@buoy-gg/shared-ui";
|
|
5
|
+
import { Play, Pause, Trash2, macOSColors, buoyColors } from "@buoy-gg/shared-ui";
|
|
6
6
|
import { startListening, stopListening, addListener, isListening as checkIsListening } from "../utils/AsyncStorageListener";
|
|
7
7
|
import { translateStorageAction } from "../utils/storageActionHelpers";
|
|
8
8
|
import { isMMKVAvailable } from "../utils/mmkvAvailability";
|
|
@@ -149,7 +149,7 @@ export function StorageEventListener() {
|
|
|
149
149
|
return "#3B82F6";
|
|
150
150
|
// Blue for merge
|
|
151
151
|
default:
|
|
152
|
-
return
|
|
152
|
+
return macOSColors.text.icon;
|
|
153
153
|
}
|
|
154
154
|
};
|
|
155
155
|
if (!isAsyncStorageAvailable) {
|
|
@@ -195,7 +195,7 @@ export function StorageEventListener() {
|
|
|
195
195
|
disabled: events.length === 0,
|
|
196
196
|
children: /*#__PURE__*/_jsx(Trash2, {
|
|
197
197
|
size: 14,
|
|
198
|
-
color: events.length > 0 ?
|
|
198
|
+
color: events.length > 0 ? macOSColors.text.icon : macOSColors.border.toggle
|
|
199
199
|
})
|
|
200
200
|
})]
|
|
201
201
|
})]
|
|
@@ -238,10 +238,10 @@ export function StorageEventListener() {
|
|
|
238
238
|
}
|
|
239
239
|
const styles = StyleSheet.create({
|
|
240
240
|
container: {
|
|
241
|
-
backgroundColor: "rgba(
|
|
241
|
+
backgroundColor: "rgba(128, 128, 128, 0.06)",
|
|
242
242
|
borderRadius: 8,
|
|
243
243
|
borderWidth: 1,
|
|
244
|
-
borderColor: "rgba(
|
|
244
|
+
borderColor: "rgba(128, 128, 128, 0.16)",
|
|
245
245
|
marginBottom: 12,
|
|
246
246
|
maxHeight: 200
|
|
247
247
|
},
|
|
@@ -252,7 +252,7 @@ const styles = StyleSheet.create({
|
|
|
252
252
|
paddingHorizontal: 12,
|
|
253
253
|
paddingVertical: 8,
|
|
254
254
|
borderBottomWidth: 1,
|
|
255
|
-
borderBottomColor: "rgba(
|
|
255
|
+
borderBottomColor: "rgba(128, 128, 128, 0.12)"
|
|
256
256
|
},
|
|
257
257
|
headerLeft: {
|
|
258
258
|
flexDirection: "row",
|
|
@@ -262,7 +262,7 @@ const styles = StyleSheet.create({
|
|
|
262
262
|
title: {
|
|
263
263
|
fontSize: 12,
|
|
264
264
|
fontWeight: "500",
|
|
265
|
-
color:
|
|
265
|
+
color: buoyColors.textSecondary,
|
|
266
266
|
textTransform: "uppercase",
|
|
267
267
|
letterSpacing: 0.5
|
|
268
268
|
},
|
|
@@ -277,7 +277,7 @@ const styles = StyleSheet.create({
|
|
|
277
277
|
},
|
|
278
278
|
statsText: {
|
|
279
279
|
fontSize: 11,
|
|
280
|
-
color:
|
|
280
|
+
color: macOSColors.text.icon,
|
|
281
281
|
fontWeight: "500"
|
|
282
282
|
},
|
|
283
283
|
listeningIndicator: {
|
|
@@ -295,9 +295,9 @@ const styles = StyleSheet.create({
|
|
|
295
295
|
width: 28,
|
|
296
296
|
height: 28,
|
|
297
297
|
borderRadius: 6,
|
|
298
|
-
backgroundColor: "rgba(
|
|
298
|
+
backgroundColor: "rgba(128, 128, 128, 0.06)",
|
|
299
299
|
borderWidth: 1,
|
|
300
|
-
borderColor: "rgba(
|
|
300
|
+
borderColor: "rgba(128, 128, 128, 0.16)",
|
|
301
301
|
alignItems: "center",
|
|
302
302
|
justifyContent: "center"
|
|
303
303
|
},
|
|
@@ -318,7 +318,7 @@ const styles = StyleSheet.create({
|
|
|
318
318
|
},
|
|
319
319
|
emptyText: {
|
|
320
320
|
fontSize: 11,
|
|
321
|
-
color:
|
|
321
|
+
color: macOSColors.text.icon,
|
|
322
322
|
fontStyle: "italic"
|
|
323
323
|
},
|
|
324
324
|
eventItem: {
|
|
@@ -328,7 +328,7 @@ const styles = StyleSheet.create({
|
|
|
328
328
|
paddingHorizontal: 12,
|
|
329
329
|
paddingVertical: 6,
|
|
330
330
|
borderBottomWidth: 1,
|
|
331
|
-
borderBottomColor: "rgba(
|
|
331
|
+
borderBottomColor: "rgba(128, 128, 128, 0.06)"
|
|
332
332
|
},
|
|
333
333
|
eventLeft: {
|
|
334
334
|
flex: 1,
|
|
@@ -344,11 +344,11 @@ const styles = StyleSheet.create({
|
|
|
344
344
|
},
|
|
345
345
|
eventData: {
|
|
346
346
|
fontSize: 11,
|
|
347
|
-
color:
|
|
347
|
+
color: buoyColors.textSecondary,
|
|
348
348
|
flex: 1
|
|
349
349
|
},
|
|
350
350
|
eventTime: {
|
|
351
351
|
fontSize: 10,
|
|
352
|
-
color:
|
|
352
|
+
color: macOSColors.text.icon
|
|
353
353
|
}
|
|
354
354
|
});
|