diff --git a/frontend/app/components/Session/LiveSession.js b/frontend/app/components/Session/LiveSession.js index 8ff90aa75..54df7d5c7 100644 --- a/frontend/app/components/Session/LiveSession.js +++ b/frontend/app/components/Session/LiveSession.js @@ -28,9 +28,6 @@ function LiveSession({ } else { console.error('No sessionID in route.'); } - return () => { - if (!session.exists()) return; - }; }, [sessionId, hasSessionsPath]); return ( diff --git a/frontend/app/components/Session/Player/ReplayPlayer/PlayerBlock.tsx b/frontend/app/components/Session/Player/ReplayPlayer/PlayerBlock.tsx new file mode 100644 index 000000000..27756f170 --- /dev/null +++ b/frontend/app/components/Session/Player/ReplayPlayer/PlayerBlock.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import cn from 'classnames'; +import { connect } from 'react-redux'; +import Player from './PlayerInst'; +import SubHeader from 'Components/Session_/Subheader'; + +import styles from 'Components/Session_/playerBlock.module.css'; + +interface IProps { + fullscreen: boolean; + sessionId: string; + disabled: boolean; + activeTab: string; + jiraConfig: Record + fullView?: boolean + isClickmap?: boolean +} + +function PlayerBlock(props: IProps) { + const { + fullscreen, + sessionId, + disabled, + activeTab, + jiraConfig, + fullView = false, + isClickmap + } = props; + + const shouldShowSubHeader = !fullscreen && !fullView && !isClickmap + return ( +
+ {shouldShowSubHeader ? ( + + ) : null} + +
+ ); +} + +export default connect((state: any) => ({ + fullscreen: state.getIn(['components', 'player', 'fullscreen']), + sessionId: state.getIn(['sessions', 'current']).sessionId, + disabled: state.getIn(['components', 'targetDefiner', 'inspectorMode']), + jiraConfig: state.getIn(['issues', 'list'])[0], +}))(PlayerBlock) \ No newline at end of file diff --git a/frontend/app/components/Session/PlayerContent.js b/frontend/app/components/Session/Player/ReplayPlayer/PlayerContent.tsx similarity index 73% rename from frontend/app/components/Session/PlayerContent.js rename to frontend/app/components/Session/Player/ReplayPlayer/PlayerContent.tsx index b3bcfede3..8e46b1163 100644 --- a/frontend/app/components/Session/PlayerContent.js +++ b/frontend/app/components/Session/Player/ReplayPlayer/PlayerContent.tsx @@ -1,18 +1,27 @@ import React from 'react'; -import PlayerBlock from '../Session_/PlayerBlock'; -import styles from '../Session_/session.module.css'; -import { countDaysFrom } from 'App/date'; -import cn from 'classnames'; -import RightBlock from './RightBlock'; -import { PlayerContext } from 'App/components/Session/playerContext'; import { observer } from 'mobx-react-lite'; +import cn from 'classnames'; +import styles from 'Components/Session_/session.module.css'; +import { countDaysFrom } from 'App/date'; +import RightBlock from 'Components/Session/RightBlock'; +import { PlayerContext } from 'Components/Session/playerContext'; +import Session from 'Types/session' +import PlayerBlock from './PlayerBlock'; const TABS = { EVENTS: 'User Steps', HEATMAPS: 'Click Map', }; -function PlayerContent({ session, live, fullscreen, activeTab, setActiveTab, isClickmap }) { +interface IProps { + fullscreen: boolean; + activeTab: string; + setActiveTab: (tab: string) => void; + isClickmap: boolean; + session: Session +} + +function PlayerContent({ session, fullscreen, activeTab, setActiveTab, isClickmap }: IProps) { const { store } = React.useContext(PlayerContext) const { @@ -60,7 +69,6 @@ function PlayerContent({ session, live, fullscreen, activeTab, setActiveTab, isC setActiveTab={setActiveTab} fullscreen={fullscreen} tabs={TABS} - live={live} /> )} @@ -69,10 +77,9 @@ function PlayerContent({ session, live, fullscreen, activeTab, setActiveTab, isC ); } -function RightMenu({ live, tabs, activeTab, setActiveTab, fullscreen }) { +function RightMenu({ tabs, activeTab, setActiveTab, fullscreen }: any) { return ( - !live && - !fullscreen && + !fullscreen ? : null ); } diff --git a/frontend/app/components/Session/Player/ReplayPlayer/PlayerInst.tsx b/frontend/app/components/Session/Player/ReplayPlayer/PlayerInst.tsx new file mode 100644 index 000000000..faa2b3c48 --- /dev/null +++ b/frontend/app/components/Session/Player/ReplayPlayer/PlayerInst.tsx @@ -0,0 +1,126 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { findDOMNode } from 'react-dom'; +import cn from 'classnames'; +import { EscapeButton } from 'UI'; +import { + NONE, + CONSOLE, + NETWORK, + STACKEVENTS, + STORAGE, + PROFILER, + PERFORMANCE, + GRAPHQL, + EXCEPTIONS, + INSPECTOR, + OVERVIEW, + fullscreenOff, +} from 'Duck/components/player'; +import NetworkPanel from 'Shared/DevTools/NetworkPanel'; +import Storage from 'Components/Session_/Storage'; +import { ConnectedPerformance } from 'Components/Session_/Performance'; +import GraphQL from 'Components/Session_/GraphQL'; +import Exceptions from 'Components/Session_/Exceptions/Exceptions'; +import Inspector from 'Components/Session_/Inspector'; +import Controls from 'Components/Session_/Player/Controls'; +import Overlay from 'Components/Session_/Player/Overlay'; +import stl from 'Components/Session_/Player/player.module.css'; +import { updateLastPlayedSession } from 'Duck/sessions'; +import OverviewPanel from 'Components/Session_/OverviewPanel'; +import ConsolePanel from 'Shared/DevTools/ConsolePanel'; +import ProfilerPanel from 'Shared/DevTools/ProfilerPanel'; +import { PlayerContext } from 'App/components/Session/playerContext'; +import StackEventPanel from 'Shared/DevTools/StackEventPanel'; + + +interface IProps { + fullView: boolean; + isMultiview?: boolean; + bottomBlock: number; + fullscreen: boolean; + fullscreenOff: () => any; + nextId: string; + sessionId: string; + activeTab: string; + isClickmap?: boolean; + updateLastPlayedSession: (id: string) => void +} + +function Player(props: IProps) { + const { + fullscreen, + fullscreenOff, + nextId, + bottomBlock, + activeTab, + fullView, + isClickmap, + } = props; + const playerContext = React.useContext(PlayerContext); + const screenWrapper = React.useRef(null); + const bottomBlockIsActive = !fullscreen && bottomBlock !== NONE; + + React.useEffect(() => { + props.updateLastPlayedSession(props.sessionId); + const parentElement = findDOMNode(screenWrapper.current) as HTMLDivElement | null; //TODO: good architecture + if (parentElement) { + playerContext.player.attach(parentElement); + playerContext.player.play(); + } + }, []); + + React.useEffect(() => { + playerContext.player.scale(); + }, [props.bottomBlock, props.fullscreen, playerContext.player]); + + if (!playerContext.player) return null; + + const maxWidth = activeTab ? 'calc(100vw - 270px)' : '100vw'; + return ( +
+ {fullscreen && } +
+ +
+
+ {!fullscreen && !!bottomBlock && ( +
+ {bottomBlock === OVERVIEW && } + {bottomBlock === CONSOLE && } + {bottomBlock === NETWORK && } + {bottomBlock === STACKEVENTS && } + {bottomBlock === STORAGE && } + {bottomBlock === PROFILER && } + {bottomBlock === PERFORMANCE && } + {bottomBlock === GRAPHQL && } + {bottomBlock === EXCEPTIONS && } + {bottomBlock === INSPECTOR && } +
+ )} + {!fullView && !isClickmap ? ( + + ) : null} +
+ ); +} + +export default connect( + (state: any) => ({ + fullscreen: state.getIn(['components', 'player', 'fullscreen']), + nextId: state.getIn(['sessions', 'nextId']), + sessionId: state.getIn(['sessions', 'current']).sessionId, + bottomBlock: state.getIn(['components', 'player', 'bottomBlock']), + }), + { + fullscreenOff, + updateLastPlayedSession, + } +)(Player); diff --git a/frontend/app/components/Session/WebPlayer.tsx b/frontend/app/components/Session/WebPlayer.tsx index 8511822f3..210e2bba1 100644 --- a/frontend/app/components/Session/WebPlayer.tsx +++ b/frontend/app/components/Session/WebPlayer.tsx @@ -7,10 +7,10 @@ import { createWebPlayer } from 'Player'; import { makeAutoObservable } from 'mobx'; import withLocationHandlers from 'HOCs/withLocationHandlers'; import { useStore } from 'App/mstore'; -import PlayerBlockHeader from '../Session_/PlayerBlockHeader'; +import PlayerBlockHeader from './Player/ReplayPlayer/PlayerBlockHeader'; import ReadNote from '../Session_/Player/Controls/components/ReadNote'; import { fetchList as fetchMembers } from 'Duck/member'; -import PlayerContent from './PlayerContent'; +import PlayerContent from './Player/ReplayPlayer/PlayerContent'; import { IPlayerContext, PlayerContext, defaultContextValue } from './playerContext'; import { observer } from 'mobx-react-lite'; import { Note } from "App/services/NotesService"; diff --git a/frontend/app/components/Session_/Player/Controls/Controls.tsx b/frontend/app/components/Session_/Player/Controls/Controls.tsx index 29ede7fd0..f55e54c04 100644 --- a/frontend/app/components/Session_/Player/Controls/Controls.tsx +++ b/frontend/app/components/Session_/Player/Controls/Controls.tsx @@ -2,15 +2,12 @@ import React from 'react'; import cn from 'classnames'; import { connect } from 'react-redux'; import { STORAGE_TYPES, selectStorageType } from 'Player'; -import LiveTag from 'Shared/LiveTag'; -import AssistSessionsTabs from './AssistSessionsTabs'; import { Icon, Tooltip } from 'UI'; import { fullscreenOn, fullscreenOff, toggleBottomBlock, - changeSkipInterval, OVERVIEW, CONSOLE, NETWORK, @@ -25,7 +22,6 @@ import { PlayerContext } from 'App/components/Session/playerContext'; import { observer } from 'mobx-react-lite'; import { fetchSessions } from 'Duck/liveSearch'; -import { AssistDuration } from './Time'; import Timeline from './Timeline'; import ControlButton from './ControlButton'; import PlayerControls from './components/PlayerControls'; @@ -63,47 +59,32 @@ function getStorageName(type: any) { function Controls(props: any) { const { player, store } = React.useContext(PlayerContext); - const { jumpToLive, toggleInspectorMode } = player; const { - live, - livePlay, playing, completed, skip, - // skipToIssue, UPDATE speed, cssLoading, messagesLoading, inspectorMode, markedTargets, - // messagesLoading: fullscreenDisabled, UPDATE - // stackList, exceptionsList, profilesList, graphqlList, - // fetchList, - liveTimeTravel, logMarkedCountNow: logRedCount, resourceMarkedCountNow: resourceRedCount, stackMarkedCountNow: stackRedCount, } = store.get(); - // const storageCount = selectStorageListNow(store.get()).length UPDATE const { bottomBlock, toggleBottomBlock, fullscreen, - closedLive, changeSkipInterval, skipInterval, disabledRedux, showStorageRedux, - session, - // showStackRedux, - fetchSessions: fetchAssistSessions, - totalAssistSessions, } = props; - const isAssist = window.location.pathname.includes('/assist/'); const storageType = selectStorageType(store.get()); const disabled = disabledRedux || cssLoading || messagesLoading || inspectorMode || markedTargets; const profilesCount = profilesList.length; @@ -112,10 +93,6 @@ function Controls(props: any) { const showProfiler = profilesCount > 0; const showExceptions = exceptionsList.length > 0; const showStorage = storageType !== STORAGE_TYPES.NONE || showStorageRedux; - // const fetchCount = fetchList.length; - // const stackCount = stackList.length; - // const showStack = stackCount > 0 || showStackRedux UPDATE - // const showFetch = fetchCount > 0 UPDATE const onKeyDown = (e: any) => { if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) { @@ -145,9 +122,6 @@ function Controls(props: any) { React.useEffect(() => { document.addEventListener('keydown', onKeyDown.bind(this)); - if (isAssist && totalAssistSessions === 0) { - fetchAssistSessions(); - } return () => { document.removeEventListener('keydown', onKeyDown.bind(this)); }; @@ -223,57 +197,31 @@ function Controls(props: any) { return (
- player.jump(t)} - liveTimeTravel={liveTimeTravel} - pause={() => player.pause()} - togglePlay={() => player.togglePlay()} - /> + {!fullscreen && ( -
+
- {!live && ( - <> - player.toggleSpeed()} - toggleSkip={() => player.toggleSkip()} - playButton={renderPlayBtn()} - controlIcon={controlIcon} - skipIntervals={SKIP_INTERVALS} - setSkipInterval={changeSkipInterval} - currentInterval={skipInterval} - /> -
- toggleBottomTools(OVERVIEW)} - /> - - )} - - {live && !closedLive && ( -
- (livePlay ? null : jumpToLive())} /> -
- -
-
- )} + player.toggleSpeed()} + toggleSkip={() => player.toggleSkip()} + playButton={renderPlayBtn()} + controlIcon={controlIcon} + skipIntervals={SKIP_INTERVALS} + setSkipInterval={changeSkipInterval} + currentInterval={skipInterval} + /> +
+ toggleBottomTools(OVERVIEW)} + />
- {isAssist && totalAssistSessions > 1 ? ( -
- -
- ) : null} -
0 || showExceptions} containerClassName="mx-2" /> - {!live && ( - toggleBottomTools(NETWORK)} - active={bottomBlock === NETWORK && !inspectorMode} - label="NETWORK" - hasErrors={resourceRedCount > 0} - noIcon - labelClassName="!text-base font-semibold" - containerClassName="mx-2" - /> - )} - {!live && ( - toggleBottomTools(PERFORMANCE)} - active={bottomBlock === PERFORMANCE && !inspectorMode} - label="PERFORMANCE" - noIcon - labelClassName="!text-base font-semibold" - containerClassName="mx-2" - /> - )} - {!live && showGraphql && ( + + toggleBottomTools(NETWORK)} + active={bottomBlock === NETWORK && !inspectorMode} + label="NETWORK" + hasErrors={resourceRedCount > 0} + noIcon + labelClassName="!text-base font-semibold" + containerClassName="mx-2" + /> + + toggleBottomTools(PERFORMANCE)} + active={bottomBlock === PERFORMANCE && !inspectorMode} + label="PERFORMANCE" + noIcon + labelClassName="!text-base font-semibold" + containerClassName="mx-2" + /> + + {showGraphql && ( toggleBottomTools(GRAPHQL)} @@ -319,7 +266,8 @@ function Controls(props: any) { containerClassName="mx-2" /> )} - {!live && showStorage && ( + + {showStorage && ( toggleBottomTools(STORAGE)} @@ -330,19 +278,17 @@ function Controls(props: any) { containerClassName="mx-2" /> )} - {!live && ( - toggleBottomTools(STACKEVENTS)} - active={bottomBlock === STACKEVENTS && !inspectorMode} - label="EVENTS" - noIcon - labelClassName="!text-base font-semibold" - containerClassName="mx-2" - hasErrors={stackRedCount > 0} - /> - )} - {!live && showProfiler && ( + toggleBottomTools(STACKEVENTS)} + active={bottomBlock === STACKEVENTS && !inspectorMode} + label="EVENTS" + noIcon + labelClassName="!text-base font-semibold" + containerClassName="mx-2" + hasErrors={stackRedCount > 0} + /> + {showProfiler && ( toggleBottomTools(PROFILER)} @@ -353,17 +299,16 @@ function Controls(props: any) { containerClassName="mx-2" /> )} - {!live && ( - - {controlIcon( - 'arrows-angle-extend', - 16, - props.fullscreenOn, - false, - 'rounded hover:bg-gray-light-shade color-gray-medium' - )} - - )} + + + {controlIcon( + 'arrows-angle-extend', + 16, + props.fullscreenOn, + false, + 'rounded hover:bg-gray-light-shade color-gray-medium' + )} +
)} @@ -385,8 +330,6 @@ export default connect( showStackRedux: !state.getIn(['components', 'player', 'hiddenHints', 'stack']), session: state.getIn(['sessions', 'current']), totalAssistSessions: state.getIn(['liveSearch', 'total']), - closedLive: - !!state.getIn(['sessions', 'errors']) || !state.getIn(['sessions', 'current']).live, skipInterval: state.getIn(['components', 'player', 'skipInterval']), }; }, @@ -394,7 +337,6 @@ export default connect( fullscreenOn, fullscreenOff, toggleBottomBlock, - changeSkipInterval, fetchSessions, } )(ControlPlayer); diff --git a/frontend/app/components/Session_/Player/Controls/Time.js b/frontend/app/components/Session_/Player/Controls/Time.js index db665fc8e..5c2c0da0c 100644 --- a/frontend/app/components/Session_/Player/Controls/Time.js +++ b/frontend/app/components/Session_/Player/Controls/Time.js @@ -19,28 +19,7 @@ const ReduxTime = observer(({ format, name, isCustom }) => { return