diff --git a/frontend/__snapshots__/replay-player-success--recent-recordings--dark.png b/frontend/__snapshots__/replay-player-success--recent-recordings--dark.png
index 9d259c96a06cd..b2d4c263e841a 100644
Binary files a/frontend/__snapshots__/replay-player-success--recent-recordings--dark.png and b/frontend/__snapshots__/replay-player-success--recent-recordings--dark.png differ
diff --git a/frontend/__snapshots__/replay-player-success--recent-recordings--light.png b/frontend/__snapshots__/replay-player-success--recent-recordings--light.png
index 67a3c75bc8661..600363cbe918f 100644
Binary files a/frontend/__snapshots__/replay-player-success--recent-recordings--light.png and b/frontend/__snapshots__/replay-player-success--recent-recordings--light.png differ
diff --git a/frontend/__snapshots__/replay-player-success--second-recording-in-list--dark.png b/frontend/__snapshots__/replay-player-success--second-recording-in-list--dark.png
index 8ca07124d50f9..085e1712a86b5 100644
Binary files a/frontend/__snapshots__/replay-player-success--second-recording-in-list--dark.png and b/frontend/__snapshots__/replay-player-success--second-recording-in-list--dark.png differ
diff --git a/frontend/__snapshots__/replay-player-success--second-recording-in-list--light.png b/frontend/__snapshots__/replay-player-success--second-recording-in-list--light.png
index fcf8f4fd07417..0aca8202e0d92 100644
Binary files a/frontend/__snapshots__/replay-player-success--second-recording-in-list--light.png and b/frontend/__snapshots__/replay-player-success--second-recording-in-list--light.png differ
diff --git a/frontend/src/scenes/session-recordings/player/PlayerMetaLinks.tsx b/frontend/src/scenes/session-recordings/player/PlayerMetaLinks.tsx
index dae06c8ba2eb1..8a5c2cb68f166 100644
--- a/frontend/src/scenes/session-recordings/player/PlayerMetaLinks.tsx
+++ b/frontend/src/scenes/session-recordings/player/PlayerMetaLinks.tsx
@@ -10,10 +10,11 @@ import {
IconTrash,
} from '@posthog/icons'
import { LemonButton, LemonButtonProps, LemonDialog, LemonMenu, LemonMenuItems } from '@posthog/lemon-ui'
+import clsx from 'clsx'
import { useActions, useValues } from 'kea'
import { FEATURE_FLAGS } from 'lib/constants'
import { useFeatureFlag } from 'lib/hooks/useFeatureFlag'
-import { IconComment } from 'lib/lemon-ui/icons'
+import { IconComment, IconFullScreen } from 'lib/lemon-ui/icons'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { Fragment } from 'react'
import { useNotebookNode } from 'scenes/notebooks/Nodes/NotebookNodeContext'
@@ -78,8 +79,9 @@ function PinToPlaylistButton({
}
export function PlayerMetaLinks({ iconsOnly }: { iconsOnly: boolean }): JSX.Element {
- const { sessionRecordingId, logicProps } = useValues(sessionRecordingPlayerLogic)
+ const { sessionRecordingId, logicProps, isFullScreen } = useValues(sessionRecordingPlayerLogic)
const { setPause, setIsFullScreen } = useActions(sessionRecordingPlayerLogic)
+
const nodeLogic = useNotebookNode()
const { closeSessionPlayer } = useActions(sessionPlayerModalLogic())
@@ -112,6 +114,11 @@ export function PlayerMetaLinks({ iconsOnly }: { iconsOnly: boolean }): JSX.Elem
{![SessionRecordingPlayerMode.Sharing].includes(mode) ? (
<>
+ {sessionRecordingId && (
+
+ {mode === SessionRecordingPlayerMode.Standard && }
+
+ )}
}
@@ -159,11 +166,13 @@ export function PlayerMetaLinks({ iconsOnly }: { iconsOnly: boolean }): JSX.Elem
- {sessionRecordingId && (
-
- {mode === SessionRecordingPlayerMode.Standard && }
-
- )}
+
setIsFullScreen(!isFullScreen)}
+ tooltip={`${!isFullScreen ? 'Go' : 'Exit'} full screen (F)`}
+ >
+
+
>
) : null}
diff --git a/frontend/src/scenes/session-recordings/player/PlayerSettings.tsx b/frontend/src/scenes/session-recordings/player/PlayerSettings.tsx
index 615cda9768b4f..c5ac8b967f20a 100644
--- a/frontend/src/scenes/session-recordings/player/PlayerSettings.tsx
+++ b/frontend/src/scenes/session-recordings/player/PlayerSettings.tsx
@@ -1,109 +1,96 @@
-import { IconEllipsis, IconFastForward } from '@posthog/icons'
+import { IconFastForward, IconGear } from '@posthog/icons'
import { LemonButton, LemonMenu, LemonSelect, LemonSwitch } from '@posthog/lemon-ui'
import clsx from 'clsx'
import { useActions, useValues } from 'kea'
import { playerSettingsLogic } from './playerSettingsLogic'
-import { PLAYBACK_SPEEDS } from './sessionRecordingPlayerLogic'
export const PlayerSettings = (): JSX.Element => {
- const { speed, autoplayDirection, skipInactivitySetting, showMouseTail, showSeekbarTicks } =
- useValues(playerSettingsLogic)
- const { setSpeed, setAutoplayDirection, setSkipInactivitySetting, setShowMouseTail, setShowSeekbarTicks } =
+ const { autoplayDirection, skipInactivitySetting, showMouseTail, showSeekbarTicks } = useValues(playerSettingsLogic)
+ const { setAutoplayDirection, setSkipInactivitySetting, setShowMouseTail, setShowSeekbarTicks } =
useActions(playerSettingsLogic)
return (
-
-
(
-
-
Autoplay
+
(
+
+ Autoplay
-
- Autoplay next recording
-
({!autoplayDirection ? 'off' : autoplayDirection})
-
- }
- value={autoplayDirection}
- aria-label="Autoplay next recording"
- onChange={setAutoplayDirection}
- dropdownPlacement="bottom-end"
- dropdownMatchSelectWidth={false}
- options={[
- { value: null, label: 'Off' },
- { value: 'newer', label: 'Newer recordings' },
- { value: 'older', label: 'Older recordings' },
- ]}
- size="small"
- />
-
- ),
- },
- {
- custom: true,
- label: () => (
-
- ),
- },
- {
- custom: true,
- label: () => (
-
- ),
- },
- {
- custom: true,
- label: () => (
-
+
+ Autoplay next recording
+
({!autoplayDirection ? 'off' : autoplayDirection})
+
}
- fullWidth
- data-attr="skip-inactivity"
- className="px-2 py-1"
- checked={skipInactivitySetting}
- onChange={setSkipInactivitySetting}
- label="Skip inactivity"
+ value={autoplayDirection}
+ aria-label="Autoplay next recording"
+ onChange={setAutoplayDirection}
+ dropdownPlacement="bottom-end"
+ dropdownMatchSelectWidth={false}
+ options={[
+ { value: null, label: 'Off' },
+ { value: 'newer', label: 'Newer recordings' },
+ { value: 'older', label: 'Older recordings' },
+ ]}
+ size="small"
/>
- ),
- },
- {
- label: `Playback speed (${speed}x)`,
- items: PLAYBACK_SPEEDS.map((speedToggle) => ({
- label: `${speedToggle}x`,
- onClick: () => setSpeed(speedToggle),
- active: speedToggle === speed,
- })),
- placement: 'right-end',
- },
- ]}
- >
- } />
-
-
+
+ ),
+ },
+ {
+ custom: true,
+ label: () => (
+
+ ),
+ },
+ {
+ custom: true,
+ label: () => (
+
+ ),
+ },
+ {
+ custom: true,
+ label: () => (
+
+ }
+ fullWidth
+ data-attr="skip-inactivity"
+ className="px-2 py-1"
+ checked={skipInactivitySetting}
+ onChange={setSkipInactivitySetting}
+ label="Skip inactivity"
+ />
+ ),
+ },
+ ]}
+ >
+ } />
+
)
}
diff --git a/frontend/src/scenes/session-recordings/player/PlayerSidebar.tsx b/frontend/src/scenes/session-recordings/player/PlayerSidebar.tsx
index c6fa9522cbfb9..eaa19d22260c2 100644
--- a/frontend/src/scenes/session-recordings/player/PlayerSidebar.tsx
+++ b/frontend/src/scenes/session-recordings/player/PlayerSidebar.tsx
@@ -9,7 +9,7 @@ import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { capitalizeFirstLetter } from 'lib/utils'
import { useRef } from 'react'
-import { SessionRecordingSidebarTab } from '~/types'
+import { SessionRecordingSidebarStacking, SessionRecordingSidebarTab } from '~/types'
import { TabToIcon } from './inspector/PlayerInspectorControls'
import { PlayerPersonMeta } from './PlayerPersonMeta'
@@ -17,20 +17,14 @@ import { playerSettingsLogic } from './playerSettingsLogic'
import { playerSidebarLogic } from './sidebar/playerSidebarLogic'
import { PlayerSidebarTab } from './sidebar/PlayerSidebarTab'
-export function PlayerSidebar({
- isVerticallyStacked,
- toggleLayoutStacking,
-}: {
- isVerticallyStacked: boolean
- toggleLayoutStacking?: () => void
-}): JSX.Element {
+export function PlayerSidebar(): JSX.Element {
const ref = useRef(null)
const { featureFlags } = useValues(featureFlagLogic)
const { activeTab } = useValues(playerSidebarLogic)
const { setTab } = useActions(playerSidebarLogic)
- const { sidebarOpen } = useValues(playerSettingsLogic)
- const { setSidebarOpen } = useActions(playerSettingsLogic)
+ const { sidebarOpen, preferredSidebarStacking, isVerticallyStacked } = useValues(playerSettingsLogic)
+ const { setSidebarOpen, setPreferredSidebarStacking } = useActions(playerSettingsLogic)
const logicKey = `player-sidebar-${isVerticallyStacked ? 'vertical' : 'horizontal'}`
@@ -87,15 +81,19 @@ export function PlayerSidebar({
barClassName="mb-0"
/>
-
- {toggleLayoutStacking && (
-
:
}
- onClick={toggleLayoutStacking}
- tooltip={`Dock to ${isVerticallyStacked ? 'right' : 'bottom'}`}
- />
- )}
+
+ : }
+ onClick={() =>
+ setPreferredSidebarStacking(
+ preferredSidebarStacking === SessionRecordingSidebarStacking.Vertical
+ ? SessionRecordingSidebarStacking.Horizontal
+ : SessionRecordingSidebarStacking.Vertical
+ )
+ }
+ tooltip={`Dock to ${isVerticallyStacked ? 'right' : 'bottom'}`}
+ />
}
diff --git a/frontend/src/scenes/session-recordings/player/SessionRecordingPlayer.tsx b/frontend/src/scenes/session-recordings/player/SessionRecordingPlayer.tsx
index 63dd749db6228..3dbeb3008c7f9 100644
--- a/frontend/src/scenes/session-recordings/player/SessionRecordingPlayer.tsx
+++ b/frontend/src/scenes/session-recordings/player/SessionRecordingPlayer.tsx
@@ -15,8 +15,6 @@ import { RecordingNotFound } from 'scenes/session-recordings/player/RecordingNot
import { MatchingEventsMatchType } from 'scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic'
import { urls } from 'scenes/urls'
-import { SessionRecordingSidebarStacking } from '~/types'
-
import { NetworkView } from '../apm/NetworkView'
import { PlayerController } from './controller/PlayerController'
import { PlayerFrame } from './PlayerFrame'
@@ -95,8 +93,7 @@ export function SessionRecordingPlayer(props: SessionRecordingPlayerProps): JSX.
sessionRecordingPlayerLogic(logicProps)
)
const speedHotkeys = useMemo(() => createPlaybackSpeedKey(setSpeed), [setSpeed])
- const { preferredSidebarStacking, sidebarOpen, playbackMode } = useValues(playerSettingsLogic)
- const { setPreferredSidebarStacking } = useActions(playerSettingsLogic)
+ const { isVerticallyStacked, sidebarOpen, playbackMode } = useValues(playerSettingsLogic)
useKeyboardHotkeys(
{
@@ -160,10 +157,6 @@ export function SessionRecordingPlayer(props: SessionRecordingPlayerProps): JSX.
}
)
- const compactLayout = size === 'small'
- const layoutStacking = compactLayout ? SessionRecordingSidebarStacking.Vertical : preferredSidebarStacking
- const isVerticallyStacked = layoutStacking === SessionRecordingSidebarStacking.Vertical
-
const lessThanFiveMinutesOld = dayjs().diff(start, 'minute') <= 5
const cannotPlayback = snapshotsInvalid && lessThanFiveMinutesOld && !messageTooLargeWarnings
@@ -239,22 +232,7 @@ export function SessionRecordingPlayer(props: SessionRecordingPlayerProps): JSX.
)}
- {!noInspector && (
-
- setPreferredSidebarStacking(
- preferredSidebarStacking ===
- SessionRecordingSidebarStacking.Vertical
- ? SessionRecordingSidebarStacking.Horizontal
- : SessionRecordingSidebarStacking.Vertical
- )
- }
- />
- )}
+ {!noInspector && }
>
)}
diff --git a/frontend/src/scenes/session-recordings/player/controller/PlayerController.tsx b/frontend/src/scenes/session-recordings/player/controller/PlayerController.tsx
index fe44dfe3a444b..894aca7cd2fbc 100644
--- a/frontend/src/scenes/session-recordings/player/controller/PlayerController.tsx
+++ b/frontend/src/scenes/session-recordings/player/controller/PlayerController.tsx
@@ -1,9 +1,12 @@
import { IconPause, IconPlay } from '@posthog/icons'
-import clsx from 'clsx'
import { useActions, useValues } from 'kea'
-import { IconFullScreen, IconSync } from 'lib/lemon-ui/icons'
+import { IconSync } from 'lib/lemon-ui/icons'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
-import { sessionRecordingPlayerLogic } from 'scenes/session-recordings/player/sessionRecordingPlayerLogic'
+import { LemonMenu } from 'lib/lemon-ui/LemonMenu'
+import {
+ PLAYBACK_SPEEDS,
+ sessionRecordingPlayerLogic,
+} from 'scenes/session-recordings/player/sessionRecordingPlayerLogic'
import { KeyboardShortcut } from '~/layout/navigation-3000/components/KeyboardShortcut'
import { SessionPlayerState } from '~/types'
@@ -13,50 +16,66 @@ import { PlayerSettings } from '../PlayerSettings'
import { SeekSkip, Timestamp } from './PlayerControllerTime'
import { Seekbar } from './Seekbar'
-export function PlayerController({ iconsOnly }: { iconsOnly: boolean }): JSX.Element {
- const { playingState, isFullScreen, endReached } = useValues(sessionRecordingPlayerLogic)
- const { togglePlayPause, setIsFullScreen } = useActions(sessionRecordingPlayerLogic)
+function SetPlaybackSpeed(): JSX.Element {
+ const { speed } = useValues(sessionRecordingPlayerLogic)
+ const { setSpeed } = useActions(sessionRecordingPlayerLogic)
+ return (
+ ({
+ label: `${speedToggle}x`,
+ onClick: () => setSpeed(speedToggle),
+ }))}
+ >
+
+ {speed}x
+
+
+ )
+}
+
+function PlayPauseButton(): JSX.Element {
+ const { playingState, endReached } = useValues(sessionRecordingPlayerLogic)
+ const { togglePlayPause } = useActions(sessionRecordingPlayerLogic)
const showPause = playingState === SessionPlayerState.PLAY
+ return (
+
+ {showPause ? 'Pause' : endReached ? 'Restart' : 'Play'}
+
+
+ }
+ >
+ {showPause ? (
+
+ ) : endReached ? (
+
+ ) : (
+
+ )}
+
+ )
+}
+
+export function PlayerController({ iconsOnly }: { iconsOnly: boolean }): JSX.Element {
return (
-
+
-
-
- {showPause ? 'Pause' : endReached ? 'Restart' : 'Play'}
-
-
- }
- >
- {showPause ? (
-
- ) : endReached ? (
-
- ) : (
-
- )}
-
+
+
-
setIsFullScreen(!isFullScreen)}
- tooltip={`${!isFullScreen ? 'Go' : 'Exit'} full screen (F)`}
- >
-
-
+
+
-
diff --git a/frontend/src/scenes/session-recordings/player/playerSettingsLogic.ts b/frontend/src/scenes/session-recordings/player/playerSettingsLogic.ts
index 67561520bc1f6..b5d1ada994eba 100644
--- a/frontend/src/scenes/session-recordings/player/playerSettingsLogic.ts
+++ b/frontend/src/scenes/session-recordings/player/playerSettingsLogic.ts
@@ -349,6 +349,10 @@ export const playerSettingsLogic = kea
([
})),
selectors({
+ isVerticallyStacked: [
+ (s) => [s.preferredSidebarStacking],
+ (preferredSidebarStacking) => preferredSidebarStacking === SessionRecordingSidebarStacking.Vertical,
+ ],
miniFilters: [
(s) => [s.tab, s.selectedMiniFilters],
(tab, selectedMiniFilters): SharedListMiniFilter[] => {