Skip to content

Commit

Permalink
feat(web-analytics): Add a replay tile to web analytics (#24259)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
robbie-c and github-actions[bot] authored Aug 8, 2024
1 parent 5967d96 commit 5194187
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 41 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ export const FEATURE_FLAGS = {
SETTINGS_SESSION_TABLE_VERSION: 'settings-session-table-version', // owner: @robbie-c
FIRST_TIME_FOR_USER_MATH: 'first-time-for-user-math', // owner: @skoob13 #team-product-analytics
MULTITAB_EDITOR: 'multitab-editor', // owner: @EDsCODE #team-data-warehouse
WEB_ANALYTICS_REPLAY: 'web-analytics-replay', // owner: @robbie-c
} as const
export type FeatureFlagKey = (typeof FEATURE_FLAGS)[keyof typeof FEATURE_FLAGS]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ export const sessionRecordingsPlaylistLogic = kea<sessionRecordingsPlaylistLogic
if (props.pinnedRecordings !== oldProps.pinnedRecordings) {
actions.loadPinnedRecordings()
}
if (props.filters && props.filters !== oldProps.filters) {
actions.setFilters(props.filters)
}
}),

loaders(({ props, values, actions }) => ({
Expand Down
83 changes: 83 additions & 0 deletions frontend/src/scenes/web-analytics/WebAnalyticsRecordings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { IconRewindPlay } from '@posthog/icons'
import clsx from 'clsx'
import { useValues } from 'kea'
import { EmptyMessage } from 'lib/components/EmptyMessage/EmptyMessage'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton'
import { RecordingRow } from 'scenes/project-homepage/RecentRecordings'
import { SessionPlayerModal } from 'scenes/session-recordings/player/modal/SessionPlayerModal'
import { sessionRecordingsPlaylistLogic } from 'scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic'
import { teamLogic } from 'scenes/teamLogic'
import { urls } from 'scenes/urls'
import { ReplayTile, webAnalyticsLogic } from 'scenes/web-analytics/webAnalyticsLogic'

import { ReplayTabs } from '~/types'

export function WebAnalyticsRecordingsTile({ tile }: { tile: ReplayTile }): JSX.Element {
const { layout } = tile
const { replayFilters, webAnalyticsFilters } = useValues(webAnalyticsLogic)
const { currentTeam } = useValues(teamLogic)
const sessionRecordingsListLogicInstance = sessionRecordingsPlaylistLogic({
logicKey: 'webAnalytics',
filters: replayFilters,
})

const { sessionRecordings, sessionRecordingsResponseLoading } = useValues(sessionRecordingsListLogicInstance)
const items = sessionRecordings.slice(0, 5)

const emptyMessage = !currentTeam?.session_recording_opt_in
? {
title: 'Recordings are not enabled for this project',
description: 'Once recordings are enabled, new recordings will display here.',
buttonText: 'Enable recordings',
buttonTo: urls.settings('project-replay'),
}
: webAnalyticsFilters.length > 0
? {
title: 'There are no recordings matching the current filters',
description: 'Try changing the filters, or view all recordings.',
buttonText: 'View all',
buttonTo: urls.replay(),
}
: {
title: 'There are no recordings matching this date range',
description: 'Make sure you have the javascript snippet setup in your website.',
buttonText: 'Learn more',
buttonTo: 'https://posthog.com/docs/user-guides/recordings',
}
const to = items.length > 0 ? urls.replay(ReplayTabs.Recent, replayFilters) : urls.replay()
return (
<>
<SessionPlayerModal />
<div
className={clsx(
'col-span-1 row-span-1 flex flex-col',
layout.colSpanClassName ?? 'md:col-span-6',
layout.rowSpanClassName ?? 'md:row-span-1',
layout.orderWhenLargeClassName ?? 'xxl:order-12',
layout.className
)}
>
<h2 className="m-0 mb-3">Session replay</h2>
<div className="border rounded bg-bg-light flex-1 flex flex-col py-2 px-1">
{sessionRecordingsResponseLoading ? (
<div className="p-2 space-y-6">
{Array.from({ length: 6 }, (_, index) => (
<LemonSkeleton key={index} />
))}
</div>
) : items.length === 0 && emptyMessage ? (
<EmptyMessage {...emptyMessage} />
) : (
items.map((item, index) => <RecordingRow key={index} recording={item} />)
)}
</div>
<div className="flex flex-row-reverse my-2">
<LemonButton to={to} icon={<IconRewindPlay />} size="small" type="secondary">
View all
</LemonButton>
</div>
</div>
</>
)
}
14 changes: 9 additions & 5 deletions frontend/src/scenes/web-analytics/WebDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
webAnalyticsLogic,
} from 'scenes/web-analytics/webAnalyticsLogic'
import { WebAnalyticsModal } from 'scenes/web-analytics/WebAnalyticsModal'
import { WebAnalyticsRecordingsTile } from 'scenes/web-analytics/WebAnalyticsRecordings'
import { WebQuery } from 'scenes/web-analytics/WebAnalyticsTile'
import { WebPropertyFilters } from 'scenes/web-analytics/WebPropertyFilters'

Expand Down Expand Up @@ -65,10 +66,12 @@ const Tiles = (): JSX.Element => {
return (
<div className="mt-2 grid grid-cols-1 md:grid-cols-2 xxl:grid-cols-3 gap-x-4 gap-y-12">
{tiles.map((tile, i) => {
if ('query' in tile) {
if (tile.kind === 'query') {
return <QueryTileItem key={i} tile={tile} />
} else if ('tabs' in tile) {
} else if (tile.kind === 'tabs') {
return <TabsTileItem key={i} tile={tile} />
} else if (tile.kind === 'replay') {
return <WebAnalyticsRecordingsTile key={i} tile={tile} />
}
return null
})}
Expand Down Expand Up @@ -201,16 +204,17 @@ export const WebTabs = ({
}[]
setActiveTabId: (id: string) => void
openModal: (tileId: TileId, tabId: string) => void
getNewInsightUrl: (tileId: TileId, tabId: string) => string
getNewInsightUrl: (tileId: TileId, tabId: string) => string | undefined
tileId: TileId
}): JSX.Element => {
const activeTab = tabs.find((t) => t.id === activeTabId)
const newInsightUrl = getNewInsightUrl(tileId, activeTabId)

const buttonsRow = [
activeTab?.canOpenInsight ? (
activeTab?.canOpenInsight && newInsightUrl ? (
<LemonButton
key="open-insight-button"
to={getNewInsightUrl(tileId, activeTabId)}
to={newInsightUrl}
icon={<IconOpenInNew />}
size="small"
type="secondary"
Expand Down
Loading

0 comments on commit 5194187

Please sign in to comment.