@buoy-gg/storage 2.1.6 → 2.1.9

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.
@@ -13,7 +13,6 @@ var _StorageBrowserMode = require("./StorageBrowserMode");
13
13
  var _clearAllStorage = require("../utils/clearAllStorage");
14
14
  var _useStorageEvents = require("../hooks/useStorageEvents");
15
15
  var _StorageEventDetailContent = require("./StorageEventDetailContent");
16
- var _StorageFilterViewV = require("./StorageFilterViewV2");
17
16
  var _StorageEventFilterView = require("./StorageEventFilterView");
18
17
  var _StorageEventCard = require("./StorageEventCard");
19
18
  var _license = require("@buoy-gg/license");
@@ -36,12 +35,8 @@ function StorageModalWithTabs({
36
35
  const [activeTab, setActiveTab] = (0, _react.useState)("browser");
37
36
 
38
37
  // Storage Browser state
39
- const [showStorageFilters, setShowStorageFilters] = (0, _react.useState)(false);
40
- const [storageIgnoredPatterns, setStorageIgnoredPatterns] = (0, _react.useState)(new Set(["@react_buoy"]) // Auto-hide dev tool keys by default
41
- );
42
38
  const [searchQuery, setSearchQuery] = (0, _react.useState)("");
43
39
  const [isSearchActive, setIsSearchActive] = (0, _react.useState)(false);
44
- const hasLoadedStorageFilters = (0, _react.useRef)(false);
45
40
 
46
41
  // Local state to control subscription (true = subscribed, false = unsubscribed)
47
42
  const [isListeningEnabled, setIsListeningEnabled] = (0, _react.useState)(true);
@@ -57,6 +52,8 @@ function StorageModalWithTabs({
57
52
  enabled: isListeningEnabled
58
53
  });
59
54
  const [selectedConversationKey, setSelectedConversationKey] = (0, _react.useState)(null);
55
+ const [selectedHistoryKey, setSelectedHistoryKey] = (0, _react.useState)(null);
56
+ const [selectedHistoryEventIndex, setSelectedHistoryEventIndex] = (0, _react.useState)(null);
60
57
  const [selectedEventIndex, setSelectedEventIndex] = (0, _react.useState)(0);
61
58
  const [showFilters, setShowFilters] = (0, _react.useState)(false);
62
59
  const [ignoredPatterns, setIgnoredPatterns] = (0, _react.useState)(new Set(["@react_buoy", "@RNAsyncStorage", "redux-persist", "persist:"]) // Auto-hide dev tool keys by default
@@ -189,10 +186,15 @@ function StorageModalWithTabs({
189
186
  const handleClearEvents = (0, _react.useCallback)(() => {
190
187
  clearStorageEvents();
191
188
  setSelectedConversationKey(null);
192
- }, [clearStorageEvents]);
193
- const handleConversationPress = (0, _react.useCallback)(conversation => {
194
- setSelectedConversationKey(conversation.key);
195
189
  setSelectedEventIndex(0);
190
+ }, [clearStorageEvents]);
191
+ const handleViewHistoryFromBrowser = (0, _react.useCallback)(key => {
192
+ setSelectedHistoryKey(key);
193
+ setSelectedHistoryEventIndex(null);
194
+ }, []);
195
+ const handleBackFromHistory = (0, _react.useCallback)(() => {
196
+ setSelectedHistoryKey(null);
197
+ setSelectedHistoryEventIndex(null);
196
198
  }, []);
197
199
  const handleTogglePattern = (0, _react.useCallback)(pattern => {
198
200
  setIgnoredPatterns(prev => {
@@ -225,22 +227,26 @@ function StorageModalWithTabs({
225
227
 
226
228
  // Storage Browser handlers
227
229
  const storageDataRef = (0, _react.useRef)([]);
228
- const handleToggleStorageFilters = (0, _react.useCallback)(() => {
229
- setShowStorageFilters(!showStorageFilters);
230
- }, [showStorageFilters]);
231
- const handleToggleStoragePattern = (0, _react.useCallback)(pattern => {
232
- setStorageIgnoredPatterns(prev => {
233
- const next = new Set(prev);
234
- if (next.has(pattern)) {
235
- next.delete(pattern);
236
- } else {
237
- next.add(pattern);
238
- }
239
- return next;
240
- });
241
- }, []);
242
- const handleAddStoragePattern = (0, _react.useCallback)(pattern => {
243
- setStorageIgnoredPatterns(prev => new Set([...prev, pattern]));
230
+ const getStorageSnapshot = (0, _react.useCallback)(() => {
231
+ const keys = storageDataRef.current;
232
+ return {
233
+ timestamp: new Date().toISOString(),
234
+ totalKeys: keys.length,
235
+ asyncStorage: keys.filter(k => k.storageType === 'async').reduce((acc, k) => {
236
+ acc[k.key] = (0, _sharedUi.truncatePayload)(k.value);
237
+ return acc;
238
+ }, {}),
239
+ mmkv: keys.filter(k => k.storageType === 'mmkv').reduce((acc, k) => {
240
+ const id = k.instanceId || 'default';
241
+ if (!acc[id]) acc[id] = {};
242
+ acc[id][k.key] = (0, _sharedUi.truncatePayload)(k.value);
243
+ return acc;
244
+ }, {}),
245
+ secure: keys.filter(k => k.storageType === 'secure').reduce((acc, k) => {
246
+ acc[k.key] = (0, _sharedUi.truncatePayload)(k.value);
247
+ return acc;
248
+ }, {})
249
+ };
244
250
  }, []);
245
251
  const handlePurgeStorage = (0, _react.useCallback)(async () => {
246
252
  _reactNative.Alert.alert("Clear Storage", "Choose what to clear:", [{
@@ -357,67 +363,154 @@ function StorageModalWithTabs({
357
363
  return conversations.find(c => c.key === selectedConversationKey) || null;
358
364
  }, [selectedConversationKey, conversations]);
359
365
 
360
- // For free users, limit visible conversations
361
- const visibleConversations = (0, _react.useMemo)(() => {
362
- if (isPro) return conversations;
363
- return conversations.slice(0, FREE_TIER_EVENT_LIMIT);
364
- }, [conversations, isPro]);
365
- const lockedConversationCount = (0, _react.useMemo)(() => {
366
+ // Event count per key for storage browser badges
367
+ const eventCountByKey = (0, _react.useMemo)(() => {
368
+ const counts = {};
369
+ conversations.forEach(conv => {
370
+ counts[conv.key] = conv.totalOperations;
371
+ });
372
+ return counts;
373
+ }, [conversations]);
374
+
375
+ // Selected history conversation (from browser tab "view history")
376
+ const selectedHistoryConversation = (0, _react.useMemo)(() => {
377
+ if (!selectedHistoryKey) return null;
378
+ return conversations.find(c => c.key === selectedHistoryKey) || null;
379
+ }, [selectedHistoryKey, conversations]);
380
+
381
+ // Filtered raw events for the events tab (chronological stream, newest-first)
382
+ const filteredEvents = (0, _react.useMemo)(() => {
383
+ return events.filter(event => {
384
+ if (!event.data?.key) return false;
385
+ if (!enabledStorageTypes.has(event.storageType)) return false;
386
+ const key = event.data.key;
387
+ return !Array.from(ignoredPatterns).some(p => key.includes(p));
388
+ });
389
+ }, [events, ignoredPatterns, enabledStorageTypes]);
390
+ const getEventsSnapshot = (0, _react.useCallback)(() => {
391
+ return filteredEvents.map(event => ({
392
+ key: event.data?.key,
393
+ action: event.action,
394
+ value: (0, _sharedUi.truncatePayload)(event.data?.value),
395
+ storageType: event.storageType,
396
+ timestamp: event.timestamp.toISOString()
397
+ }));
398
+ }, [filteredEvents]);
399
+ const visibleEvents = (0, _react.useMemo)(() => {
400
+ if (isPro) return filteredEvents;
401
+ return filteredEvents.slice(0, FREE_TIER_EVENT_LIMIT);
402
+ }, [filteredEvents, isPro]);
403
+ const lockedEventCount = (0, _react.useMemo)(() => {
366
404
  if (isPro) return 0;
367
- return Math.max(0, conversations.length - FREE_TIER_EVENT_LIMIT);
368
- }, [conversations.length, isPro]);
405
+ return Math.max(0, filteredEvents.length - FREE_TIER_EVENT_LIMIT);
406
+ }, [filteredEvents.length, isPro]);
369
407
 
370
408
  // FlatList optimization constants
371
409
  const END_REACHED_THRESHOLD = 0.8;
372
410
 
373
- // Stable keyExtractor for FlatList
374
- const keyExtractor = (0, _react.useCallback)(item => {
375
- return item.key;
411
+ // keyExtractor for raw event FlatList
412
+ const eventKeyExtractor = (0, _react.useCallback)((item, index) => {
413
+ return `${item.timestamp.getTime()}-${item.data?.key || index}`;
376
414
  }, []);
377
415
 
378
- // Removed getItemType as it's FlatList-specific
379
-
380
- // Create stable ref for event handler
381
- const selectConversationRef = (0, _react.useRef)(undefined);
382
- selectConversationRef.current = handleConversationPress;
383
-
384
- // Stable renderItem with ref pattern
385
- const renderConversationItem = (0, _react.useCallback)(({
416
+ // When a raw event card is pressed, open that key's conversation detail at the matching event
417
+ const handleRawEventPress = (0, _react.useCallback)(item => {
418
+ const conv = conversations.find(c => c.key === item.data?.key);
419
+ if (!conv) return;
420
+ const sortedEvents = [...conv.events].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
421
+ const eventIndex = sortedEvents.findIndex(e => e.timestamp.getTime() === item.timestamp.getTime());
422
+ setSelectedConversationKey(conv.key);
423
+ setSelectedEventIndex(eventIndex >= 0 ? eventIndex : 0);
424
+ }, [conversations]);
425
+
426
+ // Render a single raw event card
427
+ const renderEventItem = (0, _react.useCallback)(({
386
428
  item
387
429
  }) => {
388
430
  const cardData = {
389
- key: item.key,
390
- lastAction: item.lastEvent.action,
391
- totalOperations: item.totalOperations,
392
- lastEventTimestamp: item.lastEvent.timestamp,
393
- storageTypes: item.storageTypes,
394
- valueType: item.valueType
431
+ key: item.data?.key || "",
432
+ lastAction: item.action,
433
+ totalOperations: 1,
434
+ lastEventTimestamp: item.timestamp,
435
+ storageTypes: new Set([item.storageType]),
436
+ valueType: getValueType(item.data?.value)
395
437
  };
396
438
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageEventCard.StorageEventCard, {
397
439
  data: cardData,
398
- onPress: () => selectConversationRef.current?.(item)
440
+ onPress: () => handleRawEventPress(item)
399
441
  });
400
- }, []);
442
+ }, [handleRawEventPress]);
401
443
  if (!visible) return null;
402
444
  const persistenceKey = enableSharedModalDimensions ? _sharedUi.devToolsStorageKeys.modal.root() : _sharedUi.devToolsStorageKeys.storage.modal();
403
445
  const renderContent = () => {
446
+ // Filters overlay — applies to both tabs
447
+ if (showFilters) {
448
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageEventFilterView.StorageEventFilterView, {
449
+ ignoredPatterns: ignoredPatterns,
450
+ onTogglePattern: handleTogglePattern,
451
+ onAddPattern: handleAddPattern,
452
+ availableKeys: allEventKeys,
453
+ enabledStorageTypes: enabledStorageTypes,
454
+ onToggleStorageType: handleToggleStorageType
455
+ });
456
+ }
404
457
  if (activeTab === "browser") {
405
- if (showStorageFilters) {
406
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageFilterViewV.StorageFilterViewV2, {
407
- ignoredPatterns: storageIgnoredPatterns,
408
- onTogglePattern: handleToggleStoragePattern,
409
- onAddPattern: handleAddStoragePattern,
410
- availableKeys: allStorageKeys
458
+ // History flow for a specific key (from "view history" in browser tab)
459
+ if (selectedHistoryKey && selectedHistoryConversation) {
460
+ // Level 2: detail view for a specific event
461
+ if (selectedHistoryEventIndex !== null) {
462
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
463
+ style: styles.contentWrapper,
464
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageEventDetailContent.StorageEventDetailContent, {
465
+ conversation: selectedHistoryConversation,
466
+ selectedEventIndex: selectedHistoryEventIndex,
467
+ onEventIndexChange: setSelectedHistoryEventIndex,
468
+ disableInternalFooter: true
469
+ })
470
+ });
471
+ }
472
+
473
+ // Level 1: event list for this key (newest-first)
474
+ const ascSortedEvents = [...selectedHistoryConversation.events].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
475
+ const newestFirstEvents = [...ascSortedEvents].reverse();
476
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
477
+ data: newestFirstEvents,
478
+ keyExtractor: (item, index) => `${item.timestamp.getTime()}-${index}`,
479
+ renderItem: ({
480
+ item
481
+ }) => {
482
+ const ascIdx = ascSortedEvents.findIndex(e => e.timestamp.getTime() === item.timestamp.getTime());
483
+ const cardData = {
484
+ key: item.data?.key || "",
485
+ lastAction: item.action,
486
+ totalOperations: 1,
487
+ lastEventTimestamp: item.timestamp,
488
+ storageTypes: new Set([item.storageType]),
489
+ valueType: getValueType(item.data?.value)
490
+ };
491
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageEventCard.StorageEventCard, {
492
+ data: cardData,
493
+ onPress: () => setSelectedHistoryEventIndex(ascIdx >= 0 ? ascIdx : 0)
494
+ });
495
+ },
496
+ contentContainerStyle: styles.listContent,
497
+ ItemSeparatorComponent: () => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
498
+ style: styles.separator
499
+ }),
500
+ initialNumToRender: 20,
501
+ scrollEnabled: false
411
502
  });
412
503
  }
413
504
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageBrowserMode.StorageBrowserMode, {
414
505
  requiredStorageKeys: requiredStorageKeys,
415
- showFilters: showStorageFilters,
416
- ignoredPatterns: storageIgnoredPatterns,
417
- onTogglePattern: handleToggleStoragePattern,
418
- onAddPattern: handleAddStoragePattern,
506
+ ignoredPatterns: ignoredPatterns,
507
+ onTogglePattern: handleTogglePattern,
508
+ onAddPattern: handleAddPattern,
419
509
  searchQuery: searchQuery,
420
- storageDataRef: storageDataRef
510
+ storageDataRef: storageDataRef,
511
+ eventCountByKey: eventCountByKey,
512
+ onViewHistory: handleViewHistoryFromBrowser,
513
+ enabledStorageTypes: enabledStorageTypes
421
514
  });
422
515
  }
423
516
 
@@ -433,17 +526,7 @@ function StorageModalWithTabs({
433
526
  })
434
527
  });
435
528
  }
436
- if (showFilters) {
437
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageEventFilterView.StorageEventFilterView, {
438
- ignoredPatterns: ignoredPatterns,
439
- onTogglePattern: handleTogglePattern,
440
- onAddPattern: handleAddPattern,
441
- availableKeys: allEventKeys,
442
- enabledStorageTypes: enabledStorageTypes,
443
- onToggleStorageType: handleToggleStorageType
444
- });
445
- }
446
- if (conversations.length === 0) {
529
+ if (filteredEvents.length === 0) {
447
530
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
448
531
  style: styles.emptyState,
449
532
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Database, {
@@ -459,18 +542,15 @@ function StorageModalWithTabs({
459
542
  });
460
543
  }
461
544
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
462
- data: visibleConversations,
463
- renderItem: renderConversationItem,
464
- keyExtractor: keyExtractor,
545
+ data: visibleEvents,
546
+ renderItem: renderEventItem,
547
+ keyExtractor: eventKeyExtractor,
465
548
  onEndReachedThreshold: END_REACHED_THRESHOLD,
466
549
  contentContainerStyle: styles.listContent,
467
- ItemSeparatorComponent: () => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
468
- style: styles.separator
469
- }),
470
- ListFooterComponent: lockedConversationCount > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
550
+ ListFooterComponent: lockedEventCount > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
471
551
  style: styles.lockedBannerContainer,
472
552
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ProFeatureBanner, {
473
- featureName: `${lockedConversationCount} event${lockedConversationCount > 1 ? 's' : ''} locked`,
553
+ featureName: `${lockedEventCount} event${lockedEventCount > 1 ? 's' : ''} locked`,
474
554
  description: "Upgrade to Pro to unlock full event history"
475
555
  })
476
556
  }) : null,
@@ -484,10 +564,14 @@ function StorageModalWithTabs({
484
564
  conversation: selectedConversation,
485
565
  selectedEventIndex: selectedEventIndex,
486
566
  onEventIndexChange: setSelectedEventIndex
567
+ }) : selectedHistoryConversation && selectedHistoryEventIndex !== null ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageEventDetailContent.StorageEventDetailFooter, {
568
+ conversation: selectedHistoryConversation,
569
+ selectedEventIndex: selectedHistoryEventIndex,
570
+ onEventIndexChange: setSelectedHistoryEventIndex
487
571
  }) : null;
488
572
 
489
573
  // Determine the appropriate back handler based on current view state
490
- const currentBackHandler = showStorageFilters ? () => setShowStorageFilters(false) : showFilters ? () => setShowFilters(false) : selectedConversation ? () => {
574
+ const currentBackHandler = showFilters ? () => setShowFilters(false) : selectedHistoryEventIndex !== null ? () => setSelectedHistoryEventIndex(null) : selectedHistoryKey ? handleBackFromHistory : selectedConversation ? () => {
491
575
  setSelectedConversationKey(null);
492
576
  setSelectedEventIndex(0);
493
577
  } : onBack;
@@ -499,17 +583,18 @@ function StorageModalWithTabs({
499
583
  persistenceKey: persistenceKey,
500
584
  header: {
501
585
  showToggleButton: true,
502
- customContent: showStorageFilters ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
586
+ customContent: showFilters ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
503
587
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
504
- onBack: () => setShowStorageFilters(false)
588
+ onBack: () => setShowFilters(false)
505
589
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
506
590
  title: "Filters"
507
591
  })]
508
- }) : showFilters ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
592
+ }) : selectedHistoryKey ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
509
593
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
510
- onBack: () => setShowFilters(false)
594
+ onBack: selectedHistoryEventIndex !== null ? () => setSelectedHistoryEventIndex(null) : handleBackFromHistory
511
595
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
512
- title: "Event Filters"
596
+ title: `${selectedHistoryKey} History`,
597
+ centered: true
513
598
  })]
