Skip to content

Commit 7263835

Browse files
Wire up initial benchmark implementation #29 (#43)
* wip: wire up benchmark report display (performance tab) * update reactotron-core-ui/reactotron-core-contract, initial benchmark impl * fix prettier lint issue * weird lint issues * Fixes per review * clean up details panel title * fix newline issue --------- Co-authored-by: Steven Conner <steven.c.conner@gmail.com>
1 parent 2b902ad commit 7263835

File tree

10 files changed

+181
-70
lines changed

10 files changed

+181
-70
lines changed

app/components/DetailPanel.tsx

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
} from "react-native"
1212
import { themed } from "../theme/theme"
1313
import { CommandType } from "reactotron-core-contract"
14-
import type { TimelineItem } from "../types"
14+
import { TimelineItem, TimelineItemBenchmark } from "../types"
1515
import { TreeViewWithProvider } from "./TreeView"
1616
import ActionButton from "./ActionButton"
1717
import { Tooltip } from "./Tooltip"
@@ -49,8 +49,12 @@ export function DetailPanel({ selectedItem, onClose }: DetailPanelProps) {
4949
return "Log Details"
5050
case CommandType.Display:
5151
return "Display Details"
52-
default:
52+
case CommandType.Benchmark:
53+
return "Benchmark Details"
54+
case CommandType.ApiResponse:
5355
return "Network Details"
56+
default:
57+
return "Unknown"
5458
}
5559
}
5660

