@buoy-gg/redux 7.0.38 → 7.0.40

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