514
599
  }) : selectedConversation ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
515
600
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
@@ -544,13 +629,26 @@ function StorageModalWithTabs({
544
629
  label: "Storage"
545
630
  }, {
546
631
  key: "events",
547
- label: `Events${conversations.length > 0 && activeTab !== "events" ? ` (${conversations.length})` : ""}`
632
+ label: `Events${filteredEvents.length > 0 ? ` (${filteredEvents.length})` : ""}`
548
633
  }],
549
634
  activeTab: activeTab,
550
- onTabChange: tab => setActiveTab(tab)
635
+ onTabChange: tab => {
636
+ setActiveTab(tab);
637
+ setSelectedHistoryKey(null);
638
+ setSelectedHistoryEventIndex(null);
639
+ setSelectedConversationKey(null);
640
+ setSelectedEventIndex(0);
641
+ }
551
642
  })
552
643
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions, {
553
- children: [activeTab === "browser" && !isSearchActive && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
644
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
645
+ onPress: handleToggleFilters,
646
+ style: [styles.iconButton, (ignoredPatterns.size > 0 || enabledStorageTypes.size < 3) && styles.activeFilterButton],
647
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Filter, {
648
+ size: 14,
649
+ color: ignoredPatterns.size > 0 || enabledStorageTypes.size < 3 ? _sharedUi.macOSColors.semantic.debug : _sharedUi.macOSColors.text.secondary
650
+ })
651
+ }), activeTab === "browser" && !isSearchActive && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
554
652
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
555
653
  onPress: () => setIsSearchActive(true),
