@buoy-gg/storage 7.0.28 → 7.0.29
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/storage/components/GameUIStorageBrowser.js +51 -1
- package/lib/commonjs/storage/components/SelectionActionBar.js +10 -0
- package/lib/commonjs/storage/components/StorageActionButtons.js +16 -0
- package/lib/commonjs/storage/components/StorageEventActionButton.js +1 -0
- package/lib/commonjs/storage/components/StorageEventCard.js +5 -2
- package/lib/commonjs/storage/components/StorageEventFilterView.js +18 -0
- package/lib/commonjs/storage/components/StorageFilterCards.js +9 -0
- package/lib/commonjs/storage/components/StorageKeyEditorScreen.js +26 -5
- package/lib/commonjs/storage/components/StorageKeyRow.js +48 -1
- package/lib/commonjs/storage/components/StorageKeySection.js +23 -7
- package/lib/commonjs/storage/components/StorageModalWithTabs.js +26 -7
- package/lib/commonjs/storage/components/StorageScalarKeyEditor.js +16 -1
- package/lib/commonjs/storage/components/StorageTypeFilterBar.js +2 -0
- package/lib/commonjs/storage/components/StorageValueEditModal.js +18 -2
- package/lib/commonjs/storage/hooks/useTreeDraft.js +12 -1
- package/lib/commonjs/storage/utils/deleteStorageKeys.js +34 -5
- package/lib/module/storage/components/GameUIStorageBrowser.js +51 -1
- package/lib/module/storage/components/SelectionActionBar.js +10 -0
- package/lib/module/storage/components/StorageActionButtons.js +16 -0
- package/lib/module/storage/components/StorageEventActionButton.js +1 -0
- package/lib/module/storage/components/StorageEventCard.js +5 -2
- package/lib/module/storage/components/StorageEventFilterView.js +18 -0
- package/lib/module/storage/components/StorageFilterCards.js +9 -0
- package/lib/module/storage/components/StorageKeyEditorScreen.js +27 -6
- package/lib/module/storage/components/StorageKeyRow.js +49 -2
- package/lib/module/storage/components/StorageKeySection.js +23 -7
- package/lib/module/storage/components/StorageModalWithTabs.js +26 -7
- package/lib/module/storage/components/StorageScalarKeyEditor.js +16 -1
- package/lib/module/storage/components/StorageTypeFilterBar.js +2 -0
- package/lib/module/storage/components/StorageValueEditModal.js +18 -2
- package/lib/module/storage/hooks/useTreeDraft.js +12 -1
- package/lib/module/storage/utils/deleteStorageKeys.js +34 -5
- 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/StorageActionButtons.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageEventActionButton.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageEventCard.d.ts +5 -0
- package/lib/typescript/storage/components/StorageEventCard.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageEventFilterView.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageFilterCards.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageKeyEditorScreen.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageKeyRow.d.ts +9 -0
- package/lib/typescript/storage/components/StorageKeyRow.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageKeySection.d.ts +3 -1
- package/lib/typescript/storage/components/StorageKeySection.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageScalarKeyEditor.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageTypeFilterBar.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageValueEditModal.d.ts.map +1 -1
- package/lib/typescript/storage/hooks/useTreeDraft.d.ts +9 -1
- package/lib/typescript/storage/hooks/useTreeDraft.d.ts.map +1 -1
- package/lib/typescript/storage/utils/deleteStorageKeys.d.ts +15 -5
- package/lib/typescript/storage/utils/deleteStorageKeys.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -20,6 +20,7 @@ var _StorageActionButtons = require("./StorageActionButtons");
|
|
|
20
20
|
var _SelectionActionBar = require("./SelectionActionBar");
|
|
21
21
|
var _MMKVListener = require("../utils/MMKVListener");
|
|
22
22
|
var _storageBrowserRefresh = require("../utils/storageBrowserRefresh");
|
|
23
|
+
var _deleteStorageKeys = require("../utils/deleteStorageKeys");
|
|
23
24
|
var _setStorageValue = require("../utils/setStorageValue");
|
|
24
25
|
var _license = require("@buoy-gg/license");
|
|
25
26
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
@@ -256,6 +257,42 @@ function GameUIStorageBrowser({
|
|
|
256
257
|
});
|
|
257
258
|
}, [handleSaveValue]);
|
|
258
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Delete ONE key, from its own card.
|
|
262
|
+
*
|
|
263
|
+
* Routed through `deleteStorageKeys` exactly like the selection bar, so the
|
|
264
|
+
* per-backend fan-out keeps having a single implementation — the last time
|
|
265
|
+
* that fan-out was wrong (an MMKV method renamed upstream) it was wrong in
|
|
266
|
+
* silence, and a second copy is how one backend quietly stops being deleted.
|
|
267
|
+
*
|
|
268
|
+
* Pro is checked here rather than on the button because it's an upsell, not
|
|
269
|
+
* a capability: the row shows the action and explains the wall on press.
|
|
270
|
+
*/
|
|
271
|
+
const handleDeleteKey = (0, _react.useCallback)(storageKey => {
|
|
272
|
+
if (!isPro) {
|
|
273
|
+
setShowUpgradeModal(true);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
_reactNative.Alert.alert("Delete key", `Delete "${storageKey.key}"? This cannot be undone.`, [{
|
|
277
|
+
text: "Cancel",
|
|
278
|
+
style: "cancel"
|
|
279
|
+
}, {
|
|
280
|
+
text: "Delete",
|
|
281
|
+
style: "destructive",
|
|
282
|
+
onPress: async () => {
|
|
283
|
+
try {
|
|
284
|
+
await (0, _deleteStorageKeys.deleteStorageKeys)([storageKey], mmkvInstances.map(inst => ({
|
|
285
|
+
id: inst.id,
|
|
286
|
+
instance: inst.instance
|
|
287
|
+
})));
|
|
288
|
+
refresh();
|
|
289
|
+
} catch (error) {
|
|
290
|
+
_reactNative.Alert.alert("Error", `Failed to delete key: ${error}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}]);
|
|
294
|
+
}, [isPro, mmkvInstances, refresh]);
|
|
295
|
+
|
|
259
296
|
/** Permanent, per-key reasons a value can't be edited (never the licence). */
|
|
260
297
|
const editBlockedFor = (0, _react.useCallback)(storageKey => (0, _setStorageValue.storageEditBlockedReason)(storageKey, mmkvInstances), [mmkvInstances]);
|
|
261
298
|
|
|
@@ -644,6 +681,9 @@ function GameUIStorageBrowser({
|
|
|
644
681
|
contentContainerStyle: styles.instanceNavbarScroll,
|
|
645
682
|
children: [(isPro || mmkvInstances.length === 1) && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
646
683
|
onPress: () => setSelectedMMKVInstance(null),
|
|
684
|
+
testID: "buoy-storage-instance-all",
|
|
685
|
+
accessibilityRole: "button",
|
|
686
|
+
accessibilityLabel: "All MMKV instances",
|
|
647
687
|
style: [styles.instanceNavbarButton, selectedMMKVInstance === null && styles.instanceNavbarButtonActive],
|
|
648
688
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.HardDrive, {
|
|
649
689
|
size: 12,
|
|
@@ -661,6 +701,9 @@ function GameUIStorageBrowser({
|
|
|
661
701
|
}), mmkvInstances.map((inst, index) => {
|
|
662
702
|
const isLocked = index >= mmkvInstanceLimit;
|
|
663
703
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
704
|
+
testID: `buoy-storage-instance-${inst.id}`,
|
|
705
|
+
accessibilityRole: "button",
|
|
706
|
+
accessibilityLabel: `MMKV instance ${inst.id}`,
|
|
664
707
|
onPress: () => {
|
|
665
708
|
if (isLocked) {
|
|
666
709
|
setShowUpgradeModal(true);
|
|
@@ -728,6 +771,8 @@ function GameUIStorageBrowser({
|
|
|
728
771
|
style: styles.limitBanner,
|
|
729
772
|
onPress: () => setShowUpgradeModal(true),
|
|
730
773
|
activeOpacity: 0.8,
|
|
774
|
+
testID: "buoy-storage-locked-banner",
|
|
775
|
+
accessibilityRole: "button",
|
|
731
776
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
732
777
|
style: styles.limitBannerContent,
|
|
733
778
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
@@ -765,7 +810,11 @@ function GameUIStorageBrowser({
|
|
|
765
810
|
});
|
|
766
811
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
767
812
|
style: styles.root,
|
|
768
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView
|
|
813
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView
|
|
814
|
+
// Named because `by.type("RCTScrollView")` doesn't match on Fabric
|
|
815
|
+
// (renamed class) — automation scrolls below-the-fold rows by this id.
|
|
816
|
+
, {
|
|
817
|
+
testID: "buoy-storage-scroll",
|
|
769
818
|
style: styles.scrollContainer,
|
|
770
819
|
contentContainerStyle: styles.container,
|
|
771
820
|
showsVerticalScrollIndicator: false,
|
|
@@ -815,6 +864,7 @@ function GameUIStorageBrowser({
|
|
|
815
864
|
onHideKey: key => handleHideKeys([key]),
|
|
816
865
|
onEditKey: setEditingKey,
|
|
817
866
|
onToggleKey: handleToggleKey,
|
|
867
|
+
onDeleteKey: handleDeleteKey,
|
|
818
868
|
editBlockedFor: editBlockedFor,
|
|
819
869
|
pinnedKeys: pinnedKeys,
|
|
820
870
|
onTogglePin: onTogglePin
|
|
@@ -86,6 +86,9 @@ function SelectionActionBar({
|
|
|
86
86
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
87
87
|
style: styles.selectAllButton,
|
|
88
88
|
onPress: allSelected ? onClearSelection : onSelectAll,
|
|
89
|
+
testID: "buoy-storage-select-all",
|
|
90
|
+
accessibilityLabel: allSelected ? "Deselect all keys" : "Select all keys",
|
|
91
|
+
accessibilityRole: "button",
|
|
89
92
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CheckSquare, {
|
|
90
93
|
size: 14,
|
|
91
94
|
color: allSelected ? _sharedUi.night.color.accent : _sharedUi.night.color.textSecondary
|
|
@@ -105,6 +108,7 @@ function SelectionActionBar({
|
|
|
105
108
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CopyButton, {
|
|
106
109
|
value: getCopyData(),
|
|
107
110
|
size: 14,
|
|
111
|
+
testID: "buoy-storage-selection-copy",
|
|
108
112
|
buttonStyle: styles.actionButton,
|
|
109
113
|
colors: {
|
|
110
114
|
idle: _sharedUi.night.color.accent,
|
|
@@ -114,6 +118,9 @@ function SelectionActionBar({
|
|
|
114
118
|
}), onHideKeys && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
115
119
|
style: styles.actionButton,
|
|
116
120
|
onPress: handleHideSelected,
|
|
121
|
+
testID: "buoy-storage-selection-hide",
|
|
122
|
+
accessibilityLabel: "Hide selected keys",
|
|
123
|
+
accessibilityRole: "button",
|
|
117
124
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EyeOff, {
|
|
118
125
|
size: 14,
|
|
119
126
|
color: _sharedUi.night.color.warning
|
|
@@ -121,6 +128,9 @@ function SelectionActionBar({
|
|
|
121
128
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
122
129
|
style: styles.actionButton,
|
|
123
130
|
onPress: handleDeleteSelected,
|
|
131
|
+
testID: "buoy-storage-selection-delete",
|
|
132
|
+
accessibilityLabel: "Delete selected keys",
|
|
133
|
+
accessibilityRole: "button",
|
|
124
134
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
|
|
125
135
|
size: 14,
|
|
126
136
|
color: _sharedUi.night.color.danger
|
|
@@ -133,6 +133,9 @@ function StorageActionButtons({
|
|
|
133
133
|
style: styles.container,
|
|
134
134
|
children: [onToggleSelectMode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
135
135
|
onPress: onToggleSelectMode,
|
|
136
|
+
testID: "buoy-storage-select-mode",
|
|
137
|
+
accessibilityLabel: isSelectMode ? "Exit selection mode" : "Select keys",
|
|
138
|
+
accessibilityRole: "button",
|
|
136
139
|
style: [styles.actionButton, isSelectMode && styles.actionButtonActive],
|
|
137
140
|
children: isSelectMode ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
138
141
|
style: styles.selectModeActiveContainer,
|
|
@@ -150,6 +153,7 @@ function StorageActionButtons({
|
|
|
150
153
|
}), !isSelectMode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CopyButton, {
|
|
151
154
|
value: copyValue,
|
|
152
155
|
size: 16,
|
|
156
|
+
testID: "buoy-storage-export-copy",
|
|
153
157
|
buttonStyle: styles.actionButton,
|
|
154
158
|
colors: {
|
|
155
159
|
idle: _sharedUi.night.color.textSecondary,
|
|
@@ -158,6 +162,9 @@ function StorageActionButtons({
|
|
|
158
162
|
}
|
|
159
163
|
}), !isSelectMode && showClearAll && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
160
164
|
onPress: handleClearAll,
|
|
165
|
+
testID: "buoy-storage-clear-all",
|
|
166
|
+
accessibilityLabel: "Clear all storage",
|
|
167
|
+
accessibilityRole: "button",
|
|
161
168
|
style: styles.actionButton,
|
|
162
169
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
|
|
163
170
|
size: 16,
|
|
@@ -165,6 +172,9 @@ function StorageActionButtons({
|
|
|
165
172
|
})
|
|
166
173
|
}), !isSelectMode && showClearAsync && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
167
174
|
onPress: handleClearAsyncStorage,
|
|
175
|
+
testID: "buoy-storage-clear-async",
|
|
176
|
+
accessibilityLabel: "Clear AsyncStorage",
|
|
177
|
+
accessibilityRole: "button",
|
|
168
178
|
style: styles.actionButton,
|
|
169
179
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
|
|
170
180
|
size: 16,
|
|
@@ -172,6 +182,9 @@ function StorageActionButtons({
|
|
|
172
182
|
})
|
|
173
183
|
}), !isSelectMode && showClearAllMMKV && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
174
184
|
onPress: handleClearAllMMKV,
|
|
185
|
+
testID: "buoy-storage-clear-mmkv-all",
|
|
186
|
+
accessibilityLabel: "Clear all MMKV instances",
|
|
187
|
+
accessibilityRole: "button",
|
|
175
188
|
style: styles.actionButton,
|
|
176
189
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
|
|
177
190
|
size: 16,
|
|
@@ -179,6 +192,9 @@ function StorageActionButtons({
|
|
|
179
192
|
})
|
|
180
193
|
}), !isSelectMode && showClearMMKVIndividual && mmkvInstances.length === 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
181
194
|
onPress: () => handleClearMMKV(mmkvInstances[0].id, mmkvInstances[0].id),
|
|
195
|
+
testID: "buoy-storage-clear-mmkv",
|
|
196
|
+
accessibilityLabel: "Clear MMKV instance",
|
|
197
|
+
accessibilityRole: "button",
|
|
182
198
|
style: styles.actionButton,
|
|
183
199
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
|
|
184
200
|
size: 16,
|
|
@@ -82,7 +82,8 @@ const StorageEventCard = exports.StorageEventCard = /*#__PURE__*/(0, _react.memo
|
|
|
82
82
|
data,
|
|
83
83
|
onPress,
|
|
84
84
|
isSelected = false,
|
|
85
|
-
showChevron = true
|
|
85
|
+
showChevron = true,
|
|
86
|
+
testID
|
|
86
87
|
}) {
|
|
87
88
|
const actionColor = getActionColor(data.lastAction);
|
|
88
89
|
const actionLabel = (0, _storageActionHelpers.translateStorageAction)(data.lastAction);
|
|
@@ -109,6 +110,8 @@ const StorageEventCard = exports.StorageEventCard = /*#__PURE__*/(0, _react.memo
|
|
|
109
110
|
// Interaction
|
|
110
111
|
,
|
|
111
112
|
isSelected: isSelected,
|
|
112
|
-
onPress: onPress
|
|
113
|
+
onPress: onPress,
|
|
114
|
+
testID: testID,
|
|
115
|
+
accessibilityLabel: `${actionLabel} ${data.key}`
|
|
113
116
|
});
|
|
114
117
|
});
|
|
@@ -53,6 +53,12 @@ function StorageEventFilterView({
|
|
|
53
53
|
borderColor: _sharedUi.macOSColors.semantic.warning + '40'
|
|
54
54
|
}],
|
|
55
55
|
onPress: () => onToggleStorageType('async'),
|
|
56
|
+
testID: "buoy-storage-backend-async",
|
|
57
|
+
accessibilityRole: "button",
|
|
58
|
+
accessibilityLabel: "Toggle AsyncStorage capture",
|
|
59
|
+
accessibilityState: {
|
|
60
|
+
selected: enabledStorageTypes.has('async')
|
|
61
|
+
},
|
|
56
62
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Database, {
|
|
57
63
|
size: 16,
|
|
58
64
|
color: enabledStorageTypes.has('async') ? _sharedUi.macOSColors.semantic.warning : _sharedUi.night.color.textTertiary
|
|
@@ -67,6 +73,12 @@ function StorageEventFilterView({
|
|
|
67
73
|
borderColor: _sharedUi.macOSColors.semantic.info + '40'
|
|
68
74
|
}],
|
|
69
75
|
onPress: () => onToggleStorageType('mmkv'),
|
|
76
|
+
testID: "buoy-storage-backend-mmkv",
|
|
77
|
+
accessibilityRole: "button",
|
|
78
|
+
accessibilityLabel: "Toggle MMKV capture",
|
|
79
|
+
accessibilityState: {
|
|
80
|
+
selected: enabledStorageTypes.has('mmkv')
|
|
81
|
+
},
|
|
70
82
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.HardDrive, {
|
|
71
83
|
size: 16,
|
|
72
84
|
color: enabledStorageTypes.has('mmkv') ? _sharedUi.macOSColors.semantic.info : _sharedUi.night.color.textTertiary
|
|
@@ -81,6 +93,12 @@ function StorageEventFilterView({
|
|
|
81
93
|
borderColor: _sharedUi.macOSColors.semantic.success + '40'
|
|
82
94
|
}],
|
|
83
95
|
onPress: () => onToggleStorageType('secure'),
|
|
96
|
+
testID: "buoy-storage-backend-secure",
|
|
97
|
+
accessibilityRole: "button",
|
|
98
|
+
accessibilityLabel: "Toggle Secure Storage capture",
|
|
99
|
+
accessibilityState: {
|
|
100
|
+
selected: enabledStorageTypes.has('secure')
|
|
101
|
+
},
|
|
84
102
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Shield, {
|
|
85
103
|
size: 16,
|
|
86
104
|
color: enabledStorageTypes.has('secure') ? _sharedUi.macOSColors.semantic.success : _sharedUi.night.color.textTertiary
|
|
@@ -48,6 +48,9 @@ function StorageFilterCards({
|
|
|
48
48
|
}]],
|
|
49
49
|
onPress: () => onFilterChange?.("all"),
|
|
50
50
|
activeOpacity: 0.8,
|
|
51
|
+
testID: "buoy-storage-status-all",
|
|
52
|
+
accessibilityRole: "button",
|
|
53
|
+
accessibilityLabel: "Valid keys",
|
|
51
54
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
52
55
|
style: [styles.filterValue, {
|
|
53
56
|
color: _sharedUi.night.color.text
|
|
@@ -65,6 +68,9 @@ function StorageFilterCards({
|
|
|
65
68
|
}]],
|
|
66
69
|
onPress: () => onFilterChange?.("missing"),
|
|
67
70
|
activeOpacity: 0.8,
|
|
71
|
+
testID: "buoy-storage-status-missing",
|
|
72
|
+
accessibilityRole: "button",
|
|
73
|
+
accessibilityLabel: "Missing keys",
|
|
68
74
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
69
75
|
style: [styles.filterValue, {
|
|
70
76
|
color: displayStats.missingCount > 0 ? _sharedUi.macOSColors.semantic.error : _sharedUi.night.color.textTertiary
|
|
@@ -82,6 +88,9 @@ function StorageFilterCards({
|
|
|
82
88
|
}]],
|
|
83
89
|
onPress: () => onFilterChange?.("issues"),
|
|
84
90
|
activeOpacity: 0.8,
|
|
91
|
+
testID: "buoy-storage-status-issues",
|
|
92
|
+
accessibilityRole: "button",
|
|
93
|
+
accessibilityLabel: "Issues keys",
|
|
85
94
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
86
95
|
style: [styles.filterValue, {
|
|
87
96
|
color: displayStats.issuesCount > 0 ? _sharedUi.macOSColors.semantic.warning : _sharedUi.night.color.textTertiary
|
|
@@ -92,7 +92,7 @@ function StorageTreeEditor({
|
|
|
92
92
|
} = editor;
|
|
93
93
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
94
94
|
style: styles.screen,
|
|
95
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(EditorHeader, {
|
|
95
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolBackground, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(EditorHeader, {
|
|
96
96
|
storageKey: storageKey,
|
|
97
97
|
state: draft.isSaving ? "Saving…" : draft.isDirty ? "Draft · unsaved" : "In sync with device",
|
|
98
98
|
dirty: draft.isDirty,
|
|
@@ -111,6 +111,7 @@ function StorageTreeEditor({
|
|
|
111
111
|
children: summarize(draft.value)
|
|
112
112
|
})]
|
|
113
113
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
|
|
114
|
+
testID: "buoy-storage-editor-scroll",
|
|
114
115
|
style: styles.treeScroll,
|
|
115
116
|
contentContainerStyle: styles.treeContent,
|
|
116
117
|
keyboardShouldPersistTaps: "handled",
|
|
@@ -128,7 +129,11 @@ function StorageTreeEditor({
|
|
|
128
129
|
,
|
|
129
130
|
showTypeFilter: false,
|
|
130
131
|
onSelectionChange: editor.setSelection,
|
|
131
|
-
selectPath: draft.selectPath
|
|
132
|
+
selectPath: draft.selectPath
|
|
133
|
+
// Its own handle root: the card that opened this editor is still
|
|
134
|
+
// mounted underneath, rendering the same value in its preview tree.
|
|
135
|
+
,
|
|
136
|
+
testIDPrefix: "buoy-storage-editor-row",
|
|
132
137
|
onRequestInlineEdit: sel => editor.openValueEditor(sel.path)
|
|
133
138
|
})
|
|
134
139
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
@@ -156,6 +161,8 @@ function StorageTreeEditor({
|
|
|
156
161
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
157
162
|
onPress: draft.discard,
|
|
158
163
|
disabled: draft.isSaving,
|
|
164
|
+
testID: "buoy-storage-editor-discard",
|
|
165
|
+
accessibilityRole: "button",
|
|
159
166
|
accessibilityLabel: "Discard changes",
|
|
160
167
|
style: styles.discardButton,
|
|
161
168
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
@@ -165,6 +172,8 @@ function StorageTreeEditor({
|
|
|
165
172
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
166
173
|
onPress: editor.saveAndClose,
|
|
167
174
|
disabled: draft.isSaving,
|
|
175
|
+
testID: "buoy-storage-editor-save",
|
|
176
|
+
accessibilityRole: "button",
|
|
168
177
|
accessibilityLabel: "Save changes",
|
|
169
178
|
style: [styles.saveButton, draft.isSaving && styles.saveDisabled],
|
|
170
179
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
@@ -200,6 +209,8 @@ function EditorHeader({
|
|
|
200
209
|
style: styles.header,
|
|
201
210
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
202
211
|
onPress: onClose,
|
|
212
|
+
testID: "buoy-storage-editor-close",
|
|
213
|
+
accessibilityRole: "button",
|
|
203
214
|
accessibilityLabel: "Close editor",
|
|
204
215
|
style: styles.headerButton,
|
|
205
216
|
hitSlop: {
|
|
@@ -214,7 +225,13 @@ function EditorHeader({
|
|
|
214
225
|
})
|
|
215
226
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
216
227
|
style: styles.headerTitle,
|
|
217
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text
|
|
228
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text
|
|
229
|
+
// Which key this editor is pointed at. Worth a handle of its own:
|
|
230
|
+
// the editor is reached by expanding a card in a list of hundreds,
|
|
231
|
+
// and opening it on the wrong one looks exactly like opening it on
|
|
232
|
+
// the right one until a write lands somewhere unexpected.
|
|
233
|
+
, {
|
|
234
|
+
testID: "buoy-storage-editor-key",
|
|
218
235
|
style: styles.headerKey,
|
|
219
236
|
numberOfLines: 1,
|
|
220
237
|
children: storageKey.key
|
|
@@ -224,6 +241,8 @@ function EditorHeader({
|
|
|
224
241
|
})]
|
|
225
242
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
226
243
|
onPress: onRaw,
|
|
244
|
+
testID: "buoy-storage-editor-raw",
|
|
245
|
+
accessibilityRole: "button",
|
|
227
246
|
accessibilityLabel: "Edit raw JSON",
|
|
228
247
|
style: styles.headerButton,
|
|
229
248
|
hitSlop: {
|
|
@@ -269,8 +288,10 @@ function storageTypeColor(storageType) {
|
|
|
269
288
|
const styles = _reactNative.StyleSheet.create({
|
|
270
289
|
screen: {
|
|
271
290
|
flex: 1,
|
|
272
|
-
//
|
|
273
|
-
|
|
291
|
+
// Opaque on purpose: transparency here showed the whole key list through
|
|
292
|
+
// the editor, not just the sheet's star field. The screen paints its own
|
|
293
|
+
// ToolBackground instead — see the mount site above.
|
|
294
|
+
backgroundColor: _sharedUi.night.color.bg
|
|
274
295
|
},
|
|
275
296
|
header: {
|
|
276
297
|
flexDirection: "row",
|
|
@@ -92,6 +92,7 @@ const StorageKeyRow = exports.StorageKeyRow = /*#__PURE__*/(0, _react.memo)(func
|
|
|
92
92
|
onTogglePin,
|
|
93
93
|
onEditKey,
|
|
94
94
|
onToggleKey,
|
|
95
|
+
onDeleteKey,
|
|
95
96
|
editBlockedReason
|
|
96
97
|
}) {
|
|
97
98
|
const canEdit = onEditKey != null && editBlockedReason == null;
|
|
@@ -141,6 +142,9 @@ const StorageKeyRow = exports.StorageKeyRow = /*#__PURE__*/(0, _react.memo)(func
|
|
|
141
142
|
children: String(eventCount)
|
|
142
143
|
}), eventCount > 1 && onViewHistory && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
143
144
|
onPress: onViewHistory,
|
|
145
|
+
testID: "buoy-storage-key-history",
|
|
146
|
+
accessibilityLabel: `View history for ${storageKey.key}`,
|
|
147
|
+
accessibilityRole: "button",
|
|
144
148
|
style: styles.viewHistoryButton,
|
|
145
149
|
hitSlop: {
|
|
146
150
|
top: 6,
|
|
@@ -220,7 +224,14 @@ const StorageKeyRow = exports.StorageKeyRow = /*#__PURE__*/(0, _react.memo)(func
|
|
|
220
224
|
}) : null, onTogglePin || onHideKey || canEdit ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
221
225
|
style: styles.actionRow,
|
|
222
226
|
children: [canEdit ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
223
|
-
style: styles.editButton
|
|
227
|
+
style: styles.editButton
|
|
228
|
+
// One handle for both jobs on purpose: this is the card's single
|
|
229
|
+
// "change it" affordance, and which of the two it performs is the
|
|
230
|
+
// key's type, not a different control.
|
|
231
|
+
,
|
|
232
|
+
testID: "buoy-storage-key-edit",
|
|
233
|
+
accessibilityLabel: isBoolean && onToggleKey ? `Toggle ${storageKey.key}` : `Edit ${storageKey.key}`,
|
|
234
|
+
accessibilityRole: "button",
|
|
224
235
|
onPress: () => isBoolean && onToggleKey ? onToggleKey(storageKey) : onEditKey?.(storageKey),
|
|
225
236
|
hitSlop: {
|
|
226
237
|
top: 6,
|
|
@@ -237,6 +248,9 @@ const StorageKeyRow = exports.StorageKeyRow = /*#__PURE__*/(0, _react.memo)(func
|
|
|
237
248
|
})]
|
|
238
249
|
}) : null, onTogglePin ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
239
250
|
style: [styles.actionChip, isPinned && styles.actionChipActive],
|
|
251
|
+
testID: "buoy-storage-key-pin",
|
|
252
|
+
accessibilityLabel: isPinned ? `Unpin ${storageKey.key}` : `Pin ${storageKey.key} to top`,
|
|
253
|
+
accessibilityRole: "button",
|
|
240
254
|
onPress: () => onTogglePin(storageKey.key),
|
|
241
255
|
hitSlop: {
|
|
242
256
|
top: 6,
|
|
@@ -256,6 +270,9 @@ const StorageKeyRow = exports.StorageKeyRow = /*#__PURE__*/(0, _react.memo)(func
|
|
|
256
270
|
})]
|
|
257
271
|
}) : null, onHideKey ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
258
272
|
style: styles.actionChip,
|
|
273
|
+
testID: "buoy-storage-key-hide",
|
|
274
|
+
accessibilityLabel: `Hide ${storageKey.key} from list`,
|
|
275
|
+
accessibilityRole: "button",
|
|
259
276
|
onPress: () => onHideKey(storageKey),
|
|
260
277
|
hitSlop: {
|
|
261
278
|
top: 6,
|
|
@@ -272,6 +289,27 @@ const StorageKeyRow = exports.StorageKeyRow = /*#__PURE__*/(0, _react.memo)(func
|
|
|
272
289
|
}],
|
|
273
290
|
children: "Hide from list"
|
|
274
291
|
})]
|
|
292
|
+
}) : null, canEdit && onDeleteKey ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
293
|
+
style: [styles.actionChip, styles.dangerChip],
|
|
294
|
+
testID: "buoy-storage-key-delete",
|
|
295
|
+
accessibilityLabel: `Delete key ${storageKey.key}`,
|
|
296
|
+
accessibilityRole: "button",
|
|
297
|
+
onPress: () => onDeleteKey(storageKey),
|
|
298
|
+
hitSlop: {
|
|
299
|
+
top: 6,
|
|
300
|
+
bottom: 6,
|
|
301
|
+
left: 6,
|
|
302
|
+
right: 6
|
|
303
|
+
},
|
|
304
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
|
|
305
|
+
size: 12,
|
|
306
|
+
color: _sharedUi.night.color.danger
|
|
307
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
308
|
+
style: [styles.actionChipText, {
|
|
309
|
+
color: _sharedUi.night.color.danger
|
|
310
|
+
}],
|
|
311
|
+
children: "Delete key"
|
|
312
|
+
})]
|
|
275
313
|
}) : null]
|
|
276
314
|
}) : null]
|
|
277
315
|
});
|
|
@@ -284,6 +322,12 @@ const StorageKeyRow = exports.StorageKeyRow = /*#__PURE__*/(0, _react.memo)(func
|
|
|
284
322
|
// Create checkbox element for select mode
|
|
285
323
|
const selectionCheckbox = isSelectMode ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
286
324
|
onPress: handleCheckboxPress,
|
|
325
|
+
testID: `buoy-storage-checkbox-${storageKey.storageType}-${storageKey.key}`,
|
|
326
|
+
accessibilityLabel: `Select ${storageKey.key}`,
|
|
327
|
+
accessibilityRole: "checkbox",
|
|
328
|
+
accessibilityState: {
|
|
329
|
+
checked: isSelected
|
|
330
|
+
},
|
|
287
331
|
style: styles.checkboxContainer,
|
|
288
332
|
hitSlop: {
|
|
289
333
|
top: 8,
|
|
@@ -457,6 +501,9 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
457
501
|
borderWidth: 1,
|
|
458
502
|
borderColor: _sharedUi.night.color.border
|
|
459
503
|
},
|
|
504
|
+
dangerChip: {
|
|
505
|
+
borderColor: _sharedUi.night.color.danger + "55"
|
|
506
|
+
},
|
|
460
507
|
actionChipActive: {
|
|
461
508
|
backgroundColor: _sharedUi.night.color.accentSoft,
|
|
462
509
|
borderColor: _sharedUi.night.color.accentBorderStrong
|
|
@@ -33,17 +33,32 @@ function StorageKeySection({
|
|
|
33
33
|
onTogglePin,
|
|
34
34
|
onEditKey,
|
|
35
35
|
onToggleKey,
|
|
36
|
+
onDeleteKey,
|
|
36
37
|
editBlockedFor
|
|
37
38
|
}) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Identifies a ROW, not a key name.
|
|
41
|
+
*
|
|
42
|
+
* The same name routinely exists in more than one place — an app that keeps
|
|
43
|
+
* `auth.refreshToken` in both MMKV and the keychain has two rows called
|
|
44
|
+
* that, and they are different values in different stores.
|
|
45
|
+
*/
|
|
44
46
|
const getKeyIdentifier = (0, _react.useCallback)(storageKey => {
|
|
45
47
|
return storageKey.instanceId ? `${storageKey.storageType}-${storageKey.instanceId}-${storageKey.key}` : `${storageKey.storageType}-${storageKey.key}`;
|
|
46
48
|
}, []);
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Which ROW is expanded — by identifier, not by key name.
|
|
52
|
+
*
|
|
53
|
+
* Keyed by name, tapping one of a pair of same-named rows opened BOTH of
|
|
54
|
+
* them: two cards, two value trees, and two Edit buttons, one of which
|
|
55
|
+
* writes to a store you weren't looking at.
|
|
56
|
+
*/
|
|
57
|
+
const [expandedKey, setExpandedKey] = (0, _react.useState)(null);
|
|
58
|
+
const handleKeyPress = (0, _react.useCallback)(storageKey => {
|
|
59
|
+
const id = getKeyIdentifier(storageKey);
|
|
60
|
+
setExpandedKey(prev => prev === id ? null : id);
|
|
61
|
+
}, [getKeyIdentifier]);
|
|
47
62
|
if (keys.length === 0 && title === "Required Keys") {
|
|
48
63
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
49
64
|
style: styles.sectionContainer,
|
|
@@ -80,7 +95,7 @@ function StorageKeySection({
|
|
|
80
95
|
const uniqueKey = getKeyIdentifier(storageKey);
|
|
81
96
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageKeyRow.StorageKeyRow, {
|
|
82
97
|
storageKey: storageKey,
|
|
83
|
-
isExpanded: !isSelectMode && expandedKey ===
|
|
98
|
+
isExpanded: !isSelectMode && expandedKey === uniqueKey,
|
|
84
99
|
onPress: handleKeyPress,
|
|
85
100
|
isSelectMode: isSelectMode,
|
|
86
101
|
isSelected: selectedKeys.has(uniqueKey),
|
|
@@ -90,6 +105,7 @@ function StorageKeySection({
|
|
|
90
105
|
onHideKey: onHideKey,
|
|
91
106
|
onEditKey: onEditKey,
|
|
92
107
|
onToggleKey: onToggleKey,
|
|
108
|
+
onDeleteKey: onDeleteKey,
|
|
93
109
|
editBlockedReason: editBlockedFor?.(storageKey),
|
|
94
110
|
isPinned: pinnedKeys?.has(storageKey.key),
|
|
95
111
|
onTogglePin: onTogglePin
|
|
@@ -550,7 +550,8 @@ function StorageModalWithTabs({
|
|
|
550
550
|
};
|
|
551
551
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageEventCard.StorageEventCard, {
|
|
552
552
|
data: cardData,
|
|
553
|
-
onPress: () => handleRawEventPress(item)
|
|
553
|
+
onPress: () => handleRawEventPress(item),
|
|
554
|
+
testID: `buoy-storage-event-${item.id}`
|
|
554
555
|
});
|
|
555
556
|
}, [handleRawEventPress]);
|
|
556
557
|
if (!visible) return null;
|
|
@@ -587,6 +588,7 @@ function StorageModalWithTabs({
|
|
|
587
588
|
const ascSortedEvents = [...selectedHistoryConversation.events].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
588
589
|
const newestFirstEvents = [...ascSortedEvents].reverse();
|
|
589
590
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
|
|
591
|
+
testID: "buoy-storage-history-list",
|
|
590
592
|
style: styles.flexFill,
|
|
591
593
|
data: newestFirstEvents,
|
|
592
594
|
keyExtractor: item => item.id,
|
|
@@ -604,7 +606,8 @@ function StorageModalWithTabs({
|
|
|
604
606
|
};
|
|
605
607
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageEventCard.StorageEventCard, {
|
|
606
608
|
data: cardData,
|
|
607
|
-
onPress: () => setSelectedHistoryEventIndex(ascIdx >= 0 ? ascIdx : 0)
|
|
609
|
+
onPress: () => setSelectedHistoryEventIndex(ascIdx >= 0 ? ascIdx : 0),
|
|
610
|
+
testID: `buoy-storage-history-event-${item.id}`
|
|
608
611
|
});
|
|
609
612
|
},
|
|
610
613
|
contentContainerStyle: styles.listContent,
|
|
@@ -682,6 +685,7 @@ function StorageModalWithTabs({
|
|
|
682
685
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
683
686
|
style: styles.flexFill,
|
|
684
687
|
children: [eventTypeFilterBar, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
|
|
688
|
+
testID: "buoy-storage-events-list",
|
|
685
689
|
style: styles.flexFill,
|
|
686
690
|
data: visibleEvents,
|
|
687
691
|
renderItem: renderEventItem,
|
|
@@ -759,6 +763,7 @@ function StorageModalWithTabs({
|
|
|
759
763
|
setIsSearchActive(false);
|
|
760
764
|
},
|
|
761
765
|
placeholder: "Search storage keys...",
|
|
766
|
+
testID: "buoy-storage-search",
|
|
762
767
|
autoFocus: true,
|
|
763
768
|
onSubmitEditing: () => setIsSearchActive(false),
|
|
764
769
|
returnKeyType: "search",
|
|
@@ -773,6 +778,7 @@ function StorageModalWithTabs({
|
|
|
773
778
|
label: `Events${filteredEvents.length > 0 ? ` (${filteredEvents.length})` : ""}`
|
|
774
779
|
}],
|
|
775
780
|
activeTab: activeTab,
|
|
781
|
+
testIDPrefix: "buoy-storage-tab",
|
|
776
782
|
onTabChange: tab => {
|
|
777
783
|
setActiveTab(tab);
|
|
778
784
|
setSelectedHistoryKey(null);
|
|
@@ -785,13 +791,18 @@ function StorageModalWithTabs({
|
|
|
785
791
|
children: [onRefresh && !isSearchActive ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
786
792
|
onPress: onRefresh,
|
|
787
793
|
style: styles.iconButton,
|
|
794
|
+
testID: "buoy-storage-refresh",
|
|
788
795
|
accessibilityLabel: "Refresh storage",
|
|
796
|
+
accessibilityRole: "button",
|
|
789
797
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.RefreshCw, {
|
|
790
798
|
size: 14,
|
|
791
799
|
color: _sharedUi.night.color.textSecondary
|
|
792
800
|
})
|
|
793
801
|
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
794
802
|
onPress: handleToggleFilters,
|
|
803
|
+
testID: "buoy-storage-filters",
|
|
804
|
+
accessibilityLabel: "Storage filters",
|
|
805
|
+
accessibilityRole: "button",
|
|
795
806
|
style: [styles.iconButton, (ignoredPatterns.size > 0 || enabledStorageTypes.size < 3) && styles.activeFilterButton],
|
|
796
807
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Filter, {
|
|
797
808
|
size: 14,
|
|
@@ -800,6 +811,9 @@ function StorageModalWithTabs({
|
|
|
800
811
|
}), activeTab === "browser" && !isSearchActive && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
801
812
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
802
813
|
onPress: () => setIsSearchActive(true),
|
|
814
|
+
testID: "buoy-storage-search-open",
|
|
815
|
+
accessibilityLabel: "Open search",
|
|
816
|
+
accessibilityRole: "button",
|
|
803
817
|
style: styles.iconButton,
|
|
804
818
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Search, {
|
|
805
819
|
size: 14,
|
|
@@ -808,20 +822,24 @@ function StorageModalWithTabs({
|
|
|
808
822
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton, {
|
|
809
823
|
value: getStorageSnapshot,
|
|
810
824
|
disabled: storageDataRef.current.length === 0,
|
|
811
|
-
buttonStyle: styles.iconButton
|
|
825
|
+
buttonStyle: styles.iconButton,
|
|
826
|
+
testID: "buoy-storage-copy"
|
|
812
827
|
})]
|
|
813
828
|
}), activeTab === "events" && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
814
829
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton, {
|
|
815
830
|
value: getEventsSnapshot,
|
|
816
831
|
disabled: filteredEvents.length === 0,
|
|
817
|
-
buttonStyle: styles.iconButton
|
|
832
|
+
buttonStyle: styles.iconButton,
|
|
833
|
+
testID: "buoy-storage-events-copy"
|
|
818
834
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PowerToggleButton, {
|
|
819
835
|
isEnabled: isListening,
|
|
820
836
|
onToggle: handleToggleListening,
|
|
821
|
-
accessibilityLabel: "Toggle storage event monitoring"
|
|
837
|
+
accessibilityLabel: "Toggle storage event monitoring",
|
|
838
|
+
testID: "buoy-storage-power"
|
|
822
839
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolbarClearButton, {
|
|
823
840
|
onPress: handleClearEvents,
|
|
824
|
-
buttonStyle: styles.iconButton
|
|
841
|
+
buttonStyle: styles.iconButton,
|
|
842
|
+
testID: "buoy-storage-clear-events"
|
|
825
843
|
})]
|
|
826
844
|
})]
|
|
827
845
|
})]
|
|
@@ -891,7 +909,8 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
891
909
|
paddingVertical: 8,
|
|
892
910
|
borderBottomWidth: 1,
|
|
893
911
|
borderBottomColor: _sharedUi.macOSColors.border.default,
|
|
894
|
-
|
|
912
|
+
// Clear, like Bench — the host's hoisted sky shows through the header.
|
|
913
|
+
backgroundColor: "transparent"
|
|
895
914
|
},
|
|
896
915
|
headerSearchContainer: {
|
|
897
916
|
flex: 1
|