@buoy-gg/redux 7.0.33 → 7.0.34

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.
Files changed (32) hide show
  1. package/lib/commonjs/preset.js +14 -22
  2. package/lib/commonjs/redux/components/ReduxActionInfoView.js +8 -60
  3. package/lib/commonjs/redux/components/ReduxActionItem.js +64 -118
  4. package/lib/commonjs/redux/components/ReduxDetailViewToggle.js +15 -109
  5. package/lib/commonjs/redux/components/ReduxModal.js +24 -69
  6. package/lib/commonjs/redux/hooks/useReduxActions.js +16 -33
  7. package/lib/commonjs/redux/sync/reduxSyncAdapter.js +11 -29
  8. package/lib/commonjs/redux/utils/reduxActionStore.js +24 -94
  9. package/lib/commonjs/redux/utils/snapshotProvider.js +17 -80
  10. package/lib/module/preset.js +13 -20
  11. package/lib/module/redux/components/ReduxActionInfoView.js +1 -53
  12. package/lib/module/redux/components/ReduxActionItem.js +65 -119
  13. package/lib/module/redux/components/ReduxDetailViewToggle.js +17 -111
  14. package/lib/module/redux/components/ReduxModal.js +26 -71
  15. package/lib/module/redux/hooks/useReduxActions.js +17 -34
  16. package/lib/module/redux/sync/reduxSyncAdapter.js +12 -30
  17. package/lib/module/redux/utils/reduxActionStore.js +25 -95
  18. package/lib/module/redux/utils/snapshotProvider.js +18 -81
  19. package/lib/typescript/preset.d.ts +3 -9
  20. package/lib/typescript/preset.d.ts.map +1 -1
  21. package/lib/typescript/redux/components/ReduxActionInfoView.d.ts.map +1 -1
  22. package/lib/typescript/redux/components/ReduxActionItem.d.ts.map +1 -1
  23. package/lib/typescript/redux/components/ReduxDetailViewToggle.d.ts +2 -1
  24. package/lib/typescript/redux/components/ReduxDetailViewToggle.d.ts.map +1 -1
  25. package/lib/typescript/redux/components/ReduxModal.d.ts.map +1 -1
  26. package/lib/typescript/redux/hooks/useReduxActions.d.ts +3 -0
  27. package/lib/typescript/redux/hooks/useReduxActions.d.ts.map +1 -1
  28. package/lib/typescript/redux/sync/reduxSyncAdapter.d.ts +68 -82
  29. package/lib/typescript/redux/sync/reduxSyncAdapter.d.ts.map +1 -1
  30. package/lib/typescript/redux/utils/reduxActionStore.d.ts +2 -29
  31. package/lib/typescript/redux/utils/reduxActionStore.d.ts.map +1 -1
  32. package/package.json +4 -4
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { memo } from "react";
9
9
  import { View, Text, StyleSheet } from "react-native";
10
- import { CompactRow, buoyColors, Zap, AlertCircle, Clock, RelativeTime } from "@buoy-gg/shared-ui";
10
+ import { ChangeRow, buoyColors, AlertCircle } from "@buoy-gg/shared-ui";
11
11
  import { reduxActionStore } from "../utils/reduxActionStore";