@@ -60,6 +64,8 @@ export function DetailPanel({ selectedItem, onClose }: DetailPanelProps) {
6064
return <LogDetailContent item={selectedItem} />
6165
case CommandType.Display:
6266
return <DisplayDetailContent item={selectedItem} />
67+
case CommandType.Benchmark:
68+
return <BenchmarkDetailContent item={selectedItem} />
6369
case CommandType.ApiResponse:
6470
return <NetworkDetailContent item={selectedItem} />
6571
default:
@@ -184,6 +190,39 @@ function DisplayDetailContent({
184190
)
185191
}
186192

193+
function BenchmarkDetailContent({ item }: { item: TimelineItemBenchmark }) {
194+
const { payload } = item
195+
196+
return (
197+
<View style={$detailContent()}>
198+
{payload.steps.map((step, index) => {
199+
return (
200+
<DetailSection key={`${step.title}-${index}`} title={`Step: ${step.title}`}>
201+
<Text style={$valueText()}>Time: {step.time}</Text>
202+
<Text style={$valueText()}>Delta: {step.delta}</Text>
203+
</DetailSection>
204+
)
205+
})}
206+
<DetailSection title="Payload">
207+
<TreeViewWithProvider data={payload} />
208+
</DetailSection>
209+
<DetailSection title="Metadata">
210+
<TreeViewWithProvider
211+
data={{
212+
id: item.id,
213+
clientId: item.clientId,
214+
connectionId: item.connectionId,
215+
messageId: item.messageId,
216+
important: item.important,
217+
date: item.date,
218+
deltaTime: item.deltaTime,
219+
}}
220+
/>
221+
</DetailSection>
222+
</View>
223+
)
224+
}
225+
187226
/**
188227
* Renders detailed content for log timeline items including level, message, stack trace, and metadata.
189228
*/
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { CommandType, TimelineItemBenchmark } from "../types"
2+
import { TimelineItem } from "./TimelineItem"
3+
4+
type TimelineBenchmarkItemProps = {
5+
item: TimelineItemBenchmark
6+
isSelected?: boolean
7+
onSelect?: () => void
8+
}
9+
10+
/**
11+
* A single benchmark item in the timeline.
12+
*/
13+
export function TimelineBenchmmarkItem({
14+
item,
15+
isSelected = false,
16+
onSelect,
17+
}: TimelineBenchmarkItemProps) {
18+
const { payload, date, deltaTime, important } = item
19+
20+
if (item.type !== CommandType.Benchmark) return null
21+
22+
const { title } = payload
23+
24+
return (
25+
<TimelineItem
26+
title={"Benchmark"}
27+
date={new Date(date)}
28+
deltaTime={deltaTime}
29+
preview={title}
30+
isImportant={important}
31+
isTagged={important}
32+
isSelected={isSelected}
33+
onSelect={onSelect}
34+
actionMenu={[]}
35+
/>
36+
)
37+
}

app/components/TimelineToolbar.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export type FilterType =
55
| typeof CommandType.Log
66
| typeof CommandType.Display
77
| typeof CommandType.ApiResponse
8+
| typeof CommandType.Benchmark
89
// export type LogLevel = "all" | "debug" | "warn" | "error"
910
// export type SortBy = "time-newest" | "time-oldest" | "type" | "level"
1011

app/screens/TimelineScreen.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { TimelineItem } from "../types"
44
import { TimelineLogItem } from "../components/TimelineLogItem"
55
import { TimelineNetworkItem } from "../components/TimelineNetworkItem"
66
import { TimelineDisplayItem } from "../components/TimelineDisplayItem"
7+
import { TimelineBenchmmarkItem } from "../components/TimelineBenchmarkItem"
78
import { DetailPanel } from "../components/DetailPanel"
89
import { ResizableDivider } from "../components/ResizableDivider"
910
import { LegendList } from "@legendapp/list"
@@ -47,6 +48,11 @@ const TimelineItemRenderer = ({
4748
if (item.type === CommandType.ApiResponse) {
4849
return <TimelineNetworkItem item={item} isSelected={isSelected} onSelect={handleSelectItem} />
4950
}
51+
if (item.type === CommandType.Benchmark) {
52+
return (
53+
<TimelineBenchmmarkItem item={item} isSelected={isSelected} onSelect={handleSelectItem} />
54+
)
55+
}
5056
console.tron.log("Unknown item", item)
5157
return null
5258
}
@@ -57,8 +63,10 @@ function getTimelineTypes(activeItem: MenuItemId): FilterType[] {
5763
return [CommandType.Log, CommandType.Display]
5864
case "network":
5965
return [CommandType.ApiResponse]
66+
case "performance":
67+
return [CommandType.Benchmark]
6068
default:
61-
return [CommandType.Log, CommandType.Display, CommandType.ApiResponse]
69+
return [CommandType.Log, CommandType.Display, CommandType.ApiResponse, CommandType.Benchmark]
6270
}
6371
}
6472

app/state/connectToServer.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ export function connectToServer(props: { port: number } = { port: 9292 }): Unsub
9292
if (
9393
data.cmd.type === CommandType.Log ||
9494
data.cmd.type === CommandType.ApiResponse ||
95-
data.cmd.type === CommandType.Display
95+
data.cmd.type === CommandType.Display ||
96+
data.cmd.type === CommandType.Benchmark
9697
) {
9798
// Add a unique ID to the timeline item
9899
data.cmd.id = `${data.cmd.clientId}-${data.cmd.messageId}`
@@ -148,7 +149,7 @@ export function connectToServer(props: { port: number } = { port: 9292 }): Unsub
148149
}
149150
}
150151

151-
console.tron.log(data)
152+
console.log(data)
152153
}
153154

154155
// Clean up after disconnect

