diff --git a/frontend/src/scenes/session-recordings/player/PlayerMeta.tsx b/frontend/src/scenes/session-recordings/player/PlayerMeta.tsx index a333d76178e6a..e4446100ae281 100644 --- a/frontend/src/scenes/session-recordings/player/PlayerMeta.tsx +++ b/frontend/src/scenes/session-recordings/player/PlayerMeta.tsx @@ -4,7 +4,6 @@ import { Link } from '@posthog/lemon-ui' import clsx from 'clsx' import { useValues } from 'kea' import { CopyToClipboardInline } from 'lib/components/CopyToClipboard' -import { PropertyIcon } from 'lib/components/PropertyIcon' import { TZLabel } from 'lib/components/TZLabel' import { dayjs } from 'lib/dayjs' import { useResizeBreakpoints } from 'lib/hooks/useResizeObserver' @@ -17,6 +16,7 @@ import { asDisplay } from 'scenes/persons/person-utils' import { PersonDisplay } from 'scenes/persons/PersonDisplay' import { IconWindow } from 'scenes/session-recordings/player/icons' import { playerMetaLogic } from 'scenes/session-recordings/player/playerMetaLogic' +import { gatherIconProperties, PropertyIcons } from 'scenes/session-recordings/playlist/SessionRecordingPreview' import { urls } from 'scenes/urls' import { getCurrentExporterData } from '~/exporter/exporterViewLogic' @@ -30,49 +30,55 @@ function SessionPropertyMeta(props: { iconProperties: Record predicate: (x: string) => boolean }): JSX.Element { + const gatheredProperties = gatherIconProperties(props.iconProperties) + return ( -
- - - {!props.fullScreen ? props.iconProperties['$browser'] : null} - - - - {!props.fullScreen - ? props.iconProperties['$device_type'] || props.iconProperties['$initial_device_type'] - : null} - - - - {!props.fullScreen ? props.iconProperties['$os'] : null} - - {props.iconProperties['$geoip_country_code'] && ( - - (props.fullScreen ? key === '$geoip_country_code' : key !== '$geoip_country_code')} + /> + ) +} + +function URLOrScreen({ lastUrl }: { lastUrl: string | undefined }): JSX.Element | null { + if (!lastUrl) { + return null + } + + // re-using the rrweb web schema means that this might be a mobile replay screen name + let isValidUrl = false + try { + new URL(lastUrl || '') + isValidUrl = true + } catch (_e) { + // no valid url + } + + return ( + + · + + {isValidUrl ? ( + + + {lastUrl} + + + ) : ( + lastUrl + )} + + - { - props.fullScreen && - [ - props.iconProperties['$geoip_city_name'], - props.iconProperties['$geoip_subdivision_1_code'], - ] - .filter(props.predicate) - .join(', ') /* [city, state] */ - } - )} -
+ + ) } @@ -224,25 +230,7 @@ export function PlayerMeta(): JSX.Element { - {lastUrl && ( - - · - - - - {lastUrl} - - - - - - - - )} + {lastPageviewEvent?.properties?.['$screen_name'] && ( · diff --git a/frontend/src/scenes/session-recordings/playlist/SessionRecordingPreview.tsx b/frontend/src/scenes/session-recordings/playlist/SessionRecordingPreview.tsx index 29729ea29d6bd..7c74657f483ba 100644 --- a/frontend/src/scenes/session-recordings/playlist/SessionRecordingPreview.tsx +++ b/frontend/src/scenes/session-recordings/playlist/SessionRecordingPreview.tsx @@ -58,26 +58,28 @@ function RecordingDuration({ interface GatheredProperty { property: string value: string | undefined + label: string | undefined tooltipValue: string } const browserIconPropertyKeys = ['$geoip_country_code', '$browser', '$device_type', '$os'] const mobileIconPropertyKeys = ['$geoip_country_code', '$device_type', '$os_name'] -function gatherIconProperties( +export function gatherIconProperties( recordingProperties: Record | undefined, - recording: SessionRecordingType + recording?: SessionRecordingType ): GatheredProperty[] { const iconProperties = recordingProperties && Object.keys(recordingProperties).length > 0 ? recordingProperties - : recording.person?.properties || {} + : recording?.person?.properties || {} const deviceType = iconProperties['$device_type'] || iconProperties['$initial_device_type'] const iconPropertyKeys = deviceType === 'Mobile' ? mobileIconPropertyKeys : browserIconPropertyKeys - return iconPropertyKeys.map((property) => { + return iconPropertyKeys.flatMap((property) => { let value = iconProperties?.[property] + let label = value if (property === '$device_type') { value = iconProperties?.['$device_type'] || iconProperties?.['$initial_device_type'] } @@ -85,16 +87,21 @@ function gatherIconProperties( let tooltipValue = value if (property === '$geoip_country_code') { tooltipValue = `${iconProperties?.['$geoip_country_name']} (${value})` + label = [iconProperties?.['$geoip_city_name'], iconProperties?.['$geoip_subdivision_1_code']] + .filter(Boolean) + .join(', ') } - return { property, value, tooltipValue } + return { property, value, tooltipValue, label } }) } export interface PropertyIconsProps { recordingProperties: GatheredProperty[] - loading: boolean + loading?: boolean onPropertyClick?: (property: string, value?: string) => void - iconClassnames: string + iconClassnames?: string + showTooltip?: boolean + showLabel?: (key: string) => boolean } export function PropertyIcons({ @@ -102,35 +109,41 @@ export function PropertyIcons({ loading, onPropertyClick, iconClassnames, + showTooltip = true, + showLabel = undefined, }: PropertyIconsProps): JSX.Element { return ( -
- {!loading ? ( - recordingProperties.map(({ property, value, tooltipValue }) => { +
+ {loading ? ( + + ) : ( + recordingProperties.map(({ property, value, tooltipValue, label }) => { return ( - { - if (e.altKey) { - e.stopPropagation() - onPropertyClick?.(property, value) - } - }} - className={iconClassnames} - property={property} - value={value} - tooltipTitle={() => ( -
- Alt + Click to filter for -
- {tooltipValue ?? 'N/A'} -
- )} - /> + <> + { + if (e.altKey) { + e.stopPropagation() + onPropertyClick?.(property, value) + } + }} + className={iconClassnames} + property={property} + value={value} + noTooltip={!showTooltip} + tooltipTitle={() => ( +
+ Alt + Click to filter for +
+ {tooltipValue ?? 'N/A'} +
+ )} + /> + {showLabel?.(property) && {label || value}} + ) }) - ) : ( - )}
)