Skip to content

feat(dashboard): traces timeline ui#4056

Draft
jog1t wants to merge 1 commit into02-04-fix_traces_separate_entrypointsfrom
01-28-feat_dashboard_traces_timeline_ui
Draft

feat(dashboard): traces timeline ui#4056
jog1t wants to merge 1 commit into02-04-fix_traces_separate_entrypointsfrom
01-28-feat_dashboard_traces_timeline_ui

Conversation

@jog1t
Copy link
Contributor

@jog1t jog1t commented Jan 28, 2026

No description provided.

Copy link
Contributor Author

jog1t commented Jan 28, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more


How to use the Graphite Merge Queue

Add the label merge-queue to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@claude
Copy link

claude bot commented Jan 28, 2026

PR Review: Traces Timeline UI

This PR adds a new timeline view for visualizing actor traces in the dashboard. The implementation is comprehensive and includes several sophisticated features like gap detection and time compression. Here's my detailed review:

Code Quality & Architecture

Strengths:

  • Clean component separation with dedicated files for sidebar, timeline, types, and utilities
  • Good use of TypeScript for type safety
  • Efficient memoization with useMemo for expensive calculations
  • Responsive UI with proper loading states and empty states

Issues:

  1. Type Safety Issues (frontend/src/components/actors/traces/types.ts:10-21)

The SpanNode type has several inconsistencies:

export type SpanNode = {
    timeUnixNano: bigint;
    spanId: string | null;
    endTimeUnixNano: any;  // ❌ Using any
    startTimeUnixNano: any; // ❌ Using any
    name: ReactNode;        // ❌ Should be string
    span: OtlpSpan;
    startNs: bigint;
    endNs: bigint | null;
    children: SpanNode[];
    events: OtlpSpanEvent[];
};

Issues:

  • endTimeUnixNano and startTimeUnixNano are typed as any - these should be bigint | null or bigint
  • name is typed as ReactNode but used as a string throughout (e.g., span.span.name in span-sidebar.tsx:132)
  • Redundant fields: timeUnixNano vs startNs, startTimeUnixNano vs startNs - this creates confusion about which field to use
  • spanId can be string | null but is used as string without null checks (e.g., utils.ts:38)
  1. Dead Code in actor-traces.tsx

The old TracesTimelineView component (lines 259-648 in the diff) appears to be dead code that should be removed. It's replaced by the new modular components but wasn't cleaned up.

  1. Placeholder Implementations (frontend/src/components/actors/actor-traces.tsx:153-162)
onSelectSpan={(spanId: string | null): void => {
    throw new Error("Function not implemented.");
}}
onSelectEvent={(spanId: string, eventIndex: number): void => {
    throw new Error("Function not implemented.");
}}

These throw errors instead of being implemented. This will crash the app if users interact with the timeline view.

Potential Bugs

  1. BigInt Division in span-sidebar.tsx:92
const durationMs = span.endNs
    ? (span.endNs - span.startNs) / 1_000_000n
    : null;

Then on line 135: formatDuration(Number(durationMs)) - This converts BigInt to Number. For very large durations, this could lose precision. Consider doing the conversion differently or using a dedicated bigint formatter.

  1. Inconsistent Property Access (frontend/src/components/actors/traces/traces-timeline.tsx:1479-1483)
const durationMs = span.endTimeUnixNano
    ? (span.endTimeUnixNano - span.startTimeUnixNano) / 1_000_000
    : null;

This uses endTimeUnixNano and startTimeUnixNano but elsewhere the code uses endNs and startNs. Due to the any typing, TypeScript won't catch if these properties don't exist on the actual span objects.

  1. Missing Null Check (frontend/src/components/actors/traces/span-sidebar.tsx:118)
onClick={() => onSelectSpan(span.spanId)}

spanId is typed as string | null but passed directly without null handling.

  1. Incorrect isSpanInProgress Implementation (frontend/src/components/actors/traces/utils.ts:5)
export function isSpanInProgress(span: SpanNode): boolean {
    return span.endNs === undefined;
}

This checks for undefined, but SpanNode.endNs is typed as bigint | null, so it should check for null instead:

return span.endNs === null;

Performance Considerations

  1. Polling Interval (frontend/src/components/actors/actor-queue.tsx:9)

Adding refetchInterval: 1000 means the queue status is polled every second. This is reasonable for live updates but could be configurable based on whether the user is viewing the traces tab.

  1. Expensive Re-renders

The timeline calculations are properly memoized, but the TimelineView component doesn't have React.memo. For frequently updating traces, this could cause unnecessary re-renders.

  1. Large Span Trees

