Skip to content

Commit 1f4cc7a

Browse files
niieanibbrzoska
authored andcommitted
feat: rendering of computed render beacon spans
1 parent 9093d32 commit 1f4cc7a

File tree

1 file changed

+97
-23
lines changed

1 file changed

+97
-23
lines changed

src/v3/TraceManagerDebugger.tsx

Lines changed: 97 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
isTerminalState,
1515
} from './Trace'
1616
import type { TraceManager } from './TraceManager'
17+
import type { ComputedRenderSpan, ComputedSpan } from './traceRecordingTypes'
1718
import type {
1819
RelationSchemasBase,
1920
TraceContext,
@@ -559,6 +560,14 @@ function getStateStyle(state: string) {
559560

560561
const TRACE_HISTORY_LIMIT = 15
561562

563+
// Helper to safely get a value from a possibly empty object
564+
function getFromRecord<T>(
565+
record: Record<string, T> | undefined,
566+
key: string,
567+
): T | undefined {
568+
return record && Object.hasOwn(record, key) ? record[key] : undefined
569+
}
570+
562571
// TraceAttributes component to display attributes as chips
563572
function TraceAttributes({
564573
attributes,
@@ -754,6 +763,57 @@ function RequiredSpansList<RelationSchemasT>({
754763
)
755764
}
756765

766+
// Helper to render ComputedSpan nicely
767+
function RenderComputedSpan({ value }: { value: ComputedSpan }) {
768+
if (!value) return null
769+
return (
770+
<span style={{ marginLeft: 8, color: '#1976d2' }}>
771+
start: {value.startOffset.toFixed(2)}ms, duration:{' '}
772+
{value.duration.toFixed(2)}ms
773+
</span>
774+
)
775+
}
776+
777+
// Helper to render ComputedRenderSpan nicely
778+
function RenderComputedRenderSpan({ value }: { value: ComputedRenderSpan }) {
779+
if (!value) return null
780+
return (
781+
<span style={{ marginLeft: 8, color: '#1976d2' }}>
782+
start: {value.startOffset.toFixed(2)}ms, loading:{' '}
783+
{value.firstRenderTillLoading.toFixed(2)}ms, data:{' '}
784+
{value.firstRenderTillData.toFixed(2)}ms, content:{' '}
785+
{value.firstRenderTillContent.toFixed(2)}ms, renders: {value.renderCount},
786+
total: {value.sumOfRenderDurations.toFixed(2)}ms
787+
</span>
788+
)
789+
}
790+
791+
// Helper to render ComputedRenderBeaconSpans nicely
792+
function RenderComputedRenderBeaconSpans({
793+
computedRenderBeaconSpans,
794+
}: {
795+
computedRenderBeaconSpans: Record<string, ComputedRenderSpan>
796+
}) {
797+
if (
798+
!computedRenderBeaconSpans ||
799+
Object.keys(computedRenderBeaconSpans).length === 0
800+
)
801+
return null
802+
return (
803+
<div style={styles.section}>
804+
<div style={styles.sectionTitle}>Computed Render Beacon Spans:</div>
805+
<ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>
806+
{Object.entries(computedRenderBeaconSpans).map(([name, value]) => (
807+
<li key={name} style={styles.listItem}>
808+
{name}
809+
<RenderComputedRenderSpan value={value} />
810+
</li>
811+
))}
812+
</ul>
813+
</div>
814+
)
815+
}
816+
757817
// Function to download trace recording as a JSON file
758818
function downloadTraceRecording<
759819
RelationSchemasT extends RelationSchemasBase<RelationSchemasT>,
@@ -819,7 +879,11 @@ function TraceItem<
819879
if (trace.traceContext && trace.finalTransition) {
820880
return getComputedResults(trace.traceContext, trace.finalTransition)
821881
}
822-
return { computedSpans: {}, computedValues: {} }
882+
return {
883+
computedSpans: {},
884+
computedValues: {},
885+
computedRenderBeaconSpans: {},
886+
}
823887
}, [trace.traceContext, trace.finalTransition])
824888

825889
// Handle download button click without triggering the expand/collapse
@@ -1003,16 +1067,14 @@ function TraceItem<
10031067
<div style={styles.sectionTitle}>Computed Spans:</div>
10041068
<ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>
10051069
{(trace.computedSpans ?? []).map((name) => {
1006-
const value = computedResults.computedSpans?.[name]
1070+
const value = getFromRecord(computedResults.computedSpans, name)
10071071
return (
10081072
<li key={name} style={styles.listItem}>
10091073
{name}
10101074
{trace.state === 'complete' ||
10111075
trace.state === 'interrupted' ? (
10121076
value ? (
1013-
<span style={{ marginLeft: 8, color: '#1976d2' }}>
1014-
{JSON.stringify(value)}
1015-
</span>
1077+
<RenderComputedSpan value={value} />
10161078
) : (
10171079
<span
10181080
style={{
@@ -1030,27 +1092,39 @@ function TraceItem<
10301092
})}
10311093
</ul>
10321094
</div>
1095+
{'computedRenderBeaconSpans' in computedResults &&
1096+
computedResults.computedRenderBeaconSpans &&
1097+
Object.keys(computedResults.computedRenderBeaconSpans).length > 0 ? (
1098+
<RenderComputedRenderBeaconSpans
1099+
computedRenderBeaconSpans={
1100+
computedResults.computedRenderBeaconSpans
1101+
}
1102+
/>
1103+
) : null}
10331104
<div style={styles.section}>
10341105
<div style={styles.sectionTitle}>Computed Values:</div>
10351106
<ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>
1036-
{(trace.computedValues ?? []).map((name) => (
1037-
<li key={name} style={styles.listItem}>
1038-
{name}
1039-
{trace.state === 'complete' || trace.state === 'interrupted'
1040-
? (() => {
1041-
const value = computedResults.computedValues?.[name]
1042-
if (value !== undefined) {
1043-
return (
1044-
<span style={{ marginLeft: 8, color: '#1976d2' }}>
1045-
{String(value)}
1046-
</span>
1047-
)
1048-
}
1049-
return null
1050-
})()
1051-
: null}
1052-
</li>
1053-
))}
1107+
{(trace.computedValues ?? []).map((name) => {
1108+
const value = getFromRecord<string | number | boolean>(
1109+
computedResults.computedValues as Record<
1110+
string,
1111+
string | number | boolean
1112+
>,
1113+
name,
1114+
)
1115+
return (
1116+
<li key={name} style={styles.listItem}>
1117+
{name}
1118+
{trace.state === 'complete' || trace.state === 'interrupted'
1119+
? value !== undefined && (
1120+
<span style={{ marginLeft: 8, color: '#1976d2' }}>
1121+
{String(value)}
1122+
</span>
1123+
)
1124+
: null}
1125+
</li>
1126+
)
1127+
})}
10541128
</ul>
10551129
</div>
10561130
{/* Definition modifications details */}

0 commit comments

Comments
 (0)