Repository navigation
feat: browser events in session replay #3440
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@hyperdx/app': patch | ||
| --- | ||
|
|
||
| feat: Session replay shows clicks, navigations, console output and exceptions from OpenTelemetry browser SDKs |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import { ComponentProps, use, useEffect } from 'react'; | ||
| import { SourceKind } from '@hyperdx/common-utils/dist/types'; | ||
| import { Loader } from '@mantine/core'; | ||
|
|
||
| import { | ||
| DBRowSidePanelInner, | ||
| RowSidePanelContext, | ||
| } from '@/components/DBRowSidePanel'; | ||
| import { useSource } from '@/source'; | ||
|
|
||
| type EventPanelProps = ComponentProps<typeof DBRowSidePanelInner>; | ||
|
|
||
| /** | ||
| * The session drawer's event view. A browser log event opens on its log | ||
| * source; everything else on the trace source passed in `source`. | ||
| */ | ||
| export default function SessionEventSourcePanel({ | ||
| sourceId, | ||
| ...props | ||
| }: EventPanelProps & { sourceId?: string }) { | ||
| return sourceId ? ( | ||
| <LogSourceEventPanel {...props} sourceId={sourceId} /> | ||
| ) : ( | ||
| <DBRowSidePanelInner {...props} /> | ||
| ); | ||
| } | ||
|
|
||
| function LogSourceEventPanel({ | ||
| sourceId, | ||
| ...props | ||
| }: EventPanelProps & { sourceId: string }) { | ||
| const { data: source, isLoading } = useSource({ | ||
| id: sourceId, | ||
| kinds: [SourceKind.Log], | ||
| }); | ||
| const context = use(RowSidePanelContext); | ||
| const { onNavigateToParent } = props; | ||
| const isMissing = !isLoading && source == null; | ||
|
|
||
| // A link to a deleted source falls back to the session. | ||
| useEffect(() => { | ||
| if (isMissing) { | ||
| onNavigateToParent?.(); | ||
| } | ||
| }, [isMissing, onNavigateToParent]); | ||
|
|
||
| if (source == null) { | ||
| return <Loader />; | ||
| } | ||
| return ( | ||
| <RowSidePanelContext value={{ ...context, source }}> | ||
| <DBRowSidePanelInner {...props} source={source} /> | ||
| </RowSidePanelContext> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,6 +57,7 @@ import { | |
| getRowLookupWindow, | ||
| resolveRowTimestampAnchor, | ||
| } from '@/utils/rowTimestamps'; | ||
| import type { SessionEventNavigate } from '@/utils/sessionLogEvents'; | ||
| import { useZIndex, ZIndexContext } from '@/zIndex'; | ||
|
|
||
| import ServiceMapSidePanel from './ServiceMap/ServiceMapSidePanel'; | ||
|
|
@@ -618,19 +619,37 @@ export const DBRowSidePanelInner = ({ | |
| return clauses.length > 0 ? clauses.join(' AND ') : undefined; | ||
| }, [traceIdExpression, traceId, spanIdExpression, spanId]); | ||
|
|
||
| const handleSessionEventNavigate = useCallback( | ||
| (rowId: string, aliasWith: WithClause[]) => { | ||
| if (traceSourceData) { | ||
| const handleSessionEventNavigate = useCallback<SessionEventNavigate>( | ||
| (rowId, aliasWith, target) => { | ||
| const label = mainContent || 'Session Replay'; | ||
| if (target?.sourceId === source.id) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟠 major — Opening a same-source log event from the Session Replay tab leaves the panel on the Replay tab, so the clicked row is never shown For a log row whose source is the trace's linked log source, Nothing blocks merge automatically, but a maintainer will expect this fixed if it is a real defect in code this PR changes. If it is about surrounding code, reply and say so instead of patching. Do not widen the PR. How to respond |
||
| handleNavigateToRow(rowId, aliasWith, label, SourceKind.Log); | ||
|
Comment on lines
+625
to
+626
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When a user opens Session Replay from a log and selects a browser event on the same log source, |
||
| } else if (target != null) { | ||
| handleSourceStackPush({ | ||
| sourceId: target.sourceId, | ||
| rowId, | ||
| aliasWith, | ||
| label, | ||
| sourceKind: SourceKind.Log, | ||
| focusTimestamp: target.focusTimestamp, | ||
| }); | ||
| } else if (traceSourceData) { | ||
| handleSourceStackPush({ | ||
| sourceId: traceSourceData.id, | ||
| rowId, | ||
| aliasWith, | ||
| label: mainContent || 'Session Replay', | ||
| label, | ||
| sourceKind: traceSourceData.kind as SourceKind, | ||
| }); | ||
| } | ||
| }, | ||
| [traceSourceData, handleSourceStackPush, mainContent], | ||
| [ | ||
| traceSourceData, | ||
| source.id, | ||
| handleNavigateToRow, | ||
| handleSourceStackPush, | ||
| mainContent, | ||
| ], | ||
| ); | ||
|
|
||
| const handleTraceLogNavigate = useCallback( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SessionEventList.tsxgrows from 298 to 310 lines. The repository guide requires component files to stay under 300 lines, so this requirement must be met before merging. ExtractEventRowinto a sibling component to keep the file within that limit.Context Used: AGENTS.md (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!