Conversation
|
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.
How to use the Graphite Merge QueueAdd 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. |
PR Review: Traces Timeline UIThis PR adds a timeline visualization view for traces in the dashboard, complementing the existing list view. The implementation includes gap detection/collapsing, zoom/pan controls, and interactive span selection. 🟢 StrengthsCode Organization
UX Features
🔴 Critical Issues1. Broken Timeline View Integration (actor-traces.tsx:149-167)The timeline view is integrated but with placeholder implementations that throw errors: onSelectSpan={(spanId: string | null): void => {
throw new Error("Function not implemented.");
}}
onSelectEvent={(spanId: string, eventIndex: number): void => {
throw new Error("Function not implemented.");
}}Impact: The timeline view will crash when users click on any span or event. Fix: Implement proper state management. 2. Type Safety Issues (types.ts)Multiple export type SpanNode = {
endTimeUnixNano: any; // Should be: bigint | null
startTimeUnixNano: any; // Should be: bigint
name: ReactNode; // Should probably be: string
spanId: string | null; // Can spanId actually be null?
}Impact: Runtime type errors, loss of IDE autocomplete, harder debugging. 3. Inconsistent Property UsageThe SpanNode type has duplicate/inconsistent timestamp properties:
Used inconsistently throughout:
Impact: Potential runtime errors, confusing codebase. 4. Missing Null Checks (utils.ts:38)If 5. Incorrect Duration Check (utils.ts:5)export function isSpanInProgress(span: SpanNode): boolean {
return span.endNs === undefined;
}Per the type definition, 🟡 Major Issues6. BigInt Arithmetic (traces-timeline.tsx:467-470)If timestamps are bigints, you need to convert to Number before division. 7. Performance: Multiple Date.now() Calls
8. Unused SpanSidebar Component
9. Missing Event HandlersTimeline view references 10. Accessibility Issues
🟢 Minor Issues11. Magic NumbersConstants lack explanation: const GAP_THRESHOLD_MS = 50; // Why 50ms?
const GAP_FIXED_WIDTH_PX = 48; // Why 48px?
const MIN_ACTIVE_SEGMENT_WIDTH_PX = 8; // Why 8px?12. Missing Error HandlingNo error boundaries or try-catch blocks. If span data is malformed, the entire component will crash. 13. Sorting Assumption (utils.ts:52-53)If timestamps are bigints, subtraction won't work for sorting. Use comparison operators instead. 📋 RecommendationsHigh Priority
Medium Priority
Low Priority
🎯 Test CoverageMissing tests for:
SummaryThis is a solid foundation for a timeline visualization feature with good architecture and performance considerations. However, it cannot be merged in its current state due to the broken click handlers and type safety issues. The core algorithms look sound, but need type fixes and null handling before they're production-ready. Recommendation: Request changes - Fix critical issues #1-5 before merging. |
63d40ba to
d77a4fc
Compare
2a858f0 to
d559f28
Compare
d559f28 to
dff6754
Compare
d77a4fc to
828baf3
Compare
More templates
@rivetkit/cloudflare-workers
@rivetkit/db
@rivetkit/framework-base
@rivetkit/next-js
@rivetkit/react
rivetkit
@rivetkit/sql-loader
@rivetkit/traces
@rivetkit/workflow-engine
@rivetkit/virtual-websocket
@rivetkit/engine-runner
@rivetkit/engine-runner-protocol
commit: |
828baf3 to
a316801
Compare
e4ac15a to
a18121c
Compare
a316801 to
3d621b9
Compare
940cd33 to
9c70402
Compare
a18121c to
f49653b
Compare
Graphite Automations"Test" took an action on this PR • (02/05/26)1 assignee was added to this PR based on Kacper Wojciechowski's automation. |
9c70402 to
0ad0c4d
Compare
| import type { | ||
| OtlpAnyValue, | ||
| OtlpExportTraceServiceRequestJson, | ||
| OtlpKeyValue, | ||
| OtlpSpan, | ||
| OtlpSpanEvent, | ||
| } from "@rivetkit/traces"; | ||
| import { readRangeWireToOtlp } from "@rivetkit/traces/otlp"; | ||
| import { useQuery } from "@tanstack/react-query"; | ||
| import { format } from "date-fns"; | ||
| import { | ||
| useMemo, | ||
| useState, | ||
| type ReactElement, | ||
| } from "react"; | ||
| import { type ReactElement, useMemo, useState } from "react"; |
There was a problem hiding this comment.
Imports are not sorted correctly according to Biome's rules. React imports should come first, followed by third-party imports in alphabetical order, then local imports. Consider reorganizing these imports.
Spotted by Graphite Agent (based on CI logs)
Is this helpful? React 👍 or 👎 to let us know.
0ad0c4d to
df3efc4
Compare
| <button | ||
| key={`${span.spanId}-event-${idx}`} | ||
| onClick={() => | ||
| onSelectEvent(span.spanId, idx) | ||
| } | ||
| className={cn( | ||
| "w-full flex items-center gap-2 px-2 py-1.5 rounded text-left text-sm transition-colors", | ||
| isEventSelected | ||
| ? "bg-accent text-accent-foreground" | ||
| : "hover:bg-accent/50 text-muted-foreground", | ||
| )} | ||
| > | ||
| <Icon | ||
| icon={faCircle} | ||
| className="size-2 shrink-0 fill-current" | ||
| /> | ||
| <span className="truncate"> | ||
| {event.name} | ||
| </span> | ||
| </button> |
There was a problem hiding this comment.
This button element is missing a type attribute. Add type="button" to prevent potential form submission issues.
Spotted by Graphite Agent (based on CI logs)
Is this helpful? React 👍 or 👎 to let us know.
| {ticks.map((tick, i) => ( | ||
| <div | ||
| key={i} | ||
| className={cn( | ||
| "absolute top-0 h-full flex flex-col items-center", | ||
| tick.isGapLabel && "z-10", | ||
| )} | ||
| style={{ left: tick.position }} | ||
| > | ||
| {tick.isGapLabel ? ( | ||
| <> | ||
| <div | ||
| className="h-full w-px bg-muted-foreground/30" | ||
| style={{ | ||
| backgroundImage: | ||
| "repeating-linear-gradient(to bottom, transparent, transparent 2px, hsl(var(--muted-foreground) / 0.3) 2px, hsl(var(--muted-foreground) / 0.3) 4px)", | ||
| }} | ||
| /> | ||
| <span className="absolute top-1/2 -translate-y-1/2 text-[10px] text-muted-foreground bg-background/95 px-1.5 py-0.5 rounded border border-border whitespace-nowrap"> | ||
| {tick.label} skipped | ||
| </span> | ||
| </> | ||
| ) : ( | ||
| <> | ||
| <div className="h-2 w-px bg-border" /> | ||
| <span className="text-[10px] text-muted-foreground mt-0.5"> | ||
| {tick.label} | ||
| </span> | ||
| </> | ||
| )} | ||
| </div> | ||
| ))} |
There was a problem hiding this comment.
Using array index 'i' as a React key can cause rendering issues when items are reordered. Use a unique identifier from the tick object or create a compound key like tick.position-${i}.
Spotted by Graphite Agent (based on CI logs)
Is this helpful? React 👍 or 👎 to let us know.
| <Button | ||
| variant="ghost" | ||
| size="icon" | ||
| className="size-8" | ||
| onClick={handleZoomOut} | ||
| > | ||
| <Icon icon={faMagnifyingGlassMinus} className="size-4" /> | ||
| </Button> | ||
| <Button | ||
| variant="ghost" | ||
| size="icon" | ||
| className="size-8" | ||
| onClick={handleZoomReset} | ||
| > | ||
| <Icon icon={faMinusLarge} className="size-4" /> | ||
| </Button> | ||
| <Button | ||
| variant="ghost" | ||
| size="icon" | ||
| className="size-8" | ||
| onClick={handleZoomIn} | ||
| > | ||
| <Icon icon={faMagnifyingGlassPlus} className="size-4" /> | ||
| </Button> |
There was a problem hiding this comment.
These Button components may need explicit type="button" attributes if they're not already provided by the Button component implementation.
Spotted by Graphite Agent (based on CI logs)
Is this helpful? React 👍 or 👎 to let us know.
| <button | ||
| onClick={() => onSelectSpan(span.spanId)} | ||
| className={cn( | ||
| "flex-1 flex items-center gap-2 px-2 py-1.5 rounded text-left text-sm transition-colors min-w-0", | ||
| isSelected | ||
| ? "bg-accent text-accent-foreground" | ||
| : "hover:bg-accent/50", | ||
| )} | ||
| > | ||
| {inProgress && ( | ||
| <Icon | ||
| icon={faSpinnerThird} | ||
| className="size-3 shrink-0 animate-spin" | ||
| /> | ||
| )} | ||
| <span className="truncate flex-1">{span.span.name}</span> | ||
| {durationMs !== null && ( | ||
| <span className="text-xs text-muted-foreground shrink-0"> | ||
| {formatDuration(Number(durationMs))} | ||
| </span> | ||
| )} | ||
| </button> |
There was a problem hiding this comment.
This button element is missing a type attribute. Add type="button" to prevent potential form submission issues.
Spotted by Graphite Agent (based on CI logs)
Is this helpful? React 👍 or 👎 to let us know.
f49653b to
c2e901e
Compare
df3efc4 to
d4d11ba
Compare
Merge activity
|

No description provided.