556
654
  style: styles.iconButton,
@@ -558,33 +656,23 @@ function StorageModalWithTabs({
558
656
  size: 14,
559
657
  color: _sharedUi.macOSColors.text.secondary
560
658
  })
561
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
562
- onPress: handleToggleStorageFilters,
563
- style: [styles.iconButton, storageIgnoredPatterns.size > 0 && styles.activeFilterButton],
564
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Filter, {
565
- size: 14,
566
- color: storageIgnoredPatterns.size > 0 ? _sharedUi.macOSColors.semantic.debug : _sharedUi.macOSColors.text.secondary
567
- })
659
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton, {
660
+ value: getStorageSnapshot,
661
+ disabled: storageDataRef.current.length === 0,
662
+ buttonStyle: styles.iconButton
568
663
  })]
569
664
  }), activeTab === "events" && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
570
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
571
- onPress: handleToggleFilters,
572
- style: [styles.iconButton, ignoredPatterns.size > 0 && styles.activeFilterButton],
573
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Filter, {
574
- size: 14,
575
- color: ignoredPatterns.size > 0 ? _sharedUi.macOSColors.semantic.debug : _sharedUi.macOSColors.text.secondary
576
- })
665
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton, {
666
+ value: getEventsSnapshot,
667
+ disabled: filteredEvents.length === 0,
668
+ buttonStyle: styles.iconButton
577
669
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PowerToggleButton, {
578
670
  isEnabled: isListening,
579
671
  onToggle: handleToggleListening,
580
672
  accessibilityLabel: "Toggle storage event monitoring"
581
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
673
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolbarClearButton, {
582
674
  onPress: handleClearEvents,
583
- style: styles.iconButton,
584
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
585
- size: 14,
586
- color: _sharedUi.macOSColors.semantic.error
587
- })
675
+ buttonStyle: styles.iconButton
588
676
  })]
