Skip to content

Commit

Permalink
feat: show recording button if set (#26565)
Browse files Browse the repository at this point in the history
  • Loading branch information
daibhin authored Dec 2, 2024
1 parent fab192b commit c0500aa
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 99 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions frontend/src/lib/components/ViewRecordingButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { LemonButton, LemonButtonProps } from '@posthog/lemon-ui'
import { useActions } from 'kea'
import { Dayjs, dayjs } from 'lib/dayjs'
import { IconPlayCircle } from 'lib/lemon-ui/icons'
import { sessionPlayerModalLogic } from 'scenes/session-recordings/player/modal/sessionPlayerModalLogic'
import { urls } from 'scenes/urls'

import { EventType } from '~/types'

export default function ViewRecordingButton({
sessionId,
timestamp,
...props
}: Pick<LemonButtonProps, 'size' | 'type' | 'data-attr' | 'fullWidth' | 'className' | 'disabledReason'> & {
sessionId: string
timestamp?: string | Dayjs
}): JSX.Element {
const { openSessionPlayer } = useActions(sessionPlayerModalLogic)

return (
<LemonButton
to={urls.replaySingle(sessionId)}
onClick={() => {
const fiveSecondsBeforeEvent = dayjs(timestamp).valueOf() - 5000
openSessionPlayer({ id: sessionId }, Math.max(fiveSecondsBeforeEvent, 0))
}}
sideIcon={<IconPlayCircle />}
{...props}
>
View recording
</LemonButton>
)
}

export const mightHaveRecording = (properties: EventType['properties']): boolean => {
return properties.$session_id
? properties.$recording_status
? properties.$recording_status === 'active'
: true
: false
}
37 changes: 13 additions & 24 deletions frontend/src/queries/nodes/DataTable/EventRowActions.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { useActions } from 'kea'
import { dayjs } from 'lib/dayjs'
import { IconLink, IconPlayCircle } from 'lib/lemon-ui/icons'
import ViewRecordingButton, { mightHaveRecording } from 'lib/components/ViewRecordingButton'
import { IconLink } from 'lib/lemon-ui/icons'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { More } from 'lib/lemon-ui/LemonButton/More'
import { copyToClipboard } from 'lib/utils/copyToClipboard'
import { getCurrentTeamId } from 'lib/utils/getAppContext'
import { createActionFromEvent } from 'scenes/activity/explore/createActionFromEvent'
import { insightUrlForEvent } from 'scenes/insights/utils'
import { sessionPlayerModalLogic } from 'scenes/session-recordings/player/modal/sessionPlayerModalLogic'
import { teamLogic } from 'scenes/teamLogic'
import { urls } from 'scenes/urls'

Expand All @@ -18,7 +16,6 @@ interface EventActionProps {
}

export function EventRowActions({ event }: EventActionProps): JSX.Element {
const { openSessionPlayer } = useActions(sessionPlayerModalLogic)
const insightUrl = insightUrlForEvent(event)

return (
Expand Down Expand Up @@ -56,25 +53,17 @@ export function EventRowActions({ event }: EventActionProps): JSX.Element {
Copy link to event
</LemonButton>
)}
{!!event.properties?.$session_id && (
<LemonButton
to={urls.replaySingle(event.properties.$session_id)}
onClick={(e) => {
e.preventDefault()
if (event.properties.$session_id) {
openSessionPlayer(
{ id: event.properties.$session_id },
dayjs(event.timestamp).valueOf()
)
}
}}
fullWidth
sideIcon={<IconPlayCircle />}
data-attr="events-table-usage"
>
View recording
</LemonButton>
)}
<ViewRecordingButton
fullWidth
sessionId={event.properties.$session_id}
timestamp={event.timestamp}
disabledReason={
mightHaveRecording(event.properties)
? undefined
: 'Replay was not active when capturing this event'
}
data-attr="events-table-usage"
/>
{insightUrl && (
<LemonButton to={insightUrl} fullWidth data-attr="events-table-usage">
Try out in Insights
Expand Down
44 changes: 14 additions & 30 deletions frontend/src/queries/nodes/HogQLX/render.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { LemonButton, Link } from '@posthog/lemon-ui'
import { useActions } from 'kea'
import { Link } from '@posthog/lemon-ui'
import { JSONViewer } from 'lib/components/JSONViewer'
import { Sparkline } from 'lib/components/Sparkline'
import { IconPlayCircle } from 'lib/lemon-ui/icons'
import { sessionPlayerModalLogic } from 'scenes/session-recordings/player/modal/sessionPlayerModalLogic'
import { urls } from 'scenes/urls'
import ViewRecordingButton from 'lib/components/ViewRecordingButton'

import { ErrorBoundary } from '~/layout/ErrorBoundary'

Expand All @@ -24,30 +21,6 @@ export function parseHogQLX(value: any): any {
return value.map((v) => parseHogQLX(v))
}

function ViewRecordingModalButton({ sessionId }: { sessionId: string }): JSX.Element {
const { openSessionPlayer } = useActions(sessionPlayerModalLogic)
return (
<ErrorBoundary>
<LemonButton
type="primary"
size="xsmall"
sideIcon={<IconPlayCircle />}
data-attr="hog-ql-view-recording-button"
to={urls.replaySingle(sessionId)}
onClick={(e) => {
e.preventDefault()
if (sessionId) {
openSessionPlayer({ id: sessionId })
}
}}
className="inline-block"
>
View recording
</LemonButton>
</ErrorBoundary>
)
}

export function renderHogQLX(value: any): JSX.Element {
const object = parseHogQLX(value)

Expand All @@ -68,7 +41,18 @@ export function renderHogQLX(value: any): JSX.Element {
)
} else if (tag === 'RecordingButton') {
const { sessionId, ...props } = rest
return <ViewRecordingModalButton sessionId={sessionId} {...props} />
return (
<ErrorBoundary>
<ViewRecordingButton
sessionId={sessionId}
type="primary"
size="xsmall"
data-attr="hog-ql-view-recording-button"
className="inline-block"
{...props}
/>
</ErrorBoundary>
)
} else if (tag === 'a') {
const { href, source, target } = rest
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { ReadingHog } from 'lib/components/hedgehogs'
import { ProductIntroduction } from 'lib/components/ProductIntroduction/ProductIntroduction'
import { Sparkline } from 'lib/components/Sparkline'
import { TZLabel } from 'lib/components/TZLabel'
import { IconPlayCircle } from 'lib/lemon-ui/icons'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import ViewRecordingButton from 'lib/components/ViewRecordingButton'
import { LemonTable } from 'lib/lemon-ui/LemonTable'
import { Link } from 'lib/lemon-ui/Link'
import { urls } from 'scenes/urls'
Expand Down Expand Up @@ -155,15 +154,13 @@ const WARNING_TYPE_RENDERER = {
<li>session_id: {details.session_id}</li>
</ul>
<div className="max-w-30 mt-2">
<LemonButton
<ViewRecordingButton
sessionId={details.session_id}
timestamp={details.timestamp}
type="primary"
size="xsmall"
to={urls.replaySingle(details.session_id)}
sideIcon={<IconPlayCircle />}
data-attr="skewed-timestamp-view-recording"
>
View recording
</LemonButton>
/>
</div>
</>
)
Expand All @@ -188,15 +185,13 @@ const WARNING_TYPE_RENDERER = {
<li>skew: {details.daysFromNow} days</li>
</ul>
<div className="max-w-30 mt-2">
<LemonButton
<ViewRecordingButton
sessionId={details.session_id}
timestamp={details.timestamp}
type="primary"
size="xsmall"
to={urls.replaySingle(details.session_id)}
sideIcon={<IconPlayCircle />}
data-attr="skewed-timestamp-view-recording"
>
View recording
</LemonButton>
/>
</div>
</>
)
Expand All @@ -216,15 +211,13 @@ const WARNING_TYPE_RENDERER = {
<li>session_id: {details.session_id}</li>
</ul>
<div className="max-w-30 mt-2">
<LemonButton
<ViewRecordingButton
sessionId={details.session_id}
timestamp={details.timestamp}
type="primary"
size="xsmall"
to={urls.replaySingle(details.session_id)}
sideIcon={<IconPlayCircle />}
data-attr="message-too-large-view-recording"
>
View recording
</LemonButton>
/>
</div>
</>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Scene } from 'scenes/sceneTypes'
import { urls } from 'scenes/urls'

import { ErrorTrackingIssue } from '~/queries/schema'
import { Breadcrumb } from '~/types'
import { Breadcrumb, EventType } from '~/types'

import type { errorTrackingIssueSceneLogicType } from './errorTrackingIssueSceneLogicType'
import { errorTrackingLogic } from './errorTrackingLogic'
Expand All @@ -16,7 +16,7 @@ import { errorTrackingIssueEventsQuery, errorTrackingIssueQuery } from './querie
export interface ErrorTrackingEvent {
uuid: string
timestamp: Dayjs
properties: Record<string, any>
properties: EventType['properties']
person: {
distinct_id: string
uuid?: string
Expand Down
34 changes: 11 additions & 23 deletions frontend/src/scenes/error-tracking/groups/OverviewTab.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { PersonDisplay, TZLabel } from '@posthog/apps-common'
import { LemonButton } from '@posthog/lemon-ui'
import clsx from 'clsx'
import { useActions, useValues } from 'kea'
import { EmptyMessage } from 'lib/components/EmptyMessage/EmptyMessage'
import { ErrorDisplay } from 'lib/components/Errors/ErrorDisplay'
import { Playlist } from 'lib/components/Playlist/Playlist'
import { dayjs } from 'lib/dayjs'
import { sessionPlayerModalLogic } from 'scenes/session-recordings/player/modal/sessionPlayerModalLogic'
import ViewRecordingButton, { mightHaveRecording } from 'lib/components/ViewRecordingButton'
import { PropertyIcons } from 'scenes/session-recordings/playlist/SessionRecordingPreview'

import { ErrorTrackingEvent, errorTrackingIssueSceneLogic } from '../errorTrackingIssueSceneLogic'
Expand Down Expand Up @@ -38,7 +36,16 @@ export const OverviewTab = (): JSX.Element => {
event ? (
<div className="h-full overflow-auto">
<div className="bg-bg-light p-1 flex justify-end border-b min-h-[42px]">
<ViewSessionButton event={event} />
<ViewRecordingButton
size="small"
sessionId={event.properties.$session_id}
timestamp={event.timestamp}
disabledReason={
mightHaveRecording(event.properties)
? undefined
: 'Replay was not active when capturing this event'
}
/>
</div>
<div className="pl-2">
<ErrorDisplay eventProperties={event.properties} />
Expand All @@ -62,25 +69,6 @@ export const OverviewTab = (): JSX.Element => {
)
}

const ViewSessionButton = ({ event }: { event: ErrorTrackingEvent }): JSX.Element | null => {
const { openSessionPlayer } = useActions(sessionPlayerModalLogic)

const sessionId = event.properties.$session_id

return (
<LemonButton
size="small"
onClick={() => {
const fiveSecondsBeforeEvent = dayjs(event.timestamp).valueOf() - 5000
openSessionPlayer({ id: sessionId }, Math.max(fiveSecondsBeforeEvent, 0))
}}
disabledReason={!sessionId ? 'There was no Session ID associated with this exception' : undefined}
>
View recording
</LemonButton>
)
}

const ListItemException = ({
item: { timestamp, properties, person },
isActive,
Expand Down

0 comments on commit c0500aa

Please sign in to comment.