12
12
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
13
13
  /**
@@ -236,119 +236,76 @@ export const ReduxActionItem = /*#__PURE__*/memo(function ReduxActionItem({
236
236
  // Get color for this operation's badge
237
237
  const opColor = getOperationColor(operationIndex);
238
238
 
239
- // Custom badge showing state change, slow action, or linked indicator
240
- let customBadge = undefined;
239
+ // The async-sequence chip ("1/2 #3") sits in front of whatever indicator
240
+ // the row shows; the ⚡ / 🕒 indicators and the mono action verb are drawn
241
+ // by the shared ChangeRow.
242
+ const sequenceChip = hasLinkedActions ? /*#__PURE__*/_jsx(View, {
243
+ style: [styles.asyncSequenceBadge, {
244
+ backgroundColor: opColor.bg
245
+ }],
246
+ children: /*#__PURE__*/_jsxs(Text, {
247
+ style: [styles.asyncSequenceText, {
248
+ color: opColor.text
249
+ }],
250
+ testID: testID ? `${testID}-seq` : undefined,
251
+ children: [asyncPosition, "/", linkedCount, " #", operationIndex]
252
+ })
253
+ }) : undefined;
254
+ const common = {
255
+ statusColor,
256
+ statusLabel,
257
+ sublabel,
258
+ primaryText,
259
+ timestamp: action.timestamp,
260
+ onPress: () => onPress(action),
261
+ testID,
262
+ accessibilityLabel: `${primaryText}, ${statusLabel}, ${sublabel}`
263
+ };
241
264
  if (action.isSlowAction) {
242
- // Show slow action warning
243
- customBadge = /*#__PURE__*/_jsxs(View, {
244
- style: styles.badgeContainer,
245
- children: [hasLinkedActions && /*#__PURE__*/_jsx(View, {
246
- style: [styles.asyncSequenceBadge, {
247
- backgroundColor: opColor.bg
248
- }],
249
- children: /*#__PURE__*/_jsxs(Text, {
250
- style: [styles.asyncSequenceText, {
251
- color: opColor.text
252
- }],
253
- testID: testID ? `${testID}-seq` : undefined,
254
- children: [asyncPosition, "/", linkedCount, " #", operationIndex]
255
- })
256
- }), /*#__PURE__*/_jsx(View, {
257
- style: styles.slowBadge,
258
- testID: testID ? `${testID}-slow` : undefined,
259
- children: /*#__PURE__*/_jsx(Clock, {
260
- size: 12,
261
- color: buoyColors.error
262
- })
263
- })]
265
+ // Slow action warning (with the sequence chip when part of a flow).
266
+ return /*#__PURE__*/_jsx(ChangeRow, {
267
+ ...common,
268
+ badgePrefix: sequenceChip,
269
+ slow: true
264
270
  });
265
- } else if (action.category === "rejected") {
266
- // Show error badge for rejected actions
267
- customBadge = /*#__PURE__*/_jsxs(View, {
268
- style: styles.badgeContainer,
269
- children: [hasLinkedActions && /*#__PURE__*/_jsx(View, {
270
- style: [styles.asyncSequenceBadge, {
271
- backgroundColor: opColor.bg
272
- }],
273
- children: /*#__PURE__*/_jsxs(Text, {
274
- style: [styles.asyncSequenceText, {
275
- color: opColor.text
276
- }],
277
- testID: testID ? `${testID}-seq` : undefined,
278
- children: [asyncPosition, "/", linkedCount, " #", operationIndex]
279
- })
280
- }), /*#__PURE__*/_jsx(View, {
281
- style: styles.errorBadge,
282
- testID: testID ? `${testID}-error` : undefined,
283
- children: /*#__PURE__*/_jsx(AlertCircle, {
284
- size: 12,
285
- color: buoyColors.error
286
- })
287
- })]
271
+ }
272
+ if (action.category === "rejected") {
273
+ // Error badge for rejected actions.
274
+ return /*#__PURE__*/_jsx(ChangeRow, {
275
+ ...common,
276
+ customBadge: /*#__PURE__*/_jsxs(View, {
277
+ style: styles.badgeContainer,
278
+ children: [sequenceChip, /*#__PURE__*/_jsx(View, {
279
+ style: styles.errorBadge,
280
+ testID: testID ? `${testID}-error` : undefined,
281
+ children: /*#__PURE__*/_jsx(AlertCircle, {
282
+ size: 12,
283
+ color: buoyColors.error
284
+ })
285
+ })]
286
+ })
288
287
  });
289
- } else if (hasLinkedActions) {
290
- // Show linked indicator for async actions
291
- customBadge = /*#__PURE__*/_jsxs(View, {
292
- style: styles.badgeContainer,
293
- children: [/*#__PURE__*/_jsx(View, {
294
- style: [styles.asyncSequenceBadge, {
295
- backgroundColor: opColor.bg
296
- }],
297
- children: /*#__PURE__*/_jsxs(Text, {
298
- style: [styles.asyncSequenceText, {
299
- color: opColor.text
300
- }],
301
- testID: testID ? `${testID}-seq` : undefined,
302
- children: [asyncPosition, "/", linkedCount, " #", operationIndex]
303
- })
304
- }), action.hasStateChange && /*#__PURE__*/_jsx(View, {
305
- style: styles.changeBadge,
306
- testID: testID ? `${testID}-change` : undefined,
307
- children: /*#__PURE__*/_jsx(Zap, {
308
- size: 12,
309
- color: buoyColors.warning
310
- })
311
- })]
288
+ }
289
+ if (hasLinkedActions) {
290
+ // Linked indicator for async actions.
291
+ return /*#__PURE__*/_jsx(ChangeRow, {
292
+ ...common,
293
+ badgePrefix: sequenceChip,
294
+ changed: action.hasStateChange
312
295
  });
313
- } else if (action.hasStateChange) {
314
- // Show state change indicator with action badge
315
- customBadge = /*#__PURE__*/_jsxs(View, {
316
- style: styles.badgeContainer,
317
- children: [/*#__PURE__*/_jsx(Text, {
318
- style: [styles.actionBadgeText, {
319
- color: statusColor
320
- }],
321
- testID: testID ? `${testID}-badge` : undefined,
322
- children: actionBadge
323
- }), /*#__PURE__*/_jsx(View, {
324
- style: styles.changeBadge,
325
- testID: testID ? `${testID}-change` : undefined,
326
- children: /*#__PURE__*/_jsx(Zap, {
327
- size: 12,
328
- color: buoyColors.warning
329
- })
330
- })]
296
+ }
297
+ if (action.hasStateChange) {
298
+ // State change indicator with the action verb.
299
+ return /*#__PURE__*/_jsx(ChangeRow, {
300
+ ...common,
301
+ badgeText: actionBadge,
302
+ changed: true
331
303
  });
332
304
  }
333
- return /*#__PURE__*/_jsx(CompactRow, {
334
- testID: testID,
335
- statusTestID: testID ? `${testID}-status` : undefined,
336
- statusSublabelTestID: testID ? `${testID}-sublabel` : undefined,
337
- accessibilityLabel: `${primaryText}, ${statusLabel}, ${sublabel}`,
338
- statusDotColor: statusColor,
339
- statusLabel: statusLabel,
340
- statusSublabel: sublabel,
341
- primaryText: primaryText,
342
- bottomRightText: /*#__PURE__*/_jsx(RelativeTime, {
343
- timestamp: action.timestamp
344
- })
345
- // Use customBadge if we have special indicators, otherwise show action badge as text
346
- ,
347
- customBadge: customBadge,
348
- badgeText: customBadge ? undefined : actionBadge,
349
- badgeColor: statusColor,
350
- showChevron: true,
351
- onPress: () => onPress(action)
305
+ // Nothing special: CompactRow's plain badge with the action verb.
306
+ return /*#__PURE__*/_jsx(ChangeRow, {
307
+ ...common,
308
+ plainBadgeText: actionBadge
352
309
  });
353
310
  });
354
311
  const styles = StyleSheet.create({
@@ -357,17 +314,6 @@ const styles = StyleSheet.create({
357
314
  alignItems: "center",
358
315
  gap: 4
359
316
  },
360
- actionBadgeText: {
361
- fontSize: 11,
362
- fontWeight: "600",
363
- fontFamily: "monospace"
364
- },
365
- changeBadge: {
366
- paddingHorizontal: 4
367
- },
368
- slowBadge: {
369
- paddingHorizontal: 4
370
- },
371
317
  errorBadge: {
372
318
  paddingHorizontal: 4
373
319
  },
@@ -4,136 +4,42 @@
4
4
  * ReduxDetailViewToggle
5
5
  *
6
6
  * Three-card toggle for switching between Action, State, and Diff views.
7
- * Redux-specific component for the enhanced detail view.
7
+ * The cards themselves are the shared `DetailViewToggle`; this file owns
8
+ * the redux view list and testID prefix.
8
9
  */
9
10
 
10
11
  import React, { memo } from "react";
11
- import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
12
- import { night, FileText, Database, GitBranch } from "@buoy-gg/shared-ui";
13
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
- const VIEW_CONFIGS = [{
12
+ import { DetailViewToggle, FileText, Database, GitBranch } from "@buoy-gg/shared-ui";
13
+ import { jsx as _jsx } from "react/jsx-runtime";
14
+ // Active-card chrome takes the single night accent (the per-view
15
+ // warning/info/success tints were selection chrome, not data).
16
+ const VIEWS = [{
15
17
  key: "action",
16
18
  label: "ACTION",
17
19
  description: "View action details",
18
- icon: FileText,
19
- // Active-card chrome takes the single night accent (the per-view
20
- // warning/info/success tints were selection chrome, not data).
21
- activeColor: night.color.accent
20
+ icon: FileText
22
21
  }, {
23
22
  key: "state",
24
23
  label: "STATE",
25
24
  description: "View current state",
26
- icon: Database,
27
- activeColor: night.color.accent
25
+ icon: Database
28
26
  }, {
29
27
  key: "diff",
30
28
  label: "DIFF",
31
29
  description: "Compare changes",
32
- icon: GitBranch,
33
- activeColor: night.color.accent
30
+ icon: GitBranch
34
31
  }];
32
+ const DIFF_DISABLED = ["diff"];
35
33
  export const ReduxDetailViewToggle = /*#__PURE__*/memo(function ReduxDetailViewToggle({
36
34
  activeView,
37
35
  onViewChange,
38
36
  diffDisabled = false
39
37
  }) {
40
- return /*#__PURE__*/_jsx(View, {
41
- style: styles.container,
42
- children: VIEW_CONFIGS.map(config => {
43
- const isActive = activeView === config.key;
44
- const isDisabled = config.key === "diff" && diffDisabled;
45
- const IconComponent = config.icon;
46
- return /*#__PURE__*/_jsxs(TouchableOpacity, {
47
- style: [styles.card, isActive && [styles.cardActive, {
48
- borderColor: config.activeColor
49
- }], isDisabled && styles.cardDisabled],
50
- onPress: () => !isDisabled && onViewChange(config.key),
51
- activeOpacity: isDisabled ? 1 : 0.8,
52
- disabled: isDisabled,
53
- testID: `buoy-redux-view-${config.key}`,
54
- accessibilityRole: "button",
55
- accessibilityLabel: config.label,
56
- accessibilityState: {
57
- selected: isActive,
58
- disabled: isDisabled
59
- },
60
- children: [/*#__PURE__*/_jsxs(View, {
61
- style: styles.cardContent,
62
- children: [/*#__PURE__*/_jsx(IconComponent, {
63
- size: 14,
64
- color: isActive ? config.activeColor : isDisabled ? night.color.textTertiary : night.color.textSecondary
65
- }), /*#__PURE__*/_jsx(Text, {
66
- style: [styles.cardLabel, isActive && [styles.cardLabelActive, {
67
- color: config.activeColor
68
- }], isDisabled && styles.cardLabelDisabled],
69
- children: config.label
70
- })]
71
- }), /*#__PURE__*/_jsx(Text, {
72
- style: [styles.cardDescription, isActive && styles.cardDescriptionActive, isDisabled && styles.cardDescriptionDisabled],
73
- children: config.description
74
- })]
75
- }, config.key);
76
- })
38
+ return /*#__PURE__*/_jsx(DetailViewToggle, {
39
+ views: VIEWS,
40
+ activeView: activeView,
41
+ onViewChange: onViewChange,
42
+ disabledKeys: diffDisabled ? DIFF_DISABLED : undefined,
43
+ testIDPrefix: "buoy-redux"
77
44
  });
78
- });
79
- const styles = StyleSheet.create({
80
- container: {
81
- flexDirection: "row",
82
- gap: 8,
83
- padding: 14,
84
- // Transparent so the night sheet's star field shows through.
85
- backgroundColor: "transparent"
86
- },
87
- card: {
88
- flex: 1,
89
- backgroundColor: night.color.surface,
90
- borderRadius: 12,
91
- borderWidth: 1,
92
- borderColor: night.color.border,
93
- padding: 10,
94
- gap: 4
95
- },
96
- cardActive: {
97
- borderWidth: 1.5,
98
- backgroundColor: night.color.accentSoft,
99
- shadowColor: night.color.accent,
100
- shadowOffset: {
101
- width: 0,
102
- height: 2
103
- },
104
- shadowOpacity: 0.1,
105
- shadowRadius: 8,
106
- elevation: 3
107
- },
108
- cardDisabled: {
109
- opacity: 0.5
110
- },
111
- cardContent: {
112
- flexDirection: "row",
113
- alignItems: "center",
114
- gap: 6
115
- },
116
- cardLabel: {
117
- fontSize: 10,
118
- fontWeight: "700",
119
- letterSpacing: 0.5,
120
- color: night.color.textSecondary
121
- },
122
- cardLabelActive: {
123
- color: night.color.text
124
- },
125
- cardLabelDisabled: {
126
- color: night.color.textTertiary
127
- },
128
- cardDescription: {
129
- fontSize: 9,
130
- color: night.color.textTertiary,
131
- lineHeight: 12
132
- },
133
- cardDescriptionActive: {
134
- color: night.color.textSecondary
135
- },
136
- cardDescriptionDisabled: {
137
- color: night.color.textTertiary
138
- }
139
45
  });
@@ -8,8 +8,8 @@
8
8
  */
9
9
 
10
10
  import { useState, useMemo, useRef, useCallback, useEffect } from "react";
11
- import { View, Text, StyleSheet, FlatList, TextInput, TouchableOpacity } from "react-native";
12
- import { JsModal, ModalHeader, macOSColors, night, Search, Trash2, Power, X, Zap, CheckCircle, Copy, Lock, AlertTriangle, devToolsStorageKeys, copyToClipboard, ProUpgradeModal, PowerToggleButton, TickProvider, useLimit, TIER_LIMITS, windowDragProps, ToolEmptyState, resolveListEmptyState } from "@buoy-gg/shared-ui";
11
+ import { View, Text, StyleSheet, FlatList, TouchableOpacity } from "react-native";
12
+ import { JsModal, ModalHeader, macOSColors, night, Search, Trash2, Power, Zap, CheckCircle, Copy, Lock, AlertTriangle, devToolsStorageKeys, copyToClipboard, ProUpgradeModal, PowerToggleButton, TickProvider, useLimit, TIER_LIMITS, windowDragProps, ToolEmptyState, resolveListEmptyState, EVENT_LIST_PRESET } from "@buoy-gg/shared-ui";
13
13
  import { useIsPro } from "@buoy-gg/license";
14
14
  import { useReduxActions } from "../hooks/useReduxActions";
15
15
  import { reduxActionStore } from "../utils/reduxActionStore";
@@ -266,49 +266,29 @@ export function ReduxModal({
266
266
  onBack: onBack
267
267
  }), /*#__PURE__*/_jsx(ModalHeader.Content, {
268
268
  title: "",
269
- children: isSearchActive ? /*#__PURE__*/_jsxs(View, {
270
- style: styles.headerSearchContainer,
271
- testID: `${REDUX_TEST_ID}-search`,
272
- children: [/*#__PURE__*/_jsx(Search, {
273
- size: 14,
274
- color: night.color.textSecondary
275
- }), /*#__PURE__*/_jsx(TextInput, {
276
- ref: searchInputRef,
277
- testID: `${REDUX_TEST_ID}-search-field`,
278
- style: styles.headerSearchInput,
279
- placeholder: "Search action types...",
280
- placeholderTextColor: night.color.textTertiary,
281
- value: searchText,
282
- onChangeText: handleSearch,
283
- onSubmitEditing: () => searchInputRef.current?.blur()
284
- // Stay open while the query still filters the list.
285
- //
286
- // Collapsing it on blur hid the reason rows were missing: the
287
- // header went back to its chips — which count the WHOLE
288
- // capture, not the filtered list — while the list stayed
289
- // narrowed, so the tool showed "4 actions" above a single row
290
- // and offered nothing to explain the gap. The only way back
291
- // was to reopen a field the user had no reason to think was
292
- // still armed.
293
- ,
294
- onBlur: () => {
295
- if (searchText.length === 0) setIsSearchActive(false);
296
- },
297
- accessibilityLabel: "Search action types",
298
- autoCapitalize: "none",
299
- autoCorrect: false,
300
- returnKeyType: "search"
301
- }), /*#__PURE__*/_jsx(TouchableOpacity, {
302
- onPress: closeSearch,
303
- style: styles.headerSearchClear,
304
- testID: `${REDUX_TEST_ID}-search-clear`,
305
- accessibilityRole: "button",
306
- accessibilityLabel: "Close search",
307
- children: /*#__PURE__*/_jsx(X, {
308
- size: 14,
309
- color: night.color.textSecondary
310
- })
311
- })]
269
+ children: isSearchActive ? /*#__PURE__*/_jsx(ModalHeader.Search, {
270
+ value: searchText,
271
+ onChangeText: handleSearch,
272
+ onCancel: closeSearch,
273
+ placeholder: "Search action types...",
274
+ accessibilityLabel: "Search action types",
275
+ iconSize: 14,
276
+ testID: `${REDUX_TEST_ID}-search-field`,
277
+ containerTestID: `${REDUX_TEST_ID}-search`,
278
+ clearTestID: `${REDUX_TEST_ID}-search-clear`
279
+ // Stay open while the query still filters the list.
280
+ //
281
+ // Collapsing it on blur hid the reason rows were missing: the
282
+ // header went back to its chips — which count the WHOLE
283
+ // capture, not the filtered list — while the list stayed
284
+ // narrowed, so the tool showed "4 actions" above a single row
285
+ // and offered nothing to explain the gap. The only way back
286
+ // was to reopen a field the user had no reason to think was
287
+ // still armed.
288
+ ,
289
+ onBlur: () => {
290
+ if (searchText.length === 0) setIsSearchActive(false);
291
+ }
312
292
  }) : /*#__PURE__*/_jsxs(View, {
313
293
  style: styles.headerChipRow,
314
294
  children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
@@ -503,11 +483,7 @@ export function ReduxModal({
503
483
  keyExtractor: keyExtractor,
504
484
  contentContainerStyle: styles.listContent,
505
485
  showsVerticalScrollIndicator: true,
506
- removeClippedSubviews: true,
507
- initialNumToRender: 12,
508
- maxToRenderPerBatch: 8,
509
- windowSize: 5,
510
- updateCellsBatchingPeriod: 50
486
+ ...EVENT_LIST_PRESET
511
487
  }) : /*#__PURE__*/_jsx(EmptyState, {
512
488
  isEnabled: isEnabled,
513
489
  query: searchText,
@@ -593,27 +569,6 @@ const styles = StyleSheet.create({
593
569
  // Transparent so JsModal's ToolBackground shows through (the modal paints opaque base beneath it).
594
570
  backgroundColor: "transparent"
595
571
  },
596
- headerSearchContainer: {
597
- flexDirection: "row",
598
- alignItems: "center",
599
- backgroundColor: night.color.surfaceElevated,
600
- borderRadius: 10,
601
- borderWidth: 1,
602
- borderColor: night.color.border,
603
- paddingHorizontal: 12,
604
- paddingVertical: 5
605
- },
606
- headerSearchInput: {
607
- flex: 1,
608
- color: night.color.text,
609
- fontSize: 13,
610
- marginLeft: 6,
611
- paddingVertical: 2
612
- },
613
- headerSearchClear: {
614
- marginLeft: 6,
615
- padding: 4
616
- },
617
572
  headerChipRow: {
618
573
  flexDirection: "row",
619
574
  alignItems: "center",
@@ -2,40 +2,30 @@
2
2
 
3
3
  /**
4
4
  * Hook for consuming Redux actions from the store
5
+ *
6
+ * The subscribe / filter / pause / clear plumbing is shared `useChangeLog`;
7
+ * this file owns the redux-specific stats, action types and selection.
5
8
  */
6
9
 
7
- import { useState, useEffect, useMemo, useCallback } from "react";
10
+ import { useState, useMemo, useCallback } from "react";
11
+ import { useChangeLog } from "@buoy-gg/shared-ui";
8
12
  import { reduxActionStore } from "../utils/reduxActionStore";
13
+ const filterActions = (_actions, filter) => reduxActionStore.filterActions(filter);
9
14
  export function useReduxActions() {
10
- const [actions, setActions] = useState(() => reduxActionStore.getActions());
11
- const [filter, setFilter] = useState({});
12
- const [isEnabled, setIsEnabled] = useState(() => reduxActionStore.getEnabled());
15
+ const log = useChangeLog(reduxActionStore, {
16
+ filterItems: filterActions
17
+ });
13
18
  const [selectedAction, setSelectedAction] = useState(null);
14
19
 
15
- // Subscribe to store changes
16
- useEffect(() => {
17
- const unsubscribe = reduxActionStore.subscribe(newActions => {
18
- setActions(newActions);
19
- });
20
- return () => {
21
- unsubscribe();
22
- };
23
- }, []);
24
-
25
- // Filter actions based on current filter
26
- const filteredActions = useMemo(() => {
27
- return reduxActionStore.filterActions(filter);
28
- }, [actions, filter]);
29
-
30
20
  // Get stats
31
21
  const stats = useMemo(() => {
32
22
  return reduxActionStore.getStats();
33
- }, [actions]);
23
+ }, [log.items]);
34
24
 
35
25
  // Get unique action types
36
26
  const actionTypes = useMemo(() => {
37
27
  return reduxActionStore.getUniqueActionTypes();
38
- }, [actions]);
28
+ }, [log.items]);
39
29
 
40
30
  // Clear actions
41
31
  const clearActions = useCallback(() => {
@@ -43,26 +33,19 @@ export function useReduxActions() {
43
33
  setSelectedAction(null);
44
34
  }, []);
45
35
 
46
- // Toggle capture
47
- const toggleCapture = useCallback(() => {
48
- const newEnabled = !isEnabled;
49
- reduxActionStore.setEnabled(newEnabled);
50
- setIsEnabled(newEnabled);
51
- }, [isEnabled]);
52
-
53
36
  // Get action by ID
54
37
  const getActionById = useCallback(id => {
55
38
  return reduxActionStore.getActionById(id);
56
39
  }, []);
57
40
  return {
58
- actions,
59
- filteredActions,
60
- filter,
61
- setFilter,
41
+ actions: log.items,
42
+ filteredActions: log.filteredItems,
43
+ filter: log.filter,
44
+ setFilter: log.setFilter,
62
45
  stats,
63
46
  clearActions,
64
- isEnabled,
65
- toggleCapture,
47
+ isEnabled: log.isEnabled,
48
+ toggleCapture: log.toggleCapture,
66
49
  actionTypes,
67
50
  getActionById,
68
51
  selectedAction,