change(ui): remove live player refs inside replay player, extract some components

This commit is contained in:
nick-delirium 2023-01-10 15:20:19 +01:00 committed by Delirium
parent 6334f10888
commit 5f5efe18e6
17 changed files with 320 additions and 340 deletions

View file

@ -28,9 +28,6 @@ function LiveSession({
} else {
console.error('No sessionID in route.');
}
return () => {
if (!session.exists()) return;
};
}, [sessionId, hasSessionsPath]);
return (

View file

@ -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<string, any>
fullView?: boolean
isClickmap?: boolean
}
function PlayerBlock(props: IProps) {
const {
fullscreen,
sessionId,
disabled,
activeTab,
jiraConfig,
fullView = false,
isClickmap
} = props;
const shouldShowSubHeader = !fullscreen && !fullView && !isClickmap
return (
<div
className={cn(styles.playerBlock, 'flex flex-col', !isClickmap ? 'overflow-x-hidden' : 'overflow-visible')}
style={{ zIndex: isClickmap ? 1 : undefined, minWidth: isClickmap ? '100%' : undefined }}
>
{shouldShowSubHeader ? (
<SubHeader sessionId={sessionId} disabled={disabled} jiraConfig={jiraConfig} />
) : null}
<Player
activeTab={activeTab}
fullView={fullView}
isClickmap={isClickmap}
/>
</div>
);
}
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)

View file

@ -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}
/>
)}
</div>
@ -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 && <RightBlock tabs={tabs} setActiveTab={setActiveTab} activeTab={activeTab} />
!fullscreen ? <RightBlock tabs={tabs} setActiveTab={setActiveTab} activeTab={activeTab} /> : null
);
}

View file

@ -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<HTMLDivElement>(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 (
<div
className={cn(stl.playerBody, 'flex-1 flex flex-col relative', fullscreen && 'pb-2')}
data-bottom-block={bottomBlockIsActive}
>
{fullscreen && <EscapeButton onClose={fullscreenOff} />}
<div className={cn("relative flex-1", isClickmap ? 'overflow-visible' : 'overflow-hidden')}>
<Overlay nextId={nextId} isClickmap={isClickmap} />
<div className={cn(stl.screenWrapper, isClickmap && '!overflow-y-scroll')} ref={screenWrapper} />
</div>
{!fullscreen && !!bottomBlock && (
<div style={{ maxWidth, width: '100%' }}>
{bottomBlock === OVERVIEW && <OverviewPanel />}
{bottomBlock === CONSOLE && <ConsolePanel />}
{bottomBlock === NETWORK && <NetworkPanel />}
{bottomBlock === STACKEVENTS && <StackEventPanel />}
{bottomBlock === STORAGE && <Storage />}
{bottomBlock === PROFILER && <ProfilerPanel />}
{bottomBlock === PERFORMANCE && <ConnectedPerformance />}
{bottomBlock === GRAPHQL && <GraphQL />}
{bottomBlock === EXCEPTIONS && <Exceptions />}
{bottomBlock === INSPECTOR && <Inspector />}
</div>
)}
{!fullView && !isClickmap ? (
<Controls
speedDown={playerContext.player.speedDown}
speedUp={playerContext.player.speedUp}
jump={playerContext.player.jump}
/>
) : null}
</div>
);
}
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);

View file

@ -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";

View file

