@buoy-gg/redux 2.1.9 → 2.1.11

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 (63) hide show
  1. package/lib/commonjs/index.js +179 -1
  2. package/lib/commonjs/preset.js +98 -1
  3. package/lib/commonjs/redux/components/ReduxActionButton.js +129 -1
  4. package/lib/commonjs/redux/components/ReduxActionDetailContent.js +380 -1
  5. package/lib/commonjs/redux/components/ReduxActionDetailView.js +401 -1
  6. package/lib/commonjs/redux/components/ReduxActionInfoView.js +838 -1
  7. package/lib/commonjs/redux/components/ReduxActionItem.js +366 -1
  8. package/lib/commonjs/redux/components/ReduxDetailViewToggle.js +134 -1
  9. package/lib/commonjs/redux/components/ReduxIcon.js +18 -1
  10. package/lib/commonjs/redux/components/ReduxModal.js +530 -1
  11. package/lib/commonjs/redux/components/index.js +52 -1
  12. package/lib/commonjs/redux/hooks/index.js +25 -1
  13. package/lib/commonjs/redux/hooks/useAutoInstrumentRedux.js +197 -1
  14. package/lib/commonjs/redux/hooks/useReduxActions.js +75 -1
  15. package/lib/commonjs/redux/index.js +49 -1
  16. package/lib/commonjs/redux/utils/autoInstrument.js +270 -1
  17. package/lib/commonjs/redux/utils/buoyReduxMiddleware.js +166 -1
  18. package/lib/commonjs/redux/utils/createReduxHistoryAdapter.js +146 -1
  19. package/lib/commonjs/redux/utils/index.js +111 -1
  20. package/lib/commonjs/redux/utils/reduxActionStore.js +358 -1
  21. package/lib/module/index.js +87 -1
  22. package/lib/module/preset.js +94 -1
  23. package/lib/module/redux/components/ReduxActionButton.js +126 -1
  24. package/lib/module/redux/components/ReduxActionDetailContent.js +376 -1
  25. package/lib/module/redux/components/ReduxActionDetailView.js +397 -1
  26. package/lib/module/redux/components/ReduxActionInfoView.js +833 -1
  27. package/lib/module/redux/components/ReduxActionItem.js +362 -1
  28. package/lib/module/redux/components/ReduxDetailViewToggle.js +129 -1
  29. package/lib/module/redux/components/ReduxIcon.js +8 -1
  30. package/lib/module/redux/components/ReduxModal.js +525 -1
  31. package/lib/module/redux/components/index.js +7 -1
  32. package/lib/module/redux/hooks/index.js +4 -1
  33. package/lib/module/redux/hooks/useAutoInstrumentRedux.js +193 -1
  34. package/lib/module/redux/hooks/useReduxActions.js +71 -1
  35. package/lib/module/redux/index.js +13 -1
  36. package/lib/module/redux/utils/autoInstrument.js +260 -1
  37. package/lib/module/redux/utils/buoyReduxMiddleware.js +157 -1
  38. package/lib/module/redux/utils/createReduxHistoryAdapter.js +142 -1
  39. package/lib/module/redux/utils/index.js +8 -1
  40. package/lib/module/redux/utils/reduxActionStore.js +354 -1
  41. package/lib/typescript/index.d.ts.map +1 -0
  42. package/lib/typescript/preset.d.ts.map +1 -0
  43. package/lib/typescript/redux/components/ReduxActionButton.d.ts.map +1 -0
  44. package/lib/typescript/redux/components/ReduxActionDetailContent.d.ts.map +1 -0
  45. package/lib/typescript/redux/components/ReduxActionDetailView.d.ts.map +1 -0
  46. package/lib/typescript/redux/components/ReduxActionInfoView.d.ts.map +1 -0
  47. package/lib/typescript/redux/components/ReduxActionItem.d.ts.map +1 -0
  48. package/lib/typescript/redux/components/ReduxDetailViewToggle.d.ts.map +1 -0
  49. package/lib/typescript/redux/components/ReduxIcon.d.ts.map +1 -0
  50. package/lib/typescript/redux/components/ReduxModal.d.ts.map +1 -0
  51. package/lib/typescript/redux/components/index.d.ts.map +1 -0
  52. package/lib/typescript/redux/hooks/index.d.ts.map +1 -0
  53. package/lib/typescript/redux/hooks/useAutoInstrumentRedux.d.ts.map +1 -0
  54. package/lib/typescript/redux/hooks/useReduxActions.d.ts.map +1 -0
  55. package/lib/typescript/redux/index.d.ts.map +1 -0
  56. package/lib/typescript/redux/types/index.d.ts.map +1 -0
  57. package/lib/typescript/redux/utils/autoInstrument.d.ts.map +1 -0
  58. package/lib/typescript/redux/utils/buoyReduxMiddleware.d.ts.map +1 -0
  59. package/lib/typescript/redux/utils/createReduxHistoryAdapter.d.ts.map +1 -0
  60. package/lib/typescript/redux/utils/index.d.ts.map +1 -0
  61. package/lib/typescript/redux/utils/reduxActionStore.d.ts.map +1 -0
  62. package/package.json +12 -12
  63. package/LICENSE +0 -58
