From 59e0196d158a289041877be113cbeb403e14e16a Mon Sep 17 00:00:00 2001 From: David Newell Date: Mon, 22 Apr 2024 15:21:49 +0100 Subject: [PATCH] feat: improve scroll syncing (#21622) --- .../inspector/PlayerInspectorControls.tsx | 41 +++---------------- .../player/inspector/PlayerInspectorList.tsx | 24 ++++++++--- .../player/inspector/playerInspectorLogic.ts | 5 +-- .../player/playerSettingsLogic.ts | 9 ---- 4 files changed, 27 insertions(+), 52 deletions(-) diff --git a/frontend/src/scenes/session-recordings/player/inspector/PlayerInspectorControls.tsx b/frontend/src/scenes/session-recordings/player/inspector/PlayerInspectorControls.tsx index ab2dddb3b5ad7..7839f697042f8 100644 --- a/frontend/src/scenes/session-recordings/player/inspector/PlayerInspectorControls.tsx +++ b/frontend/src/scenes/session-recordings/player/inspector/PlayerInspectorControls.tsx @@ -1,8 +1,8 @@ -import { IconBug, IconClock, IconDashboard, IconInfo, IconPause, IconTerminal, IconX } from '@posthog/icons' +import { IconBug, IconClock, IconDashboard, IconInfo, IconTerminal, IconX } from '@posthog/icons' import { LemonButton, LemonCheckbox, LemonInput, LemonSelect, LemonTabs, Tooltip } from '@posthog/lemon-ui' import { useActions, useValues } from 'kea' import { FEATURE_FLAGS } from 'lib/constants' -import { IconPlayCircle, IconUnverifiedEvent } from 'lib/lemon-ui/icons' +import { IconUnverifiedEvent } from 'lib/lemon-ui/icons' import { Spinner } from 'lib/lemon-ui/Spinner/Spinner' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { capitalizeFirstLetter } from 'lib/utils' @@ -69,11 +69,10 @@ function TabButtons({ export function PlayerInspectorControls({ onClose }: { onClose: () => void }): JSX.Element { const { logicProps } = useValues(sessionRecordingPlayerLogic) const inspectorLogic = playerInspectorLogic(logicProps) - const { tab, windowIdFilter, syncScrollingPaused, windowIds, showMatchingEventsFilter } = useValues(inspectorLogic) - const { setWindowIdFilter, setSyncScrollPaused, setTab } = useActions(inspectorLogic) - const { showOnlyMatching, timestampMode, miniFilters, syncScroll, searchQuery } = useValues(playerSettingsLogic) - const { setShowOnlyMatching, setTimestampMode, setMiniFilter, setSyncScroll, setSearchQuery } = - useActions(playerSettingsLogic) + const { tab, windowIdFilter, windowIds, showMatchingEventsFilter } = useValues(inspectorLogic) + const { setWindowIdFilter, setTab } = useActions(inspectorLogic) + const { showOnlyMatching, timestampMode, miniFilters, searchQuery } = useValues(playerSettingsLogic) + const { setShowOnlyMatching, setTimestampMode, setMiniFilter, setSearchQuery } = useActions(playerSettingsLogic) const mode = logicProps.mode ?? SessionRecordingPlayerMode.Standard @@ -199,34 +198,6 @@ export function PlayerInspectorControls({ onClose }: { onClose: () => void }): J - - { - // If the user has syncScrolling on, but it is paused due to interacting with the Inspector, we want to resume it - if (syncScroll && syncScrollingPaused) { - setSyncScrollPaused(false) - } else { - // Otherwise we are just toggling the setting - setSyncScroll(!syncScroll) - } - }} - tooltipPlacement="left" - tooltip={ - syncScroll && syncScrollingPaused - ? 'Synced scrolling is paused - click to resume' - : 'Scroll the list in sync with the recording playback' - } - > - {syncScroll && syncScrollingPaused ? ( - - ) : ( - - )} - {showMatchingEventsFilter ? ( diff --git a/frontend/src/scenes/session-recordings/player/inspector/PlayerInspectorList.tsx b/frontend/src/scenes/session-recordings/player/inspector/PlayerInspectorList.tsx index fbd58fa6c67bd..7ba6d4ab16af3 100644 --- a/frontend/src/scenes/session-recordings/player/inspector/PlayerInspectorList.tsx +++ b/frontend/src/scenes/session-recordings/player/inspector/PlayerInspectorList.tsx @@ -15,7 +15,6 @@ import { userLogic } from 'scenes/userLogic' import { sidePanelSettingsLogic } from '~/layout/navigation-3000/sidepanel/panels/sidePanelSettingsLogic' import { AvailableFeature, SessionRecordingPlayerTab } from '~/types' -import { playerSettingsLogic } from '../playerSettingsLogic' import { sessionRecordingPlayerLogic } from '../sessionRecordingPlayerLogic' import { PlayerInspectorListItem } from './components/PlayerInspectorListItem' import { playerInspectorLogic } from './playerInspectorLogic' @@ -114,10 +113,9 @@ export function PlayerInspectorList(): JSX.Element { const { logicProps, snapshotsLoaded, sessionPlayerMetaData } = useValues(sessionRecordingPlayerLogic) const inspectorLogic = playerInspectorLogic(logicProps) - const { items, tabsState, playbackIndicatorIndex, playbackIndicatorIndexStop, syncScrollingPaused, tab } = + const { items, tabsState, playbackIndicatorIndex, playbackIndicatorIndexStop, syncScrollPaused, tab } = useValues(inspectorLogic) const { setSyncScrollPaused } = useActions(inspectorLogic) - const { syncScroll } = useValues(playerSettingsLogic) const { currentTeam } = useValues(teamLogic) const { hasAvailableFeature } = useValues(userLogic) const performanceAvailable: boolean = hasAvailableFeature(AvailableFeature.RECORDINGS_PERFORMANCE) @@ -161,12 +159,12 @@ export function PlayerInspectorList(): JSX.Element { .getElementById('PlayerInspectorListMarker') ?.setAttribute('style', `transform: translateY(${offset}px)`) - if (!syncScrollingPaused && syncScroll) { + if (!syncScrollPaused) { scrolledByJsFlag.current = true listRef.current.scrollToRow(playbackIndicatorIndex) } } - }, [playbackIndicatorIndex, syncScroll]) + }, [playbackIndicatorIndex]) const renderRow: ListRowRenderer = ({ index, key, parent, style }) => { return ( @@ -226,6 +224,22 @@ export function PlayerInspectorList(): JSX.Element { /> )} + {syncScrollPaused && ( +
+ { + if (listRef.current) { + listRef.current.scrollToRow(playbackIndicatorIndex) + } + // Tricky: Need to dely to make sure the row scrolled has finished + setTimeout(() => setSyncScrollPaused(false), 100) + }} + > + Sync scrolling + +
+ )} ) : tabsState[tab] === 'loading' ? (
diff --git a/frontend/src/scenes/session-recordings/player/inspector/playerInspectorLogic.ts b/frontend/src/scenes/session-recordings/player/inspector/playerInspectorLogic.ts index 91bdd827c65b6..5428d7d78d976 100644 --- a/frontend/src/scenes/session-recordings/player/inspector/playerInspectorLogic.ts +++ b/frontend/src/scenes/session-recordings/player/inspector/playerInspectorLogic.ts @@ -159,7 +159,7 @@ export const playerInspectorLogic = kea([ connect((props: PlayerInspectorLogicProps) => ({ actions: [ playerSettingsLogic, - ['setTab', 'setMiniFilter', 'setSyncScroll', 'setSearchQuery'], + ['setTab', 'setMiniFilter', 'setSearchQuery'], eventUsageLogic, ['reportRecordingInspectorItemExpanded'], sessionRecordingDataLogic(props), @@ -210,13 +210,12 @@ export const playerInspectorLogic = kea([ }, ], - syncScrollingPaused: [ + syncScrollPaused: [ false, { setTab: () => false, setSyncScrollPaused: (_, { paused }) => paused, setItemExpanded: () => true, - setSyncScroll: () => false, }, ], })), diff --git a/frontend/src/scenes/session-recordings/player/playerSettingsLogic.ts b/frontend/src/scenes/session-recordings/player/playerSettingsLogic.ts index b88bec2df3f5e..e453087bc07c8 100644 --- a/frontend/src/scenes/session-recordings/player/playerSettingsLogic.ts +++ b/frontend/src/scenes/session-recordings/player/playerSettingsLogic.ts @@ -185,7 +185,6 @@ export const playerSettingsLogic = kea([ setTimestampMode: (mode: 'absolute' | 'relative') => ({ mode }), setMiniFilter: (key: string, enabled: boolean) => ({ key, enabled }), setSearchQuery: (search: string) => ({ search }), - setSyncScroll: (enabled: boolean) => ({ enabled }), setDurationTypeToShow: (type: DurationType) => ({ type }), setShowFilters: (showFilters: boolean) => ({ showFilters }), setPrefersAdvancedFilters: (prefersAdvancedFilters: boolean) => ({ prefersAdvancedFilters }), @@ -347,14 +346,6 @@ export const playerSettingsLogic = kea([ setSearchQuery: (_, { search }) => search || '', }, ], - - syncScroll: [ - true, - { persist: true }, - { - setSyncScroll: (_, { enabled }) => enabled, - }, - ], })), selectors({