app/types.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Import types from the official Reactotron contract package
2-
import { CommandType } from "reactotron-core-contract"
2+
import { CommandType, CommandMap } from "reactotron-core-contract"
33
import type {
44
ErrorStackFrame,
55
ErrorLogPayload,
@@ -112,6 +112,8 @@ export interface NetworkPayload {
112112
* While they share similarities with the Command type from reactotron-core-contract, they are
113113
* tailored for this macOS app's UI needs (e.g., date as string for serialization, additional id field).
114114
*/
115+
116+
// Unified timeline item type
115117
export type TimelineItemBase = {
116118
id: string
117119
important: boolean
@@ -127,6 +129,11 @@ export type TimelineItemLog = TimelineItemBase & {
127129
payload: LogPayload
128130
}
129131

132+
export type TimelineItemBenchmark = TimelineItemBase & {
133+
type: typeof CommandType.Benchmark
134+
payload: CommandMap[typeof CommandType.Benchmark]
135+
}
136+
130137
export type TimelineItemNetwork = TimelineItemBase & {
131138
type: typeof CommandType.ApiResponse
132139
payload: NetworkPayload
@@ -137,7 +144,11 @@ export type TimelineItemDisplay = TimelineItemBase & {
137144
payload: DisplayPayload
138145
}
139146

140-
export type TimelineItem = TimelineItemLog | TimelineItemNetwork | TimelineItemDisplay
147+
export type TimelineItem =
148+
| TimelineItemLog
149+
| TimelineItemNetwork
150+
| TimelineItemDisplay
151+
| TimelineItemBenchmark
141152

142153
// StateSubscription represents a single state path/value pair tracked by the app
143154
// This is derived from the contract's StateValuesChangePayload structure

bin/generateTurboModule.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ import { TurboModuleRegistry } from "react-native"
117117
export interface Spec extends TurboModule {
118118
${fullSignature}
119119
}
120-
export default TurboModuleRegistry.getEnforcing<Spec>("${moduleName}")`
120+
export default TurboModuleRegistry.getEnforcing<Spec>("${moduleName}")
121+
`
121122

122123
fs.writeFileSync(nativeTsFile, tsTemplate)
123124
printSuccess(`Generated ${nativeTsFile}`)

macos/Podfile.lock

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,66 +1778,66 @@ SPEC CHECKSUMS:
17781778
fmt: f6af2d677a106e3e44c9536a4c0c7f03ab53c854
17791779
glog: b7594b792ee4e02ed1f44b01d046ca25fa713e3d
17801780
hermes-engine: b5c9cfbe6415f1b0b24759f2942c8f33e9af6347
1781-
IRNativeModules: f6a98dc467185ace04d1da1a790185d75f722342
1782-
RCT-Folly: e8b53d8c0d2d9df4a6a8b0a368a1a91fc62a88cb
1781+
IRNativeModules: 2fa316ab0ca91ec3e7bd4ba7ab2fc1f642fb5542
1782+
RCT-Folly: abec2d7f4af402b4957c44e86ceff8725b23c1b4
17831783
RCTDeprecation: 9da6c2d8a3b1802142718283260fb06d702ddb07
17841784
RCTRequired: 574f9d55bda1d50676530b6c36bab4605612dfb6
17851785
RCTTypeSafety: 7de929c405e619c023116e7747118a2c5d5b2320
17861786
React: ee782717a9c48bc876ab9d625324790a750775a9
17871787
React-callinvoker: 13537424f973520ee8d5b6a9d3c6f84443c6d1ff
1788-
React-Core: 967717dbbf6ec98ba43703bd31f16b2bd96c6b8e
1789-
React-CoreModules: 5b3eab1c27e3dcc291e88feec03025a9d835ba88
1790-
React-cxxreact: 70a5f32667ddc7572f41d76efb1a53a54208fb9d
1788+
React-Core: 3dea71b9fbed9fae6d4b7c22f146782c37b77d89
1789+
React-CoreModules: 34edcc752f034ba37ba6c10140144c1059196580
1790+
React-cxxreact: 6d6888fe269f8b2eb7a611f1d686e57774aa5778
17911791
React-debug: 2bc559a0e9d4fcdb3ac425f94270cc6ed7df9e05
1792-
React-defaultsnativemodule: b92049137b587b4bc8a002ebcdee94ed29a8c982
1793-
React-domnativemodule: 913453ae47d35cfd81e59f053fafdbf31280068f
1794-
React-Fabric: 9ca22fec823dec1f9b01567176c5d1c68b32754a
1795-
React-FabricComponents: 245d1c642c933c332922330358a20e0fc35c0d32
1796-
React-FabricImage: 870aed3dc688fb9102c6e6a3ad72cef1b4920e8b
1792+
React-defaultsnativemodule: 2498edcaaeea328f40ee226df031ca7dea793c42
1793+
React-domnativemodule: 88e425c54b41c43e8335af6402dce28f697f1ff5
1794+
React-Fabric: a944efc0297503213737f8cbf46e01a3b444fc3c
1795+
React-FabricComponents: 0c157dab0466bb06e1e3d2087b23574776825636
1796+
React-FabricImage: 3af244020d7ec7bef933f59b06707d81f105b225
17971797
React-featureflags: 430dcdb3434a1e0e82a86fd9e54cb60c00727c91
1798-
React-featureflagsnativemodule: 44fd0fc90cef865119bfae906eff26eea859f849
1799-
React-graphics: 846d79890e53c99d82aac8a5068c5af413b33156
1800-
React-hermes: 9d0e93261964415c1221ca0d3228ce6379fd0688
1801-
React-idlecallbacksnativemodule: d98e90ce04ede2a70cd0af36cbbc63f4452c7ca1
1802-
React-ImageManager: 45c24f173763276f768de21a6402d97ffaa99a96
1803-
React-jserrorhandler: 740d4c211d827e4bea189f19d4cda7bdb4d43c53
1804-
React-jsi: 12cffc431f7697e012b21219983afa0b00b05cf1
1805-
React-jsiexecutor: 0cfda76ba3dd858fd0428b7de688dfef2047f28c
1806-
React-jsinspector: fbaf7da8fda2b15dd264d181ed2c4735f66873ee
1807-
React-jsinspectortracing: c8531ea5125d017530aac9039936d6a1d0e6848f
1808-
React-jsitracing: d43e7b3d7a953e91c79490bbd74ef8abd2a9b3e7
1809-
React-logger: 4decf7656034a9a718ba347ecc1c87c79a04b58b
1810-
React-Mapbuffer: 4ad71d8e010591048bfa792f1ad6178181b87b9f
1811-
React-microtasksnativemodule: 7e04642d32b00c17481fdd11598d6351538ec842
1812-
react-native-mmkv: c969437e688f281c34d90310d5e05bbd5f8732a1
1813-
React-NativeModulesApple: 5bcf2c52a2aacd96cc958020b6c571df986d97c7
1814-
React-perflogger: 96cceccf29bf5507b3f48339f1d7282827a5274c
1815-
React-performancetimeline: f3f35f8a93f3788a0f920a09f0a99d58d14dcd06
1798+
React-featureflagsnativemodule: ca7c090df392ee31f3961bef6f5d776b431a328a
1799+
React-graphics: c375afb2f7abbee422f77bff01c1a06d71121951
1800+
React-hermes: 13744d913b44345d282c02bb3c2f30f037ffc88d
1801+
React-idlecallbacksnativemodule: 0417962dec9b92931f1db35ccc97261b0d5456b6
1802+
React-ImageManager: f3aec32f5a763636b7413b7dcb5ec255b12fcf91
1803+
React-jserrorhandler: 49faef82e71661aa5f690f30b099a695990a5a41
1804+
React-jsi: b8bb9eba2303e7aab8fb405c6a83dcfdc502521c
1805+
React-jsiexecutor: 9f0490b2ee12daeb9d936a2538babc2ea18dae5e
1806+
React-jsinspector: 43b6fcec4bc7f24e1b028d0d325303dc5f8112dd
1807+
React-jsinspectortracing: 240cbca9e33331b849d6b20f0d8b0d984994dc6b
1808+
React-jsitracing: 60136e095299445d4322fe0e07ddfdf775d3250e
1809+
React-logger: 8e5c62114dc6a8ae688d6c655dac1bc988892e64
1810+
React-Mapbuffer: f0ac9fd9d7d860258ca7972d1660a05a3550a344
1811+
React-microtasksnativemodule: 82f0c5d8c3862acaede4c139224cfa7970d840a7
1812+
react-native-mmkv: a578df102150a1742d11e741b581bc63edef9771
1813+
React-NativeModulesApple: 001e3bd5b4ec71a6955a8208096dfbfa2849214c
1814+
React-perflogger: e13bcc7a9221c3709d3c8178d9e7f709be4f1350
1815+
React-performancetimeline: 985dbe15d489dd2004d7de871ff464050e90efb4
18161816
React-RCTActionSheet: c5496a827b39f505ffc1d27a52400df58e7a7433
1817-
React-RCTAnimation: 85bd4ea6add91fcebc8d878f77b06e461b56ad71
1818-
React-RCTAppDelegate: 683a918e166b700b246e0fc689f7031647c01c8c
1819-
React-RCTBlob: f81a5529c660e702eba8a49510b80dd73dbc1b99
1820-
React-RCTFabric: 0320d6e5ca090ca22e480508da1c24de22110592
1821-
React-RCTFBReactNativeSpec: d2b96f3e56a8b8a9403ba6a6bef754e5238a44a4
1822-
React-RCTImage: 0be56a9f1eb4751f49ef45fc6ad27e71746d86fd
1823-
React-RCTLinking: 18d73b57aaeca804b842722362ed26ff4685ba49
1824-
React-RCTNetwork: 0740e1a7716e67826e86277a363c14d8cd762733
1825-
React-RCTSettings: 013a99ae1b136d66ab43a6af136f799de59be8a4
1826-
React-RCTText: 64e02ee03d40e880fff0577945059ab13c197e48
1827-
React-RCTVibration: ba41c5511e2631fc85868dc641711c85f7014c0d
1817+
React-RCTAnimation: 2a3fe9a75306411bb35bb076f1460fdc20100424
1818+
React-RCTAppDelegate: dc3ade2dde8eadc00a032348724e244cc17f2f1b
1819+
React-RCTBlob: 8fa27ea21f1d74dfb135a4aa06717a6c0d7137e7
1820+
React-RCTFabric: a3ac9f29a1527be4f0e47453d5e7d8c53e94751d
1821+
React-RCTFBReactNativeSpec: 22e076481266347172337c170126f32cf243fa8f
1822+
React-RCTImage: a3d738fd2f91fde3ed01ecc02e7330ac08fddba3
1823+
React-RCTLinking: 852bf1d4e09642bac25ae9914e1bf526e7a2f482
1824+
React-RCTNetwork: 9258e83aa911199f6b42a95f3f6f1bdfb3d40c73
1825+
React-RCTSettings: aed7da613ab1b362ac60c0ee9ce2cdbaa32c8924
1826+
React-RCTText: 6328e0e445b8b83809cab4eab7662be8b276e585
1827+
React-RCTVibration: 3eb6934cecfd666e03d0ab67984a07be2384396f
18281828
React-rendererconsistency: 7abe42d721328057bcbc198e30a683708a4fed3e
1829-
React-rendererdebug: 3a239d4dc5b17df934ed5d185a28deaafe409e82
1829+
React-rendererdebug: 658c171e28d33b6589f098bdd47f6ad95d475eef
18301830
React-rncore: a0f8d109f16242155e59631d96a128e3d55f1d54
1831-
React-RuntimeApple: 4848dcc033d82c1fec97dda42d26fda9ecb58925
1832-
React-RuntimeCore: de1d1c8bf38be83ffdd8fc538ccb44b401a4d365
1831+
React-RuntimeApple: c08c4216dde3b8881b7ece736a4a9149da483731
1832+
React-RuntimeCore: dc99f3ac9a9c7a66d11c79d941bd900ce9989e68
18331833
React-runtimeexecutor: 4b57851b6252cb71c8812a50e8055cb0086fc180
1834-
React-RuntimeHermes: 296a1196feb18fdd86650ef8c783ffab08a4468c
1835-
React-runtimescheduler: 95db8cc66bb5258540ae76fc1bc635300a1a777e
1834+
React-RuntimeHermes: 65b4c1d4a2424566569811986632b8136c3dccb8
1835+
React-runtimescheduler: 3cdf7c42f85c113e12278ab9ca6dabee56e197ec
18361836
React-timing: 756815d960e39ff0d09ff9c7cb7159299edf0169
1837-
React-utils: ede99de002483095eef4b98f26df5a9ee23fa005
1838-
ReactAppDependencyProvider: 78d1aa823d2f280f83372f9abb50502cee4d0424
1839-
ReactCodegen: f45a37b5b62e02d930ee7097bf484d94d1b5f880
1840-
ReactCommon: 1f166930a8b46ce42b43ba1470ab688cd3ebfdf0
1837+
React-utils: 0ed154e9b14a89a2d5c962ec00cdbad9f02ae0b8
1838+
ReactAppDependencyProvider: 3a460ab76f1149df99ed324bb1c764b76de7a730
1839+
ReactCodegen: 4aab124636ad46be1546ce579d11e864dd1a8bc5
1840+
ReactCommon: 15c98590279f1b5ab3436f4bf14c9f0a123df289
18411841
SocketRocket: 03f7111df1a343b162bf5b06ead333be808e1e0a
18421842
Yoga: 187db0b2a37012c01dac36afb886a29b92bfd943
18431843

0 commit comments

Comments
 (0)