@@ -1 +1,833 @@
1
- "use strict";import React,{memo,useMemo,useCallback,useState,useEffect}from"react";import{View,Text,StyleSheet,ScrollView,TouchableOpacity}from"react-native";import{buoyColors,Clock,AlertTriangle,Zap,Hash,Info,Box,AlertCircle,FileText,parseValue,ProUpgradeModal,copyToClipboard}from"@buoy-gg/shared-ui";import{useIsPro}from"@buoy-gg/license";import{DataViewer}from"@buoy-gg/shared-ui/dataViewer";import{reduxActionStore}from"../utils/reduxActionStore";import{jumpToState,replayAction}from"../utils/buoyReduxMiddleware";import{ReduxActionButton}from"./ReduxActionButton";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";function getCategoryInfo(e){switch(e){case"pending":return{label:"PENDING",color:buoyColors.warning,bgColor:buoyColors.warning+"26"};case"fulfilled":return{label:"FULFILLED",color:buoyColors.success,bgColor:buoyColors.success+"26"};case"rejected":return{label:"REJECTED",color:buoyColors.error,bgColor:buoyColors.error+"26"};case"internal":return{label:"INTERNAL",color:buoyColors.textMuted,bgColor:buoyColors.textMuted+"26"};case"query":return{label:"QUERY",color:buoyColors.info,bgColor:buoyColors.info+"26"};case"mutation":return{label:"MUTATION",color:buoyColors.info,bgColor:buoyColors.info+"26"};default:return{label:"ACTION",color:buoyColors.info,bgColor:buoyColors.info+"26"}}}function formatDuration(e){return void 0===e?"N/A":e<1?"<1ms":`${e.toFixed(1)}ms`}function SectionHeader({icon:e,title:o,badge:t}){return _jsxs(View,{style:styles.sectionHeader,children:[_jsxs(View,{style:styles.sectionHeaderLeft,children:[_jsx(e,{size:14,color:buoyColors.primary}),_jsx(Text,{style:styles.sectionTitle,children:o})]}),t]})}function InfoRow({label:e,value:o,valueColor:t,mono:r=!1}){return _jsxs(View,{style:styles.infoRow,children:[_jsx(Text,{style:styles.infoLabel,children:e}),_jsx(Text,{style:[styles.infoValue,r&&styles.infoValueMono,t&&{color:t}],numberOfLines:1,ellipsizeMode:"middle",children:o})]})}function formatTime(e){const o=new Date(e);return`${o.getHours().toString().padStart(2,"0")}:${o.getMinutes().toString().padStart(2,"0")}:${o.getSeconds().toString().padStart(2,"0")}.${o.getMilliseconds().toString().padStart(3,"0")}`}export const ReduxActionInfoView=memo(function({action:e,onNavigateToAction:o}){const t=useIsPro(),[r,l]=useState(!1);useEffect(()=>{r&&t&&l(!1)},[r,t]);const s=getCategoryInfo(e.category),i=void 0!==e.payload,a=e.meta&&Object.keys(e.meta).length>0,n=void 0!==e.error,c=useMemo(()=>reduxActionStore.getLinkedActions(e),[e]),d=c.length>1,y=d?reduxActionStore.getBaseActionType(e.type):null,u=e.meta?.requestId?reduxActionStore.getAsyncOperationDuration(e.meta.requestId):null,g=useCallback(async()=>{t?await copyToClipboard(e.action):l(!0)},[e,t]),x=useCallback(async()=>{t?await copyToClipboard(e.payload):l(!0)},[e.payload,t]),b=useCallback(()=>{e.action&&"object"==typeof e.action&&"type"in e.action&&replayAction(e.action)},[e]),p=useCallback(()=>{void 0!==e.nextState&&jumpToState(e.nextState)},[e]);return _jsxs(ScrollView,{style:styles.container,contentContainerStyle:styles.contentContainer,showsVerticalScrollIndicator:!1,children:[_jsxs(View,{style:styles.card,children:[_jsx(SectionHeader,{icon:Info,title:"ACTION INFO"}),_jsxs(View,{style:styles.cardContent,children:[_jsx(InfoRow,{label:"Type",value:e.type,mono:!0}),e.sliceName&&_jsx(InfoRow,{label:"Slice",value:e.sliceName,mono:!0}),_jsx(InfoRow,{label:"Action",value:e.actionName,mono:!0}),_jsxs(View,{style:styles.badgeRow,children:[_jsx(View,{style:[styles.categoryBadge,{backgroundColor:s.bgColor}],children:_jsx(Text,{style:[styles.categoryText,{color:s.color}],children:s.label})}),_jsxs(View,{style:[styles.durationBadge,e.isSlowAction&&styles.durationBadgeSlow],children:[_jsx(Clock,{size:10,color:e.isSlowAction?buoyColors.error:buoyColors.textSecondary}),_jsx(Text,{style:[styles.durationText,e.isSlowAction&&styles.durationTextSlow],children:formatDuration(e.duration)}),e.isSlowAction&&_jsx(AlertTriangle,{size:10,color:buoyColors.error})]}),e.hasStateChange?_jsxs(View,{style:styles.changesBadge,children:[_jsx(Zap,{size:10,color:buoyColors.success}),_jsx(Text,{style:styles.changesText,children:e.diffSummary||"changed"})]}):_jsx(View,{style:styles.noChangesBadge,children:_jsx(Text,{style:styles.noChangesText,children:"no change"})})]})]})]}),d&&_jsxs(View,{style:styles.card,children:[_jsx(SectionHeader,{icon:Hash,title:"ASYNC FLOW",badge:_jsx(View,{style:styles.asyncBadge,children:_jsxs(Text,{style:styles.asyncBadgeText,children:[c.length," ACTIONS"]})})}),_jsxs(View,{style:styles.cardContent,children:[_jsx(Text,{style:styles.baseActionType,children:y}),null!==u&&_jsxs(View,{style:styles.totalDurationRow,children:[_jsx(Text,{style:styles.totalDurationLabel,children:"Total Duration"}),_jsxs(Text,{style:styles.totalDurationValue,children:[u,"ms"]})]}),_jsx(View,{style:styles.timeline,children:c.map((t,r)=>{const l=getCategoryInfo(t.category),s=t.id===e.id;return _jsxs(TouchableOpacity,{style:[styles.timelineItem,s&&styles.timelineItemCurrent],onPress:()=>o?.(t),disabled:s||!o,activeOpacity:.7,children:[r<c.length-1&&_jsx(View,{style:styles.timelineConnector}),_jsx(View,{style:[styles.timelineDot,{backgroundColor:l.color}]}),_jsxs(View,{style:styles.timelineContent,children:[_jsxs(View,{style:styles.timelineHeader,children:[_jsx(View,{style:[styles.timelineStatusBadge,{backgroundColor:l.bgColor}],children:_jsx(Text,{style:[styles.timelineStatusText,{color:l.color}],children:l.label})}),s&&_jsx(View,{style:styles.currentBadge,children:_jsx(Text,{style:styles.currentBadgeText,children:"CURRENT"})})]}),_jsx(Text,{style:styles.timelineTime,children:formatTime(t.timestamp)})]})]},t.id)})})]})]}),i&&_jsxs(View,{style:styles.card,children:[_jsx(SectionHeader,{icon:Box,title:"PAYLOAD",badge:_jsx(View,{style:styles.typeBadge,children:_jsx(Text,{style:styles.typeText,children:Array.isArray(e.payload)?"ARRAY":"object"==typeof e.payload?"OBJECT":typeof e.payload?.toString().toUpperCase()})})}),_jsx(View,{style:styles.dataViewerContainer,children:_jsx(DataViewer,{title:"",data:parseValue(e.payload),showTypeFilter:!1})})]}),a&&_jsxs(View,{style:styles.card,children:[_jsx(SectionHeader,{icon:Hash,title:"ASYNC METADATA",badge:_jsx(View,{style:[styles.categoryBadge,{backgroundColor:s.bgColor}],children:_jsx(Text,{style:[styles.categoryText,{color:s.color}],children:"RTK THUNK"})})}),_jsxs(View,{style:styles.cardContent,children:[e.meta?.requestId&&_jsx(InfoRow,{label:"Request ID",value:e.meta.requestId,mono:!0}),e.meta?.requestStatus&&_jsx(InfoRow,{label:"Status",value:e.meta.requestStatus.toUpperCase(),valueColor:s.color}),void 0!==e.meta?.arg&&_jsxs(View,{style:styles.argSection,children:[_jsx(Text,{style:styles.argLabel,children:"Original Argument"}),_jsx(View,{style:styles.argValueContainer,children:"object"==typeof e.meta.arg?_jsx(DataViewer,{title:"",data:parseValue(e.meta.arg),showTypeFilter:!1}):_jsx(Text,{style:styles.argValue,children:JSON.stringify(e.meta.arg)})})]}),e.meta?.rejectedWithValue&&_jsx(InfoRow,{label:"Rejected With Value",value:"true",valueColor:buoyColors.error}),e.meta?.aborted&&_jsx(InfoRow,{label:"Aborted",value:"true",valueColor:buoyColors.warning}),e.meta?.condition&&_jsx(InfoRow,{label:"Condition",value:"true",valueColor:buoyColors.textMuted})]})]}),n&&_jsxs(View,{style:[styles.card,styles.errorCard],children:[_jsx(SectionHeader,{icon:AlertCircle,title:"ERROR",badge:_jsx(View,{style:styles.errorBadge,children:_jsx(Text,{style:styles.errorBadgeText,children:"REJECTED"})})}),_jsx(View,{style:styles.dataViewerContainer,children:"object"==typeof e.error?_jsx(DataViewer,{title:"",data:parseValue(e.error),showTypeFilter:!1}):_jsx(Text,{style:styles.errorText,children:String(e.error)})})]}),_jsxs(View,{style:styles.card,children:[_jsx(SectionHeader,{icon:FileText,title:"FULL ACTION OBJECT"}),_jsx(View,{style:styles.dataViewerContainer,children:_jsx(DataViewer,{title:"",data:parseValue(e.action),showTypeFilter:!1})})]}),_jsx(View,{style:styles.actionFooter,children:_jsxs(View,{style:styles.actionsGrid,children:[_jsxs(View,{style:styles.actionButtonWrapper,children:[_jsx(ReduxActionButton,{type:"replay",text:"REPLAY",onPress:b}),_jsx(Text,{style:styles.actionDescription,children:"Dispatch again"})]}),_jsxs(View,{style:styles.actionButtonWrapper,children:[_jsx(ReduxActionButton,{type:"jump",text:"JUMP",onPress:p}),_jsx(Text,{style:styles.actionDescription,children:"Restore this state"})]}),_jsxs(View,{style:styles.actionButtonWrapper,children:[_jsx(ReduxActionButton,{type:"copy",text:"COPY ACTION",onPress:g}),_jsx(Text,{style:styles.actionDescription,children:t?"Copy to clipboard":"Pro feature"})]}),i&&_jsxs(View,{style:styles.actionButtonWrapper,children:[_jsx(ReduxActionButton,{type:"copy",text:"COPY PAYLOAD",onPress:x}),_jsx(Text,{style:styles.actionDescription,children:t?"Copy payload only":"Pro feature"})]})]})}),_jsx(ProUpgradeModal,{visible:r,onClose:()=>l(!1),featureName:"Copy"})]})});const styles=StyleSheet.create({container:{flex:1},contentContainer:{padding:8,paddingBottom:100,gap:16},card:{backgroundColor:buoyColors.card,borderRadius:6,borderWidth:1,borderColor:buoyColors.primary+"4D",overflow:"hidden",shadowColor:buoyColors.primary,shadowOffset:{width:0,height:0},shadowOpacity:.1,shadowRadius:6},errorCard:{borderColor:buoyColors.error+"4D",shadowColor:buoyColors.error},sectionHeader:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",paddingHorizontal:12,paddingVertical:10,borderBottomWidth:1,borderBottomColor:buoyColors.primary+"33",backgroundColor:buoyColors.primary+"15"},sectionHeaderLeft:{flexDirection:"row",alignItems:"center",gap:6},sectionTitle:{fontSize:12,fontWeight:"600",letterSpacing:.5,color:buoyColors.primary,fontFamily:"monospace"},cardContent:{padding:14,gap:10},infoRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between"},infoLabel:{fontSize:11,color:buoyColors.textMuted,fontWeight:"500"},infoValue:{fontSize:11,color:buoyColors.text,fontWeight:"500",flex:1,textAlign:"right",marginLeft:12},infoValueMono:{fontFamily:"monospace"},badgeRow:{flexDirection:"row",flexWrap:"wrap",gap:8,marginTop:6},categoryBadge:{paddingHorizontal:8,paddingVertical:3,borderRadius:4},categoryText:{fontSize:9,fontWeight:"700",letterSpacing:.3},durationBadge:{flexDirection:"row",alignItems:"center",gap:4,paddingHorizontal:8,paddingVertical:3,borderRadius:4,backgroundColor:buoyColors.input},durationBadgeSlow:{backgroundColor:buoyColors.error+"26"},durationText:{fontSize:9,fontWeight:"600",color:buoyColors.textSecondary,fontFamily:"monospace"},durationTextSlow:{color:buoyColors.error},changesBadge:{flexDirection:"row",alignItems:"center",gap:4,paddingHorizontal:8,paddingVertical:3,borderRadius:4,backgroundColor:buoyColors.success+"26"},changesText:{fontSize:9,fontWeight:"600",color:buoyColors.success},noChangesBadge:{paddingHorizontal:8,paddingVertical:3,borderRadius:4,backgroundColor:buoyColors.input},noChangesText:{fontSize:9,fontWeight:"600",color:buoyColors.textMuted},typeBadge:{paddingHorizontal:6,paddingVertical:2,borderRadius:3,backgroundColor:buoyColors.input},typeText:{fontSize:8,fontWeight:"600",color:buoyColors.textMuted,fontFamily:"monospace"},dataViewerContainer:{backgroundColor:buoyColors.base,minHeight:60},argSection:{marginTop:4},argLabel:{fontSize:11,color:buoyColors.textMuted,fontWeight:"500",marginBottom:6},argValueContainer:{backgroundColor:buoyColors.base,borderRadius:6,borderWidth:1,borderColor:buoyColors.border,overflow:"hidden"},argValue:{fontSize:11,color:buoyColors.text,fontFamily:"monospace",padding:10},errorBadge:{paddingHorizontal:8,paddingVertical:3,borderRadius:4,backgroundColor:buoyColors.error+"26"},errorBadgeText:{fontSize:9,fontWeight:"700",color:buoyColors.error,letterSpacing:.3},errorText:{fontSize:12,color:buoyColors.error,fontFamily:"monospace",padding:14},asyncBadge:{paddingHorizontal:8,paddingVertical:3,borderRadius:4,backgroundColor:buoyColors.primary+"26"},asyncBadgeText:{fontSize:9,fontWeight:"700",color:buoyColors.primary,letterSpacing:.3},baseActionType:{fontSize:12,fontWeight:"600",color:buoyColors.text,fontFamily:"monospace",marginBottom:8},totalDurationRow:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",marginBottom:12,paddingBottom:12,borderBottomWidth:1,borderBottomColor:buoyColors.border},totalDurationLabel:{fontSize:11,color:buoyColors.textMuted,fontWeight:"500"},totalDurationValue:{fontSize:14,fontWeight:"700",color:buoyColors.success,fontFamily:"monospace"},timeline:{gap:0},timelineItem:{flexDirection:"row",alignItems:"flex-start",paddingVertical:8,paddingHorizontal:8,borderRadius:8,position:"relative"},timelineItemCurrent:{backgroundColor:buoyColors.primary+"15"},timelineConnector:{position:"absolute",left:13,top:24,bottom:-8,width:2,backgroundColor:buoyColors.border},timelineDot:{width:12,height:12,borderRadius:6,marginRight:10,marginTop:2},timelineContent:{flex:1},timelineHeader:{flexDirection:"row",alignItems:"center",gap:8,marginBottom:2},timelineStatusBadge:{paddingHorizontal:6,paddingVertical:2,borderRadius:4},timelineStatusText:{fontSize:9,fontWeight:"700",letterSpacing:.3},currentBadge:{paddingHorizontal:6,paddingVertical:2,borderRadius:4,backgroundColor:buoyColors.primary},currentBadgeText:{fontSize:8,fontWeight:"700",color:"#fff",letterSpacing:.3},timelineTime:{fontSize:10,color:buoyColors.textMuted,fontFamily:"monospace"},actionFooter:{backgroundColor:buoyColors.card,borderRadius:6,borderWidth:1,borderColor:buoyColors.primary+"4D",paddingVertical:12,paddingHorizontal:12,shadowColor:buoyColors.primary,shadowOffset:{width:0,height:0},shadowOpacity:.1,shadowRadius:6},actionsGrid:{flexDirection:"row",flexWrap:"wrap",gap:12,justifyContent:"flex-start"},actionButtonWrapper:{alignItems:"center",gap:4},actionDescription:{fontSize:9,color:buoyColors.textMuted,textAlign:"center"}});
1
+ "use strict";
2
+
3
+ /**
4
+ * ReduxActionInfoView
5
+ *
6
+ * Displays comprehensive action information including:
7
+ * - Action metadata (type, slice, category, duration)
8
+ * - Payload data
9
+ * - Async thunk metadata (requestId, status, arg)
10
+ * - Error details for rejected actions
11
+ */
12
+
13
+ import React, { memo, useMemo, useCallback, useState, useEffect } from "react";
14
+ import { View, Text, StyleSheet, ScrollView, TouchableOpacity } from "react-native";
15
+ import { buoyColors, Clock, AlertTriangle, Zap, Hash, Info, Box, AlertCircle, FileText, parseValue, ProUpgradeModal, copyToClipboard } from "@buoy-gg/shared-ui";
16
+ import { useIsPro } from "@buoy-gg/license";
17
+ import { DataViewer } from "@buoy-gg/shared-ui/dataViewer";
18
+ import { reduxActionStore } from "../utils/reduxActionStore";
19
+ import { jumpToState, replayAction } from "../utils/buoyReduxMiddleware";
20
+ import { ReduxActionButton } from "./ReduxActionButton";
21
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
22
+ /**
23
+ * Get category display info
24
+ */
25
+ function getCategoryInfo(category) {
26
+ switch (category) {
27
+ case "pending":
28
+ return {
29
+ label: "PENDING",
30
+ color: buoyColors.warning,
31
+ bgColor: buoyColors.warning + "26"
32
+ };
33
+ case "fulfilled":
34
+ return {
35
+ label: "FULFILLED",
36
+ color: buoyColors.success,
37
+ bgColor: buoyColors.success + "26"
38
+ };
39
+ case "rejected":
40
+ return {
41
+ label: "REJECTED",
42
+ color: buoyColors.error,
43
+ bgColor: buoyColors.error + "26"
44
+ };
45
+ case "internal":
46
+ return {
47
+ label: "INTERNAL",
48
+ color: buoyColors.textMuted,
49
+ bgColor: buoyColors.textMuted + "26"
50
+ };
51
+ case "query":
52
+ return {
53
+ label: "QUERY",
54
+ color: buoyColors.info,
55
+ bgColor: buoyColors.info + "26"
56
+ };
57
+ case "mutation":
58
+ return {
59
+ label: "MUTATION",
60
+ color: buoyColors.info,
61
+ bgColor: buoyColors.info + "26"
62
+ };
63
+ default:
64
+ return {
65
+ label: "ACTION",
66
+ color: buoyColors.info,
67
+ bgColor: buoyColors.info + "26"
68
+ };
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Format duration for display
74
+ */
75
+ function formatDuration(duration) {
76
+ if (duration === undefined) return "N/A";
77
+ if (duration < 1) return "<1ms";
78
+ return `${duration.toFixed(1)}ms`;
79
+ }
80
+
81
+ /**
82
+ * Section header component - matches React Query DevTools styling
83
+ */
84
+ function SectionHeader({
85
+ icon: Icon,
86
+ title,
87
+ badge
88
+ }) {
89
+ return /*#__PURE__*/_jsxs(View, {
90
+ style: styles.sectionHeader,
91
+ children: [/*#__PURE__*/_jsxs(View, {
92
+ style: styles.sectionHeaderLeft,
93
+ children: [/*#__PURE__*/_jsx(Icon, {
94
+ size: 14,
95
+ color: buoyColors.primary
96
+ }), /*#__PURE__*/_jsx(Text, {
97
+ style: styles.sectionTitle,
98
+ children: title
99
+ })]
100
+ }), badge]
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Info row component for key-value display
106
+ */
107
+ function InfoRow({
108
+ label,
109
+ value,
110
+ valueColor,
111
+ mono = false
112
+ }) {
113
+ return /*#__PURE__*/_jsxs(View, {
114
+ style: styles.infoRow,
115
+ children: [/*#__PURE__*/_jsx(Text, {
116
+ style: styles.infoLabel,
117
+ children: label
118
+ }), /*#__PURE__*/_jsx(Text, {
119
+ style: [styles.infoValue, mono && styles.infoValueMono, valueColor && {
120
+ color: valueColor
121
+ }],
122
+ numberOfLines: 1,
123
+ ellipsizeMode: "middle",
124
+ children: value
125
+ })]
126
+ });
127
+ }
128
+
129
+ /**
130
+ * Format timestamp for display
131
+ */
132
+ function formatTime(timestamp) {
133
+ const date = new Date(timestamp);
134
+ const hours = date.getHours().toString().padStart(2, "0");
135
+ const minutes = date.getMinutes().toString().padStart(2, "0");
136
+ const seconds = date.getSeconds().toString().padStart(2, "0");
137
+ const ms = date.getMilliseconds().toString().padStart(3, "0");
138
+ return `${hours}:${minutes}:${seconds}.${ms}`;
139
+ }
140
+ export const ReduxActionInfoView = /*#__PURE__*/memo(function ReduxActionInfoView({
141
+ action,
142
+ onNavigateToAction
143
+ }) {
144
+ const isPro = useIsPro();
145
+ const [showProModal, setShowProModal] = useState(false);
146
+
147
+ // Auto-close modal when user becomes Pro
148
+ useEffect(() => {
149
+ if (showProModal && isPro) {
150
+ setShowProModal(false);
151
+ }
152
+ }, [showProModal, isPro]);
153
+ const categoryInfo = getCategoryInfo(action.category);
154
+ const hasPayload = action.payload !== undefined;
155
+ const hasMeta = action.meta && Object.keys(action.meta).length > 0;
156
+ const hasError = action.error !== undefined;
157
+
158
+ // Get related async actions
159
+ const relatedActions = useMemo(() => {
160
+ return reduxActionStore.getLinkedActions(action);
161
+ }, [action]);
162
+ const hasRelatedActions = relatedActions.length > 1;
163
+ const baseActionType = hasRelatedActions ? reduxActionStore.getBaseActionType(action.type) : null;
164
+ const totalDuration = action.meta?.requestId ? reduxActionStore.getAsyncOperationDuration(action.meta.requestId) : null;
165
+
166
+ // Action handlers - copy requires Pro
167
+ const handleCopyAction = useCallback(async () => {
168
+ if (!isPro) {
169
+ setShowProModal(true);
170
+ return;
171
+ }
172
+ await copyToClipboard(action.action);
173
+ }, [action, isPro]);
174
+ const handleCopyPayload = useCallback(async () => {
175
+ if (!isPro) {
176
+ setShowProModal(true);
177
+ return;
178
+ }
179
+ await copyToClipboard(action.payload);
180
+ }, [action.payload, isPro]);
181
+ const handleReplay = useCallback(() => {
182
+ // Replay the original action
183
+ if (action.action && typeof action.action === "object" && "type" in action.action) {
184
+ replayAction(action.action);
185
+ }
186
+ }, [action]);
187
+ const handleJump = useCallback(() => {
188
+ // Jump to the state after this action was applied
189
+ if (action.nextState !== undefined) {
190
+ jumpToState(action.nextState);
191
+ }
192
+ }, [action]);
193
+ return /*#__PURE__*/_jsxs(ScrollView, {
194
+ style: styles.container,
195
+ contentContainerStyle: styles.contentContainer,
196
+ showsVerticalScrollIndicator: false,
197
+ children: [/*#__PURE__*/_jsxs(View, {
198
+ style: styles.card,
199
+ children: [/*#__PURE__*/_jsx(SectionHeader, {
200
+ icon: Info,
201
+ title: "ACTION INFO"
202
+ }), /*#__PURE__*/_jsxs(View, {
203
+ style: styles.cardContent,
204
+ children: [/*#__PURE__*/_jsx(InfoRow, {
205
+ label: "Type",
206
+ value: action.type,
207
+ mono: true
208
+ }), action.sliceName && /*#__PURE__*/_jsx(InfoRow, {
209
+ label: "Slice",
210
+ value: action.sliceName,
211
+ mono: true
212
+ }), /*#__PURE__*/_jsx(InfoRow, {
213
+ label: "Action",
214
+ value: action.actionName,
215
+ mono: true
216
+ }), /*#__PURE__*/_jsxs(View, {
217
+ style: styles.badgeRow,
218
+ children: [/*#__PURE__*/_jsx(View, {
219
+ style: [styles.categoryBadge, {
220
+ backgroundColor: categoryInfo.bgColor
221
+ }],
222
+ children: /*#__PURE__*/_jsx(Text, {
223
+ style: [styles.categoryText, {
224
+ color: categoryInfo.color
225
+ }],
226
+ children: categoryInfo.label
227
+ })
228
+ }), /*#__PURE__*/_jsxs(View, {
229
+ style: [styles.durationBadge, action.isSlowAction && styles.durationBadgeSlow],
230
+ children: [/*#__PURE__*/_jsx(Clock, {
231
+ size: 10,
232
+ color: action.isSlowAction ? buoyColors.error : buoyColors.textSecondary
233
+ }), /*#__PURE__*/_jsx(Text, {
234
+ style: [styles.durationText, action.isSlowAction && styles.durationTextSlow],
235
+ children: formatDuration(action.duration)
236
+ }), action.isSlowAction && /*#__PURE__*/_jsx(AlertTriangle, {
237
+ size: 10,
238
+ color: buoyColors.error
239
+ })]
240
+ }), action.hasStateChange ? /*#__PURE__*/_jsxs(View, {
241
+ style: styles.changesBadge,
242
+ children: [/*#__PURE__*/_jsx(Zap, {
243
+ size: 10,
244
+ color: buoyColors.success
245
+ }), /*#__PURE__*/_jsx(Text, {
246
+ style: styles.changesText,
247
+ children: action.diffSummary || "changed"
248
+ })]
249
+ }) : /*#__PURE__*/_jsx(View, {
250
+ style: styles.noChangesBadge,
251
+ children: /*#__PURE__*/_jsx(Text, {
252
+ style: styles.noChangesText,
253
+ children: "no change"
254
+ })
255
+ })]
256
+ })]
257
+ })]
258
+ }), hasRelatedActions && /*#__PURE__*/_jsxs(View, {
259
+ style: styles.card,
260
+ children: [/*#__PURE__*/_jsx(SectionHeader, {
261
+ icon: Hash,
262
+ title: "ASYNC FLOW",
263
+ badge: /*#__PURE__*/_jsx(View, {
264
+ style: styles.asyncBadge,
265
+ children: /*#__PURE__*/_jsxs(Text, {
266
+ style: styles.asyncBadgeText,
267
+ children: [relatedActions.length, " ACTIONS"]
268
+ })
269
+ })
270
+ }), /*#__PURE__*/_jsxs(View, {
271
+ style: styles.cardContent,
272
+ children: [/*#__PURE__*/_jsx(Text, {
273
+ style: styles.baseActionType,
274
+ children: baseActionType
275
+ }), totalDuration !== null && /*#__PURE__*/_jsxs(View, {
276
+ style: styles.totalDurationRow,
277
+ children: [/*#__PURE__*/_jsx(Text, {
278
+ style: styles.totalDurationLabel,
279
+ children: "Total Duration"
280
+ }), /*#__PURE__*/_jsxs(Text, {
281
+ style: styles.totalDurationValue,
282
+ children: [totalDuration, "ms"]
283
+ })]
284
+ }), /*#__PURE__*/_jsx(View, {
285
+ style: styles.timeline,
286
+ children: relatedActions.map((relatedAction, index) => {
287
+ const relatedCategoryInfo = getCategoryInfo(relatedAction.category);
288
+ const isCurrent = relatedAction.id === action.id;
289
+ return /*#__PURE__*/_jsxs(TouchableOpacity, {
290
+ style: [styles.timelineItem, isCurrent && styles.timelineItemCurrent],
291
+ onPress: () => onNavigateToAction?.(relatedAction),
292
+ disabled: isCurrent || !onNavigateToAction,
293
+ activeOpacity: 0.7,
294
+ children: [index < relatedActions.length - 1 && /*#__PURE__*/_jsx(View, {
295
+ style: styles.timelineConnector
296
+ }), /*#__PURE__*/_jsx(View, {
297
+ style: [styles.timelineDot, {
298
+ backgroundColor: relatedCategoryInfo.color
299
+ }]
300
+ }), /*#__PURE__*/_jsxs(View, {
301
+ style: styles.timelineContent,
302
+ children: [/*#__PURE__*/_jsxs(View, {
303
+ style: styles.timelineHeader,
304
+ children: [/*#__PURE__*/_jsx(View, {
305
+ style: [styles.timelineStatusBadge, {
306
+ backgroundColor: relatedCategoryInfo.bgColor
307
+ }],
308
+ children: /*#__PURE__*/_jsx(Text, {
309
+ style: [styles.timelineStatusText, {
310
+ color: relatedCategoryInfo.color
311
+ }],
312
+ children: relatedCategoryInfo.label
313
+ })
314
+ }), isCurrent && /*#__PURE__*/_jsx(View, {
315
+ style: styles.currentBadge,
316
+ children: /*#__PURE__*/_jsx(Text, {
317
+ style: styles.currentBadgeText,
318
+ children: "CURRENT"
319
+ })
320
+ })]
321
+ }), /*#__PURE__*/_jsx(Text, {
322
+ style: styles.timelineTime,
323
+ children: formatTime(relatedAction.timestamp)
324
+ })]
325
+ })]
326
+ }, relatedAction.id);
327
+ })
328
+ })]
329
+ })]
330
+ }), hasPayload && /*#__PURE__*/_jsxs(View, {
331
+ style: styles.card,
332
+ children: [/*#__PURE__*/_jsx(SectionHeader, {
333
+ icon: Box,
334
+ title: "PAYLOAD",
335
+ badge: /*#__PURE__*/_jsx(View, {
336
+ style: styles.typeBadge,
337
+ children: /*#__PURE__*/_jsx(Text, {
338
+ style: styles.typeText,
339
+ children: Array.isArray(action.payload) ? "ARRAY" : typeof action.payload === "object" ? "OBJECT" : typeof action.payload?.toString().toUpperCase()
340
+ })
341
+ })
342
+ }), /*#__PURE__*/_jsx(View, {
343
+ style: styles.dataViewerContainer,
344
+ children: /*#__PURE__*/_jsx(DataViewer, {
345
+ title: "",
346
+ data: parseValue(action.payload),
347
+ showTypeFilter: true,
348
+ rawMode: true,
349
+ initialExpanded: true
350
+ })
351
+ })]
352
+ }), hasMeta && /*#__PURE__*/_jsxs(View, {
353
+ style: styles.card,
354
+ children: [/*#__PURE__*/_jsx(SectionHeader, {
355
+ icon: Hash,
356
+ title: "ASYNC METADATA",
357
+ badge: /*#__PURE__*/_jsx(View, {
358
+ style: [styles.categoryBadge, {
359
+ backgroundColor: categoryInfo.bgColor
360
+ }],
361
+ children: /*#__PURE__*/_jsx(Text, {
362
+ style: [styles.categoryText, {
363
+ color: categoryInfo.color
364
+ }],
365
+ children: "RTK THUNK"
366
+ })
367
+ })
368
+ }), /*#__PURE__*/_jsxs(View, {
369
+ style: styles.cardContent,
370
+ children: [action.meta?.requestId && /*#__PURE__*/_jsx(InfoRow, {
371
+ label: "Request ID",
372
+ value: action.meta.requestId,
373
+ mono: true
374
+ }), action.meta?.requestStatus && /*#__PURE__*/_jsx(InfoRow, {
375
+ label: "Status",
376
+ value: action.meta.requestStatus.toUpperCase(),
377
+ valueColor: categoryInfo.color
378
+ }), action.meta?.arg !== undefined && /*#__PURE__*/_jsxs(View, {
379
+ style: styles.argSection,
380
+ children: [/*#__PURE__*/_jsx(Text, {
381
+ style: styles.argLabel,
382
+ children: "Original Argument"
383
+ }), /*#__PURE__*/_jsx(View, {
384
+ style: styles.argValueContainer,
385
+ children: typeof action.meta.arg === "object" ? /*#__PURE__*/_jsx(DataViewer, {
386
+ title: "",
387
+ data: parseValue(action.meta.arg),
388
+ showTypeFilter: true,
389
+ rawMode: true,
390
+ initialExpanded: true
391
+ }) : /*#__PURE__*/_jsx(Text, {
392
+ style: styles.argValue,
393
+ children: JSON.stringify(action.meta.arg)
394
+ })
395
+ })]
396
+ }), action.meta?.rejectedWithValue && /*#__PURE__*/_jsx(InfoRow, {
397
+ label: "Rejected With Value",
398
+ value: "true",
399
+ valueColor: buoyColors.error
400
+ }), action.meta?.aborted && /*#__PURE__*/_jsx(InfoRow, {
401
+ label: "Aborted",
402
+ value: "true",
403
+ valueColor: buoyColors.warning
404
+ }), action.meta?.condition && /*#__PURE__*/_jsx(InfoRow, {
405
+ label: "Condition",
406
+ value: "true",
407
+ valueColor: buoyColors.textMuted
408
+ })]
409
+ })]
410
+ }), hasError && /*#__PURE__*/_jsxs(View, {
411
+ style: [styles.card, styles.errorCard],
412
+ children: [/*#__PURE__*/_jsx(SectionHeader, {
413
+ icon: AlertCircle,
414
+ title: "ERROR",
415
+ badge: /*#__PURE__*/_jsx(View, {
416
+ style: styles.errorBadge,
417
+ children: /*#__PURE__*/_jsx(Text, {
418
+ style: styles.errorBadgeText,
419
+ children: "REJECTED"
420
+ })
421
+ })
422
+ }), /*#__PURE__*/_jsx(View, {
423
+ style: styles.dataViewerContainer,
424
+ children: typeof action.error === "object" ? /*#__PURE__*/_jsx(DataViewer, {
425
+ title: "",
426
+ data: parseValue(action.error),
427
+ showTypeFilter: true,
428
+ rawMode: true,
429
+ initialExpanded: true
430
+ }) : /*#__PURE__*/_jsx(Text, {
431
+ style: styles.errorText,
432
+ children: String(action.error)
433
+ })
434
+ })]
435
+ }), /*#__PURE__*/_jsxs(View, {
436
+ style: styles.card,
437
+ children: [/*#__PURE__*/_jsx(SectionHeader, {
438
+ icon: FileText,
439
+ title: "FULL ACTION OBJECT"
440
+ }), /*#__PURE__*/_jsx(View, {
441
+ style: styles.dataViewerContainer,
442
+ children: /*#__PURE__*/_jsx(DataViewer, {
443
+ title: "",
444
+ data: parseValue(action.action),
445
+ showTypeFilter: true,
446
+ rawMode: true,
447
+ initialExpanded: true
448
+ })
449
+ })]
450
+ }), /*#__PURE__*/_jsx(View, {
451
+ style: styles.actionFooter,
452
+ children: /*#__PURE__*/_jsxs(View, {
453
+ style: styles.actionsGrid,
454
+ children: [/*#__PURE__*/_jsxs(View, {
455
+ style: styles.actionButtonWrapper,
456
+ children: [/*#__PURE__*/_jsx(ReduxActionButton, {
457
+ type: "replay",
458
+ text: "REPLAY",
459
+ onPress: handleReplay
460
+ }), /*#__PURE__*/_jsx(Text, {
461
+ style: styles.actionDescription,
462
+ children: "Dispatch again"
463
+ })]
464
+ }), /*#__PURE__*/_jsxs(View, {
465
+ style: styles.actionButtonWrapper,
466
+ children: [/*#__PURE__*/_jsx(ReduxActionButton, {
467
+ type: "jump",
468
+ text: "JUMP",
469
+ onPress: handleJump
470
+ }), /*#__PURE__*/_jsx(Text, {
471
+ style: styles.actionDescription,
472
+ children: "Restore this state"
473
+ })]
474
+ }), /*#__PURE__*/_jsxs(View, {
475
+ style: styles.actionButtonWrapper,
476
+ children: [/*#__PURE__*/_jsx(ReduxActionButton, {
477
+ type: "copy",
478
+ text: "COPY ACTION",
479
+ onPress: handleCopyAction
480
+ }), /*#__PURE__*/_jsx(Text, {
481
+ style: styles.actionDescription,
482
+ children: isPro ? "Copy to clipboard" : "Pro feature"
483
+ })]
484
+ }), hasPayload && /*#__PURE__*/_jsxs(View, {
485
+ style: styles.actionButtonWrapper,
486
+ children: [/*#__PURE__*/_jsx(ReduxActionButton, {
487
+ type: "copy",
488
+ text: "COPY PAYLOAD",
489
+ onPress: handleCopyPayload
490
+ }), /*#__PURE__*/_jsx(Text, {
491
+ style: styles.actionDescription,
492
+ children: isPro ? "Copy payload only" : "Pro feature"
493
+ })]
494
+ })]
495
+ })
496
+ }), /*#__PURE__*/_jsx(ProUpgradeModal, {
497
+ visible: showProModal,
498
+ onClose: () => setShowProModal(false),
499
+ featureName: "Copy"
500
+ })]
501
+ });
502
+ });
503
+ const styles = StyleSheet.create({
504
+ container: {
505
+ flex: 1
506
+ },
507
+ contentContainer: {
508
+ padding: 8,
509
+ paddingBottom: 100,
510
+ gap: 16
511
+ },
512
+ // Card styling - matches React Query DevTools
513
+ card: {
514
+ backgroundColor: buoyColors.card,
515
+ borderRadius: 6,
516
+ borderWidth: 1,
517
+ borderColor: buoyColors.primary + "4D",
518
+ overflow: "hidden",
519
+ shadowColor: buoyColors.primary,
520
+ shadowOffset: {
521
+ width: 0,
522
+ height: 0
523
+ },
524
+ shadowOpacity: 0.1,
525
+ shadowRadius: 6
526
+ },
527
+ errorCard: {
528
+ borderColor: buoyColors.error + "4D",
529
+ shadowColor: buoyColors.error
530
+ },
531
+ // Section header - green tinted like React Query
532
+ sectionHeader: {
533
+ flexDirection: "row",
534
+ alignItems: "center",
535
+ justifyContent: "space-between",
536
+ paddingHorizontal: 12,
537
+ paddingVertical: 10,
538
+ borderBottomWidth: 1,
539
+ borderBottomColor: buoyColors.primary + "33",
540
+ backgroundColor: buoyColors.primary + "15"
541
+ },
542
+ sectionHeaderLeft: {
543
+ flexDirection: "row",
544
+ alignItems: "center",
545
+ gap: 6
546
+ },
547
+ sectionTitle: {
548
+ fontSize: 12,
549
+ fontWeight: "600",
550
+ letterSpacing: 0.5,
551
+ color: buoyColors.primary,
552
+ fontFamily: "monospace"
553
+ },
554
+ cardContent: {
555
+ padding: 14,
556
+ gap: 10
557
+ },
558
+ infoRow: {
559
+ flexDirection: "row",
560
+ alignItems: "center",
561
+ justifyContent: "space-between"
562
+ },
563
+ infoLabel: {
564
+ fontSize: 11,
565
+ color: buoyColors.textMuted,
566
+ fontWeight: "500"
567
+ },
568
+ infoValue: {
569
+ fontSize: 11,
570
+ color: buoyColors.text,
571
+ fontWeight: "500",
572
+ flex: 1,
573
+ textAlign: "right",
574
+ marginLeft: 12
575
+ },
576
+ infoValueMono: {
577
+ fontFamily: "monospace"
578
+ },
579
+ badgeRow: {
580
+ flexDirection: "row",
581
+ flexWrap: "wrap",
582
+ gap: 8,
583
+ marginTop: 6
584
+ },
585
+ categoryBadge: {
586
+ paddingHorizontal: 8,
587
+ paddingVertical: 3,
588
+ borderRadius: 4
589
+ },
590
+ categoryText: {
591
+ fontSize: 9,
592
+ fontWeight: "700",
593
+ letterSpacing: 0.3
594
+ },
595
+ durationBadge: {
596
+ flexDirection: "row",
597
+ alignItems: "center",
598
+ gap: 4,
599
+ paddingHorizontal: 8,
600
+ paddingVertical: 3,
601
+ borderRadius: 4,
602
+ backgroundColor: buoyColors.input
603
+ },
604
+ durationBadgeSlow: {
605
+ backgroundColor: buoyColors.error + "26"
606
+ },
607
+ durationText: {
608
+ fontSize: 9,
609
+ fontWeight: "600",
610
+ color: buoyColors.textSecondary,
611
+ fontFamily: "monospace"
612
+ },
613
+ durationTextSlow: {
614
+ color: buoyColors.error
615
+ },
616
+ changesBadge: {
617
+ flexDirection: "row",
618
+ alignItems: "center",
619
+ gap: 4,
620
+ paddingHorizontal: 8,
621
+ paddingVertical: 3,
622
+ borderRadius: 4,
623
+ backgroundColor: buoyColors.success + "26"
624
+ },
625
+ changesText: {
626
+ fontSize: 9,
627
+ fontWeight: "600",
628
+ color: buoyColors.success
629
+ },
630
+ noChangesBadge: {
631
+ paddingHorizontal: 8,
632
+ paddingVertical: 3,
633
+ borderRadius: 4,
634
+ backgroundColor: buoyColors.input
635
+ },
636
+ noChangesText: {
637
+ fontSize: 9,
638
+ fontWeight: "600",
639
+ color: buoyColors.textMuted
640
+ },
641
+ typeBadge: {
642
+ paddingHorizontal: 6,
643
+ paddingVertical: 2,
644
+ borderRadius: 3,
645
+ backgroundColor: buoyColors.input
646
+ },
647
+ typeText: {
648
+ fontSize: 8,
649
+ fontWeight: "600",
650
+ color: buoyColors.textMuted,
651
+ fontFamily: "monospace"
652
+ },
653
+ dataViewerContainer: {
654
+ backgroundColor: buoyColors.base,
655
+ minHeight: 60
656
+ },
657
+ argSection: {
658
+ marginTop: 4
659
+ },
660
+ argLabel: {
661
+ fontSize: 11,
662
+ color: buoyColors.textMuted,
663
+ fontWeight: "500",
664
+ marginBottom: 6
665
+ },
666
+ argValueContainer: {
667
+ backgroundColor: buoyColors.base,
668
+ borderRadius: 6,
669
+ borderWidth: 1,
670
+ borderColor: buoyColors.border,
671
+ overflow: "hidden"
672
+ },
673
+ argValue: {
674
+ fontSize: 11,
675
+ color: buoyColors.text,
676
+ fontFamily: "monospace",
677
+ padding: 10
678
+ },
679
+ errorBadge: {
680
+ paddingHorizontal: 8,
681
+ paddingVertical: 3,
682
+ borderRadius: 4,
683
+ backgroundColor: buoyColors.error + "26"
684
+ },
685
+ errorBadgeText: {
686
+ fontSize: 9,
687
+ fontWeight: "700",
688
+ color: buoyColors.error,
689
+ letterSpacing: 0.3
690
+ },
691
+ errorText: {
692
+ fontSize: 12,
693
+ color: buoyColors.error,
694
+ fontFamily: "monospace",
695
+ padding: 14
696
+ },
697
+ // Async Operation / Related Actions styles
698
+ asyncBadge: {
699
+ paddingHorizontal: 8,
700
+ paddingVertical: 3,
701
+ borderRadius: 4,
702
+ backgroundColor: buoyColors.primary + "26"
703
+ },
704
+ asyncBadgeText: {
705
+ fontSize: 9,
706
+ fontWeight: "700",
707
+ color: buoyColors.primary,
708
+ letterSpacing: 0.3
709
+ },
710
+ baseActionType: {
711
+ fontSize: 12,
712
+ fontWeight: "600",
713
+ color: buoyColors.text,
714
+ fontFamily: "monospace",
715
+ marginBottom: 8
716
+ },
717
+ totalDurationRow: {
718
+ flexDirection: "row",
719
+ justifyContent: "space-between",
720
+ alignItems: "center",
721
+ marginBottom: 12,
722
+ paddingBottom: 12,
723
+ borderBottomWidth: 1,
724
+ borderBottomColor: buoyColors.border
725
+ },
726
+ totalDurationLabel: {
727
+ fontSize: 11,
728
+ color: buoyColors.textMuted,
729
+ fontWeight: "500"
730
+ },
731
+ totalDurationValue: {
732
+ fontSize: 14,
733
+ fontWeight: "700",
734
+ color: buoyColors.success,
735
+ fontFamily: "monospace"
736
+ },
737
+ timeline: {
738
+ gap: 0
739
+ },
740
+ timelineItem: {
741
+ flexDirection: "row",
742
+ alignItems: "flex-start",
743
+ paddingVertical: 8,
744
+ paddingHorizontal: 8,
745
+ borderRadius: 8,
746
+ position: "relative"
747
+ },
748
+ timelineItemCurrent: {
749
+ backgroundColor: buoyColors.primary + "15"
750
+ },
751
+ timelineConnector: {
752
+ position: "absolute",
753
+ left: 13,
754
+ top: 24,
755
+ bottom: -8,
756
+ width: 2,
757
+ backgroundColor: buoyColors.border
758
+ },
759
+ timelineDot: {
760
+ width: 12,
761
+ height: 12,
762
+ borderRadius: 6,
763
+ marginRight: 10,
764
+ marginTop: 2
765
+ },
766
+ timelineContent: {
767
+ flex: 1
768
+ },
769
+ timelineHeader: {
770
+ flexDirection: "row",
771
+ alignItems: "center",
772
+ gap: 8,
773
+ marginBottom: 2
774
+ },
775
+ timelineStatusBadge: {
776
+ paddingHorizontal: 6,
777
+ paddingVertical: 2,
778
+ borderRadius: 4
779
+ },
780
+ timelineStatusText: {
781
+ fontSize: 9,
782
+ fontWeight: "700",
783
+ letterSpacing: 0.3
784
+ },
785
+ currentBadge: {
786
+ paddingHorizontal: 6,
787
+ paddingVertical: 2,
788
+ borderRadius: 4,
789
+ backgroundColor: buoyColors.primary
790
+ },
791
+ currentBadgeText: {
792
+ fontSize: 8,
793
+ fontWeight: "700",
794
+ color: "#fff",
795
+ letterSpacing: 0.3
796
+ },
797
+ timelineTime: {
798
+ fontSize: 10,
799
+ color: buoyColors.textMuted,
800
+ fontFamily: "monospace"
801
+ },
802
+ // Action footer - matches React Query DevTools
803
+ actionFooter: {
804
+ backgroundColor: buoyColors.card,
805
+ borderRadius: 6,
806
+ borderWidth: 1,
807
+ borderColor: buoyColors.primary + "4D",
808
+ paddingVertical: 12,
809
+ paddingHorizontal: 12,
810
+ shadowColor: buoyColors.primary,
811
+ shadowOffset: {
812
+ width: 0,
813
+ height: 0
814
+ },
815
+ shadowOpacity: 0.1,
816
+ shadowRadius: 6
817
+ },
818
+ actionsGrid: {
819
+ flexDirection: "row",
820
+ flexWrap: "wrap",
821
+ gap: 12,
822
+ justifyContent: "flex-start"
823
+ },
824
+ actionButtonWrapper: {
825
+ alignItems: "center",
826
+ gap: 4
827
+ },
828
+ actionDescription: {
829
+ fontSize: 9,
830
+ color: buoyColors.textMuted,
831
+ textAlign: "center"
832
+ }
833
+ });