@ -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 (
<div className={styles.controls}>
<Timeline
live={live}
jump={(t: number) => player.jump(t)}
liveTimeTravel={liveTimeTravel}
pause={() => player.pause()}
togglePlay={() => player.togglePlay()}
/>
<Timeline />
{!fullscreen && (
<div className={cn(styles.buttons, live ? '!px-5 !pt-0' : '!px-2')} data-is-live={live}>
<div className={cn(styles.buttons, '!px-2')}>
<div className="flex items-center">
{!live && (
<>
<PlayerControls
live={live}
skip={skip}
speed={speed}
disabled={disabled}
backTenSeconds={backTenSeconds}
forthTenSeconds={forthTenSeconds}
toggleSpeed={() => player.toggleSpeed()}
toggleSkip={() => player.toggleSkip()}
playButton={renderPlayBtn()}
controlIcon={controlIcon}
skipIntervals={SKIP_INTERVALS}
setSkipInterval={changeSkipInterval}
currentInterval={skipInterval}
/>
<div className={cn('mx-2')} />
<XRayButton
isActive={bottomBlock === OVERVIEW && !inspectorMode}
onClick={() => toggleBottomTools(OVERVIEW)}
/>
</>
)}
{live && !closedLive && (
<div className={styles.buttonsLeft}>
<LiveTag isLive={livePlay} onClick={() => (livePlay ? null : jumpToLive())} />
<div className="font-semibold px-2">
<AssistDuration />
</div>
</div>
)}
<PlayerControls
skip={skip}
speed={speed}
disabled={disabled}
backTenSeconds={backTenSeconds}
forthTenSeconds={forthTenSeconds}
toggleSpeed={() => player.toggleSpeed()}
toggleSkip={() => player.toggleSkip()}
playButton={renderPlayBtn()}
controlIcon={controlIcon}
skipIntervals={SKIP_INTERVALS}
setSkipInterval={changeSkipInterval}
currentInterval={skipInterval}
/>
<div className={cn('mx-2')} />
<XRayButton
isActive={bottomBlock === OVERVIEW && !inspectorMode}
onClick={() => toggleBottomTools(OVERVIEW)}
/>
</div>
{isAssist && totalAssistSessions > 1 ? (
<div>
<AssistSessionsTabs session={session} />
</div>
) : null}
<div className="flex items-center h-full">
<ControlButton
disabled={disabled && !inspectorMode}
@ -285,30 +233,29 @@ function Controls(props: any) {
hasErrors={logRedCount > 0 || showExceptions}
containerClassName="mx-2"
/>
{!live && (
<ControlButton
disabled={disabled && !inspectorMode}
onClick={() => toggleBottomTools(NETWORK)}
active={bottomBlock === NETWORK && !inspectorMode}
label="NETWORK"
hasErrors={resourceRedCount > 0}
noIcon
labelClassName="!text-base font-semibold"
containerClassName="mx-2"
/>
)}
{!live && (
<ControlButton
disabled={disabled && !inspectorMode}
onClick={() => toggleBottomTools(PERFORMANCE)}
active={bottomBlock === PERFORMANCE && !inspectorMode}
label="PERFORMANCE"
noIcon
labelClassName="!text-base font-semibold"
containerClassName="mx-2"
/>
)}
{!live && showGraphql && (
<ControlButton
disabled={disabled && !inspectorMode}
onClick={() => toggleBottomTools(NETWORK)}
active={bottomBlock === NETWORK && !inspectorMode}
label="NETWORK"
hasErrors={resourceRedCount > 0}
noIcon
labelClassName="!text-base font-semibold"
containerClassName="mx-2"
/>
<ControlButton
disabled={disabled && !inspectorMode}
onClick={() => toggleBottomTools(PERFORMANCE)}
active={bottomBlock === PERFORMANCE && !inspectorMode}
label="PERFORMANCE"
noIcon
labelClassName="!text-base font-semibold"
containerClassName="mx-2"
/>
{showGraphql && (
<ControlButton
disabled={disabled && !inspectorMode}
onClick={() => toggleBottomTools(GRAPHQL)}
@ -319,7 +266,8 @@ function Controls(props: any) {
containerClassName="mx-2"
/>
)}
{!live && showStorage && (
{showStorage && (
<ControlButton
disabled={disabled && !inspectorMode}
onClick={() => toggleBottomTools(STORAGE)}
@ -330,19 +278,17 @@ function Controls(props: any) {
containerClassName="mx-2"
/>
)}
{!live && (
<ControlButton
disabled={disabled && !inspectorMode}
onClick={() => toggleBottomTools(STACKEVENTS)}
active={bottomBlock === STACKEVENTS && !inspectorMode}
label="EVENTS"
noIcon
labelClassName="!text-base font-semibold"
containerClassName="mx-2"
hasErrors={stackRedCount > 0}
/>
)}
{!live && showProfiler && (
<ControlButton
disabled={disabled && !inspectorMode}
onClick={() => toggleBottomTools(STACKEVENTS)}
active={bottomBlock === STACKEVENTS && !inspectorMode}
label="EVENTS"
noIcon
labelClassName="!text-base font-semibold"
containerClassName="mx-2"
hasErrors={stackRedCount > 0}
/>
{showProfiler && (
<ControlButton
disabled={disabled && !inspectorMode}
onClick={() => toggleBottomTools(PROFILER)}
@ -353,17 +299,16 @@ function Controls(props: any) {
containerClassName="mx-2"
/>
)}
{!live && (
<Tooltip title="Fullscreen" delay={0} placement="top-start" className="mx-4">
{controlIcon(
'arrows-angle-extend',
16,
props.fullscreenOn,
false,
'rounded hover:bg-gray-light-shade color-gray-medium'
)}
</Tooltip>
)}
<Tooltip title="Fullscreen" delay={0} placement="top-start" className="mx-4">
{controlIcon(
'arrows-angle-extend',
16,
props.fullscreenOn,
false,
'rounded hover:bg-gray-light-shade color-gray-medium'
)}
</Tooltip>
</div>
</div>
)}
@ -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);

View file

@ -19,28 +19,7 @@ const ReduxTime = observer(({ format, name, isCustom }) => {
return <Time format={format} time={time} isCustom={isCustom} />
})
const AssistDurationCont = () => {
const { store } = React.useContext(PlayerContext)
const { assistStart } = store.get()
const [assistDuration, setAssistDuration] = React.useState('00:00');
React.useEffect(() => {
const interval = setInterval(() => {
setAssistDuration(Duration.fromMillis(+new Date() - assistStart).toFormat('mm:ss'));
}
, 1000);
return () => clearInterval(interval);
}, [])
return (
<>
Elapsed {assistDuration}
</>
)
}
const AssistDuration = observer(AssistDurationCont)
ReduxTime.displayName = "ReduxTime";
export default React.memo(Time);
export { ReduxTime, AssistDuration };
export { ReduxTime };

View file

@ -4,7 +4,7 @@ import { observer } from 'mobx-react-lite';
import styles from './timeTracker.module.css';
import cn from 'classnames'
const TimeTracker = ({ scale, live, left }) => {
const TimeTracker = ({ scale, live = false, left }) => {
const { store } = React.useContext(PlayerContext)
const time = store.get().time

View file

@ -40,8 +40,6 @@ function Timeline(props: IProps) {
skipToIssue,
ready,
endTime,
live,
liveTimeTravel,
} = store.get()
const { issues } = props;
const notes = notesStore.sessionNotes
@ -64,16 +62,13 @@ function Timeline(props: IProps) {
const debouncedTooltipChange = useMemo(() => debounce(props.setTimelineHoverTime, 50), [])
const onDragEnd = () => {
if (live && !liveTimeTravel) return;
if (wasPlaying) {
player.togglePlay();
}
};
const onDrag: OnDragCallback = (offset) => {
if ((live && !liveTimeTravel) || !progressRef.current) return;
// @ts-ignore react mismatch
const p = (offset.x) / progressRef.current.offsetWidth;
const time = Math.max(Math.round(p * endTime), 0);
debouncedJump(time);
@ -84,39 +79,20 @@ function Timeline(props: IProps) {
}
};
const getLiveTime = (e: React.MouseEvent) => {
const duration = new Date().getTime() - props.startedAt;
const p = e.nativeEvent.offsetX / e.target.offsetWidth;
const time = Math.max(Math.round(p * duration), 0);
return [time, duration];
};
const showTimeTooltip = (e: React.MouseEvent<HTMLDivElement>) => {
if (e.target !== progressRef.current && e.target !== timelineRef.current) {
return props.tooltipVisible && hideTimeTooltip();
}
let timeLineTooltip;
if (live) {
const [time, duration] = getLiveTime(e);
timeLineTooltip = {
time: Duration.fromMillis(duration - time).toFormat(`-mm:ss`),
offset: e.nativeEvent.offsetX,
isVisible: true,
};
} else {
const time = getTime(e);
const tz = settingsStore.sessionSettings.timezone.value
const timeStr = DateTime.fromMillis(props.startedAt + time).setZone(tz).toFormat(`hh:mm:ss a`)
timeLineTooltip = {
time: Duration.fromMillis(time).toFormat(`mm:ss`),
timeStr,
offset: e.nativeEvent.offsetX,
isVisible: true,
};
}
const time = getTime(e);
const tz = settingsStore.sessionSettings.timezone.value
const timeStr = DateTime.fromMillis(props.startedAt + time).setZone(tz).toFormat(`hh:mm:ss a`)
const timeLineTooltip = {
time: Duration.fromMillis(time).toFormat(`mm:ss`),
timeStr,
offset: e.nativeEvent.offsetX,
isVisible: true,
};
debouncedTooltipChange(timeLineTooltip);
}
@ -132,29 +108,16 @@ function Timeline(props: IProps) {
hideTimeTooltip();
};
const loadAndSeek = async (e: React.MouseEvent<HTMLDivElement>) => {
e.persist();
await player.toggleTimetravel();
setTimeout(() => {
seekProgress(e);
});
};
const jumpToTime = (e: React.MouseEvent<HTMLDivElement>) => {
if (live && !liveTimeTravel) {
loadAndSeek(e);
} else {
seekProgress(e);
}
seekProgress(e);
};
const getTime = (e: React.MouseEvent<HTMLDivElement>, customEndTime?: number) => {
// @ts-ignore react mismatch
const p = e.nativeEvent.offsetX / e.target.offsetWidth;
const targetTime = customEndTime || endTime;
const time = Math.max(Math.round(p * targetTime), 0);
return time;
return Math.max(Math.round(p * targetTime), 0);
};
return (
@ -176,21 +139,19 @@ function Timeline(props: IProps) {
onMouseEnter={showTimeTooltip}
onMouseLeave={hideTimeTooltip}
>
<TooltipContainer live={live} />
{/* custo color is live */}
<TooltipContainer />
<DraggableCircle
left={time * scale}
onDrop={onDragEnd}
live={live}
/>
<CustomDragLayer
onDrag={onDrag}
minX={0}
maxX={progressRef.current ? progressRef.current.offsetWidth : 0}
/>
<TimeTracker scale={scale} live={live} left={time * scale} />
<TimeTracker scale={scale} left={time * scale} />
{!live && skip ?
{skip ?
skipIntervals.map((interval) => (
<div
key={interval.start}

View file

@ -32,7 +32,7 @@ const ItemTypes = {
interface Props {
left: number
live: boolean
live?: boolean
onDrop?: () => void
}

View file

@ -1,13 +1,11 @@
import React from 'react';
import { Icon, Tooltip, Popover } from 'UI';
import cn from 'classnames';
import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv';
import { ReduxTime } from '../Time';
// @ts-ignore
import styles from '../controls.module.css';
interface Props {
live: boolean;
skip: boolean;
speed: number;
disabled: boolean;
@ -30,7 +28,6 @@ interface Props {
function PlayerControls(props: Props) {
const {
live,
skip,
speed,
disabled,
@ -45,10 +42,10 @@ function PlayerControls(props: Props) {
controlIcon,
} = props;
const [showTooltip, setShowTooltip] = React.useState(false);
const speedRef = React.useRef(null);
const arrowBackRef = React.useRef(null);
const arrowForwardRef = React.useRef(null);
const skipRef = React.useRef<HTMLDivElement>();
const speedRef = React.useRef<HTMLButtonElement>(null);
const arrowBackRef = React.useRef<HTMLButtonElement>(null);
const arrowForwardRef = React.useRef<HTMLButtonElement>(null);
const skipRef = React.useRef<HTMLDivElement>(null);
React.useEffect(() => {
const handleKeyboard = (e: KeyboardEvent) => {
@ -56,16 +53,16 @@ function PlayerControls(props: Props) {
return;
}
if (e.key === 'ArrowRight') {
arrowForwardRef.current.focus();
arrowForwardRef.current?.focus();
}
if (e.key === 'ArrowLeft') {
arrowBackRef.current.focus();
arrowBackRef.current?.focus();
}
if (e.key === 'ArrowDown') {
speedRef.current.focus();
speedRef.current?.focus();
}
if (e.key === 'ArrowUp') {
speedRef.current.focus();
speedRef.current?.focus();
}
};
document.addEventListener('keydown', handleKeyboard);
@ -75,22 +72,20 @@ function PlayerControls(props: Props) {
const toggleTooltip = () => {
setShowTooltip(!showTooltip);
};
const handleClickOutside = () => {
setShowTooltip(false);
};
return (
<div className="flex items-center">
{playButton}
<div className="mx-1" />
{!live && (
<div className="flex items-center font-semibold text-center" style={{ minWidth: 85 }}>
{/* @ts-ignore */}
<ReduxTime isCustom name="time" format="mm:ss" />
<span className="px-1">/</span>
{/* @ts-ignore */}
<ReduxTime isCustom name="endTime" format="mm:ss" />
</div>
)}
<div className="flex items-center font-semibold text-center" style={{ minWidth: 85 }}>
{/* @ts-ignore */}
<ReduxTime isCustom name="time" format="mm:ss" />
<span className="px-1">/</span>
{/* @ts-ignore */}
<ReduxTime isCustom name="endTime" format="mm:ss" />
</div>
<div className="rounded ml-4 bg-active-blue border border-active-blue-border flex items-stretch">
{/* @ts-ignore */}
@ -115,8 +110,6 @@ function PlayerControls(props: Props) {
<div className="p-1 border-l border-r bg-active-blue-border border-active-blue-border flex items-center">
<Popover
// open={showTooltip}
// interactive
// @ts-ignore
theme="nopadding"
animation="none"
@ -176,7 +169,7 @@ function PlayerControls(props: Props) {
</Tooltip>
</div>
{!live && (
<div className="flex items-center">
<div className="mx-2" />
{/* @ts-ignore */}
@ -203,7 +196,7 @@ function PlayerControls(props: Props) {
{'Skip Inactivity'}
</button>
</div>
)}
</div>
);
}

View file

@ -4,12 +4,12 @@ import CreateNote from './CreateNote';
import store from 'App/store';
import { Provider } from 'react-redux';
function TooltipContainer({ live }: { live: boolean }) {
function TooltipContainer() {
return (
<Provider store={store}>
<>
<TimeTooltip liveTimeTravel={live} />
<TimeTooltip />
<CreateNote />
</>
</Provider>

View file

@ -1,18 +1,8 @@
import React from 'react';
import {
SessionRecordingStatus,
getStatusText,
CallingState,
ConnectionStatus,
RemoteControlStatus,
} from 'Player';
import AutoplayTimer from './Overlay/AutoplayTimer';
import PlayIconLayer from './Overlay/PlayIconLayer';
import LiveStatusText from './Overlay/LiveStatusText';
import Loader from './Overlay/Loader';
import ElementsMarker from './Overlay/ElementsMarker';
import RequestingWindow, { WindowType } from 'App/components/Assist/RequestingWindow';
import { PlayerContext } from 'App/components/Session/playerContext';
import { observer } from 'mobx-react-lite';
@ -24,7 +14,6 @@ interface Props {
function Overlay({
nextId,
closedLive,
isClickmap,
}: Props) {
const { player, store } = React.useContext(PlayerContext)
@ -37,53 +26,17 @@ function Overlay({
completed,
autoplay,
inspectorMode,
live,
peerConnectionStatus,
markedTargets,
activeTargetIndex,
livePlay,
calling,
remoteControl,
recordingState,
} = store.get()
const loading = messagesLoading || cssLoading
const liveStatusText = getStatusText(peerConnectionStatus)
const concetionStatus = peerConnectionStatus
const showAutoplayTimer = !live && completed && autoplay && nextId
const showPlayIconLayer = !isClickmap && !live && !markedTargets && !inspectorMode && !loading && !showAutoplayTimer;
const showLiveStatusText = live && livePlay && liveStatusText && !loading;
const showRequestWindow =
live &&
(calling === CallingState.Connecting ||
remoteControl === RemoteControlStatus.Requesting ||
recordingState === SessionRecordingStatus.Requesting);
const getRequestWindowType = () => {
if (calling === CallingState.Connecting) {
return WindowType.Call
}
if (remoteControl === RemoteControlStatus.Requesting) {
return WindowType.Control
}
if (recordingState === SessionRecordingStatus.Requesting) {
return WindowType.Record
}
return null;
}
const showAutoplayTimer = completed && autoplay && nextId
const showPlayIconLayer = !isClickmap && !markedTargets && !inspectorMode && !loading && !showAutoplayTimer;
return (
<>
{showRequestWindow ? <RequestingWindow getWindowType={getRequestWindowType} /> : null}
{showAutoplayTimer && <AutoplayTimer />}
{showLiveStatusText && (
<LiveStatusText
text={liveStatusText}
concetionStatus={closedLive ? ConnectionStatus.Closed : concetionStatus}
/>
)}
{loading ? <Loader /> : null}
{showPlayIconLayer && <PlayIconLayer playing={playing} togglePlay={togglePlay} />}
{markedTargets && <ElementsMarker targets={markedTargets} activeIndex={activeTargetIndex} />}

View file

@ -3,5 +3,14 @@ import Marker from './ElementsMarker/Marker';
import type { MarkedTarget } from 'Player';
export default function ElementsMarker({ targets, activeIndex }: { targets: MarkedTarget[], activeIndex: number }) {
return targets && targets.map(t => <React.Fragment key={t.index}><Marker target={t} active={activeIndex === t.index}/></React.Fragment>)
return targets ? <>
{targets.map(
t => <React.Fragment key={t.index}>
<Marker
target={t}
active={activeIndex === t.index}
/>
</React.Fragment>
)}
</> : null
}

View file

@ -1,36 +0,0 @@
import React from 'react';
import cn from 'classnames';
import { connect } from 'react-redux';
import Player from './Player';
import SubHeader from './Subheader';
import styles from './playerBlock.module.css';
@connect((state) => ({
fullscreen: state.getIn(['components', 'player', 'fullscreen']),
sessionId: state.getIn(['sessions', 'current']).sessionId,
disabled: state.getIn(['components', 'targetDefiner', 'inspectorMode']),
jiraConfig: state.getIn(['issues', 'list'])[0],
}))
export default class PlayerBlock extends React.PureComponent {
render() {
const { fullscreen, sessionId, disabled, activeTab, jiraConfig, fullView = false, isMultiview, isClickmap } = this.props;
const shouldShowSubHeader = !fullscreen && !fullView && !isMultiview && !isClickmap
return (
<div className={cn(styles.playerBlock, 'flex flex-col', !isClickmap ? 'overflow-x-hidden' : 'overflow-visible')} style={{ zIndex: isClickmap ? 1 : undefined, minWidth: isMultiview || isClickmap ? '100%' : undefined }}>
{shouldShowSubHeader ? (
<SubHeader sessionId={sessionId} disabled={disabled} jiraConfig={jiraConfig} />
) : null}
<Player
className="flex-1"
fullscreen={fullscreen}
activeTab={activeTab}
fullView={fullView}
isMultiview={isMultiview}
isClickmap={isClickmap}
/>
</div>
);
}
}

View file

@ -11,7 +11,6 @@ import { useModal } from 'App/components/Modal';
import BugReportModal from './BugReport/BugReportModal';
import { PlayerContext } from 'App/components/Session/playerContext';
import { observer } from 'mobx-react-lite';
import { useStore } from 'App/mstore';
import AutoplayToggle from 'Shared/AutoplayToggle';
function SubHeader(props) {
@ -35,7 +34,6 @@ function SubHeader(props) {
const [isCopied, setCopied] = React.useState(false);
const { showModal, hideModal } = useModal();
const isAssist = window.location.pathname.includes('/assist/');
const location =
currentLocation && currentLocation.length > 60
@ -72,7 +70,6 @@ function SubHeader(props) {
</Tooltip>
</div>
)}
{!isAssist ? (
<div
className="ml-auto text-sm flex items-center color-gray-medium gap-2"
style={{ width: 'max-content' }}
@ -111,7 +108,6 @@ function SubHeader(props) {
<QueueControls />
</div>
</div>
) : null}
</div>
);
}

View file

@ -2,7 +2,7 @@ import React from 'react'
import { Icon } from 'UI';
import stl from './escapeButton.module.css'
function EscapeButton({ onClose = null}) {
function EscapeButton({ onClose = () => null }) {
return (
<div className={ stl.closeWrapper } onClick={ onClose }>
<Icon name="close" size="16" />