589
677
  })]
590
678
  })]
@@ -621,7 +709,7 @@ const styles = _reactNative.StyleSheet.create({
621
709
  height: 8
622
710
  },
623
711
  listContent: {
624
- paddingVertical: 16
712
+ paddingVertical: 6
625
713
  },
626
714
  lockedBannerContainer: {
627
715
  marginTop: 8,
@@ -58,7 +58,10 @@ export function GameUIStorageBrowser({
58
58
  onTogglePattern,
59
59
  onAddPattern,
60
60
  searchQuery = "",
61
- storageDataRef
61
+ storageDataRef,
62
+ eventCountByKey,
63
+ onViewHistory,
64
+ enabledStorageTypes
62
65
  }) {
63
66
  const isPro = useIsPro();
64
67
  const [showUpgradeModal, setShowUpgradeModal] = useState(false);
@@ -350,7 +353,12 @@ export function GameUIStorageBrowser({
350
353
  const filteredKeys = useMemo(() => {
351
354
  let keys = sortedKeys;
352
355
 
353
- // Apply ignored pattern filter first
356
+ // Apply enabled storage types filter (from parent unified filter)
357
+ if (enabledStorageTypes && enabledStorageTypes.size > 0) {
358
+ keys = keys.filter(k => enabledStorageTypes.has(k.storageType));
359
+ }
360
+
361
+ // Apply ignored pattern filter
354
362
  keys = keys.filter(k => {
355
363
  // Check if key matches any ignored pattern
356
364
  const shouldIgnore = Array.from(ignoredPatterns).some(pattern => k.key.includes(pattern));
@@ -386,7 +394,7 @@ export function GameUIStorageBrowser({
386
394
  // No need to filter again here
387
395
 
388
396
  return keys;
389
- }, [sortedKeys, activeFilter, activeStorageType, ignoredPatterns, searchQuery, selectedMMKVInstance]);
397
+ }, [sortedKeys, activeFilter, activeStorageType, ignoredPatterns, searchQuery, selectedMMKVInstance, enabledStorageTypes]);
390
398
 
391
399
  // For free users, limit visible keys to FREE_TIER_KEY_LIMIT
392
400
  const visibleKeys = useMemo(() => {
@@ -618,7 +626,9 @@ export function GameUIStorageBrowser({
618
626
  emptyMessage: "",
619
627
  isSelectMode: isSelectMode,
620
628
  selectedKeys: selectedKeyIds,
621
- onSelectionChange: handleSelectionChange
629
+ onSelectionChange: handleSelectionChange,
630
+ eventCountByKey: eventCountByKey,
631
+ onViewHistory: onViewHistory
622
632
  }), hasLockedKeys && /*#__PURE__*/_jsxs(TouchableOpacity, {
623
633
  style: styles.limitBanner,
624
634
  onPress: () => setShowUpgradeModal(true),
@@ -13,7 +13,10 @@ export function StorageBrowserMode({
13
13
  onTogglePattern,
14
14
  onAddPattern,
15
15
  searchQuery = "",
16
- storageDataRef
16
+ storageDataRef,
17
+ eventCountByKey,
18
+ onViewHistory,
19
+ enabledStorageTypes
17
20
  }) {
18
21
  return /*#__PURE__*/_jsx(GameUIStorageBrowser, {
19
22
  requiredStorageKeys: requiredStorageKeys,
@@ -22,6 +25,9 @@ export function StorageBrowserMode({
22
25
  onTogglePattern: onTogglePattern,
23
26
  onAddPattern: onAddPattern,
24
27
  searchQuery: searchQuery,
25
- storageDataRef: storageDataRef
28
+ storageDataRef: storageDataRef,
29
+ eventCountByKey: eventCountByKey,
30
+ onViewHistory: onViewHistory,
31
+ enabledStorageTypes: enabledStorageTypes
26
32
  });
27
33
  }