No virtualization is implemented for the span list. With hundreds or thousands of spans, rendering performance could degrade. Consider using react-virtual or similar.

Security Concerns

No significant security issues identified. The code properly sanitizes and validates data through TypeScript types (once the any types are fixed).

Best Practices & Maintainability

  1. Magic Numbers

Constants like GAP_THRESHOLD_MS = 50, GAP_FIXED_WIDTH_PX = 48, and MIN_ACTIVE_SEGMENT_WIDTH_PX = 8 are well-named and properly extracted.

  1. Missing Documentation

Complex algorithms like detectTimeSegments and createTimeMapper would benefit from JSDoc comments explaining their logic, especially around gap compression.

  1. Error Handling

No error boundaries or error handling for edge cases like:

  • What happens if minTime > maxTime?
  • What if all spans have null endNs?
  • Division by zero in time calculations

Test Coverage

No tests are included in this PR. Given the complexity of the timeline calculations, unit tests for:

  • detectTimeSegments
  • createTimeMapper
  • Time formatting functions
  • Gap detection logic

would significantly improve confidence in the implementation.

Recommendations

Critical (must fix):

  1. Fix type safety issues in types.ts - remove any types
  2. Implement the onSelectSpan and onSelectEvent handlers or remove the timeline view until ready
  3. Fix isSpanInProgress to check for null instead of undefined
  4. Remove dead code (old TracesTimelineView in actor-traces.tsx)

High priority:

  1. Resolve property name inconsistencies (startNs vs startTimeUnixNano)
  2. Add null checks for nullable fields
  3. Consider BigInt precision handling

Nice to have:

  1. Add tests for complex timeline calculations
  2. Add JSDoc for complex functions
  3. Consider virtualizing large span lists
  4. Add error boundaries for the timeline view

Summary

This is a solid implementation of a complex feature with good component architecture and visual polish. However, there are critical type safety issues and unimplemented functionality that need to be addressed before merging. The code shows good understanding of React patterns and performance optimization, but needs refinement in TypeScript usage and completeness.

@jog1t jog1t force-pushed the 01-27-refactor_rivetkit_make_traces_server_only_lib branch from 63d40ba to d77a4fc Compare January 30, 2026 21:29
@jog1t jog1t force-pushed the 01-28-feat_dashboard_traces_timeline_ui branch from 2a858f0 to d559f28 Compare January 30, 2026 21:29
@jog1t jog1t changed the base branch from 01-27-refactor_rivetkit_make_traces_server_only_lib to graphite-base/4056 February 4, 2026 22:11
@jog1t jog1t force-pushed the 01-28-feat_dashboard_traces_timeline_ui branch from d559f28 to dff6754 Compare February 4, 2026 22:11
@jog1t jog1t force-pushed the graphite-base/4056 branch from d77a4fc to 828baf3 Compare February 4, 2026 22:11
@jog1t jog1t changed the base branch from graphite-base/4056 to 02-04-fix_traces_separate_entrypoints February 4, 2026 22:11
@jog1t jog1t mentioned this pull request Feb 4, 2026
11 tasks
@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 4, 2026

More templates

@rivetkit/cloudflare-workers

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/cloudflare-workers@4056

@rivetkit/db

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/db@4056

@rivetkit/framework-base

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/framework-base@4056

@rivetkit/next-js

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/next-js@4056

@rivetkit/react

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/react@4056

rivetkit

pnpm add https://pkg.pr.new/rivet-dev/rivet/rivetkit@4056

@rivetkit/sql-loader

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/sql-loader@4056

@rivetkit/traces

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/traces@4056

@rivetkit/workflow-engine

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/workflow-engine@4056

@rivetkit/virtual-websocket

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/virtual-websocket@4056

@rivetkit/engine-runner

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner@4056

@rivetkit/engine-runner-protocol

pnpm add https://pkg.pr.new/rivet-dev/rivet/@rivetkit/engine-runner-protocol@4056

commit: a18121c

@jog1t jog1t force-pushed the 02-04-fix_traces_separate_entrypoints branch from 828baf3 to a316801 Compare February 4, 2026 22:17
@jog1t jog1t force-pushed the 01-28-feat_dashboard_traces_timeline_ui branch from dff6754 to e4ac15a Compare February 4, 2026 22:17
@jog1t jog1t force-pushed the 01-28-feat_dashboard_traces_timeline_ui branch from e4ac15a to a18121c Compare February 4, 2026 22:57
@jog1t jog1t force-pushed the 02-04-fix_traces_separate_entrypoints branch from a316801 to 3d621b9 Compare February 4, 2026 22:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant