change(ui): display timeline on the assist by default
This commit is contained in:
parent
7b65531ca7
commit
cac29f9e87
9 changed files with 95 additions and 69 deletions
|
|
@ -26,7 +26,7 @@ function ChatWindow({ userId, incomeStream, localStream, endCall, isPrestart }:
|
|||
>
|
||||
<div className="handle flex items-center p-2 cursor-move select-none border-b">
|
||||
<div className={stl.headerTitle}>
|
||||
<b>Talking to </b> {userId ? userId : 'Anonymous User'}
|
||||
<b>Call with </b> {userId ? userId : 'Anonymous User'}
|
||||
<br />
|
||||
{incomeStream && incomeStream.length > 2 ? ' (+ other agents in the call)' : ''}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
import LiveTag from 'Shared/LiveTag';
|
||||
import { toggleTimetravel, jumpToLive } from 'Player';
|
||||
|
||||
import { Icon, Button } from 'UI';
|
||||
import { Icon } from 'UI';
|
||||
import { toggleInspectorMode } from 'Player';
|
||||
import {
|
||||
fullscreenOn,
|
||||
|
|
@ -326,15 +326,13 @@ export default class Controls extends React.Component {
|
|||
|
||||
return (
|
||||
<div className={styles.controls}>
|
||||
{!live || liveTimeTravel ? (
|
||||
<Timeline
|
||||
live={live}
|
||||
jump={this.props.jump}
|
||||
liveTimeTravel={liveTimeTravel}
|
||||
pause={this.props.pause}
|
||||
togglePlay={this.props.togglePlay}
|
||||
/>
|
||||
) : null}
|
||||
<Timeline
|
||||
live={live}
|
||||
jump={this.props.jump}
|
||||
liveTimeTravel={liveTimeTravel}
|
||||
pause={this.props.pause}
|
||||
togglePlay={this.props.togglePlay}
|
||||
/>
|
||||
{!fullscreen && (
|
||||
<div className={cn(styles.buttons, { '!px-5 !pt-0': live })} data-is-live={live}>
|
||||
<div className="flex items-center">
|
||||
|
|
@ -370,15 +368,6 @@ export default class Controls extends React.Component {
|
|||
<div className="font-semibold px-2">
|
||||
<AssistDuration isLivePlay={livePlay} />
|
||||
</div>
|
||||
|
||||
{!liveTimeTravel && (
|
||||
<div
|
||||
onClick={toggleTimetravel}
|
||||
className="p-2 ml-2 rounded hover:bg-teal-light bg-gray-lightest cursor-pointer"
|
||||
>
|
||||
See Past Activity
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,12 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import cn from 'classnames';
|
||||
import { connectPlayer, Controls } from 'Player';
|
||||
import { TimelinePointer, Icon } from 'UI';
|
||||
import { connectPlayer, Controls, toggleTimetravel } from 'Player';
|
||||
import TimeTracker from './TimeTracker';
|
||||
import stl from './timeline.module.css';
|
||||
import { TYPES } from 'Types/session/event';
|
||||
import { setTimelinePointer, setTimelineHoverTime } from 'Duck/sessions';
|
||||
import DraggableCircle from './DraggableCircle';
|
||||
import CustomDragLayer from './CustomDragLayer';
|
||||
import { debounce } from 'App/utils';
|
||||
import { Tooltip } from 'react-tippy';
|
||||
import TooltipContainer from './components/TooltipContainer';
|
||||
|
||||
const BOUNDRY = 0;
|
||||
|
|
@ -84,6 +80,7 @@ let debounceTooltipChange = () => null;
|
|||
@connect(
|
||||
(state) => ({
|
||||
issues: state.getIn(['sessions', 'current', 'issues']),
|
||||
startedAt: state.getIn(['sessions', 'current', 'startedAt']),
|
||||
clickRageTime: state.getIn(['sessions', 'current', 'clickRage']) && state.getIn(['sessions', 'current', 'clickRageTime']),
|
||||
returningLocationTime:
|
||||
state.getIn(['sessions', 'current', 'returningLocation']) && state.getIn(['sessions', 'current', 'returningLocationTime']),
|
||||
|
|
@ -102,10 +99,28 @@ export default class Timeline extends React.PureComponent {
|
|||
this.hideTimeTooltip();
|
||||
};
|
||||
|
||||
getTime = (e) => {
|
||||
loadAndSeek = async (e) => {
|
||||
e.persist();
|
||||
await toggleTimetravel();
|
||||
|
||||
setTimeout(() => {
|
||||
this.seekProgress(e)
|
||||
})
|
||||
}
|
||||
|
||||
jumpToTime = (e) => {
|
||||
if (this.props.live && !this.props.liveTimeTravel) {
|
||||
this.loadAndSeek(e)
|
||||
} else {
|
||||
this.seekProgress(e)
|
||||
}
|
||||
}
|
||||
|
||||
getTime = (e, customEndTime) => {
|
||||
const { endTime } = this.props;
|
||||
const p = e.nativeEvent.offsetX / e.target.offsetWidth;
|
||||
const time = Math.max(Math.round(p * endTime), 0);
|
||||
const targetTime = customEndTime || endTime
|
||||
const time = Math.max(Math.round(p * targetTime), 0);
|
||||
|
||||
return time;
|
||||
};
|
||||
|
|
@ -129,13 +144,17 @@ export default class Timeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
onDragEnd = () => {
|
||||
const { live, liveTimeTravel } = this.props;
|
||||
if (live && !liveTimeTravel) return;
|
||||
|
||||
if (this.wasPlaying) {
|
||||
this.props.togglePlay();
|
||||
}
|
||||
};
|
||||
|
||||
onDrag = (offset) => {
|
||||
const { endTime } = this.props;
|
||||
const { endTime, live, liveTimeTravel } = this.props;
|
||||
if (live && !liveTimeTravel) return;
|
||||
|
||||
const p = (offset.x - BOUNDRY) / this.progressRef.current.offsetWidth;
|
||||
const time = Math.max(Math.round(p * endTime), 0);
|
||||
|
|
@ -147,18 +166,39 @@ export default class Timeline extends React.PureComponent {
|
|||
}
|
||||
};
|
||||
|
||||
getLiveTime = (e) => {
|
||||
const { startedAt } = this.props;
|
||||
const duration = new Date().getTime() - startedAt
|
||||
const p = e.nativeEvent.offsetX / e.target.offsetWidth;
|
||||
const time = Math.max(Math.round(p * duration), 0);
|
||||
|
||||
return [time, duration];
|
||||
};
|
||||
|
||||
showTimeTooltip = (e) => {
|
||||
if (e.target !== this.progressRef.current && e.target !== this.timelineRef.current) {
|
||||
return this.props.tooltipVisible && this.hideTimeTooltip();
|
||||
}
|
||||
const time = this.getTime(e);
|
||||
const { endTime, liveTimeTravel } = this.props;
|
||||
|
||||
const timeLineTooltip = {
|
||||
time: liveTimeTravel ? endTime - time : time,
|
||||
offset: e.nativeEvent.offsetX,
|
||||
isVisible: true,
|
||||
};
|
||||
const { live } = this.props;
|
||||
let timeLineTooltip;
|
||||
|
||||
if (live) {
|
||||
const [time, duration] = this.getLiveTime(e);
|
||||
timeLineTooltip = {
|
||||
time: (duration - time),
|
||||
offset: e.nativeEvent.offsetX,
|
||||
isVisible: true,
|
||||
};
|
||||
} else {
|
||||
const time = this.getTime(e);
|
||||
timeLineTooltip = {
|
||||
time: time,
|
||||
offset: e.nativeEvent.offsetX,
|
||||
isVisible: true,
|
||||
}
|
||||
}
|
||||
|
||||
debounceTooltipChange(timeLineTooltip);
|
||||
};
|
||||
|
||||
|
|
@ -174,13 +214,7 @@ export default class Timeline extends React.PureComponent {
|
|||
skipIntervals,
|
||||
disabled,
|
||||
endTime,
|
||||
exceptionsList,
|
||||
resourceList,
|
||||
clickRageTime,
|
||||
stackList,
|
||||
fetchList,
|
||||
issues,
|
||||
liveTimeTravel,
|
||||
live,
|
||||
} = this.props;
|
||||
|
||||
const scale = 100 / endTime;
|
||||
|
|
@ -189,14 +223,14 @@ export default class Timeline extends React.PureComponent {
|
|||
<div className="flex items-center absolute w-full" style={{ top: '-4px', zIndex: 100, padding: `0 ${BOUNDRY}px`, maxWidth: '100%' }}>
|
||||
<div
|
||||
className={stl.progress}
|
||||
onClick={disabled ? null : this.seekProgress}
|
||||
onClick={disabled ? null : this.jumpToTime}
|
||||
ref={this.progressRef}
|
||||
role="button"
|
||||
onMouseMoveCapture={this.showTimeTooltip}
|
||||
onMouseEnter={this.showTimeTooltip}
|
||||
onMouseLeave={this.hideTimeTooltip}
|
||||
>
|
||||
<TooltipContainer liveTimeTravel={liveTimeTravel} />
|
||||
<TooltipContainer live={live} />
|
||||
{/* custo color is live */}
|
||||
<DraggableCircle left={this.props.time * scale} onDrop={this.onDragEnd} live={this.props.live} />
|
||||
<CustomDragLayer
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import TimeTooltip from '../TimeTooltip';
|
|||
import store from 'App/store';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
function TooltipContainer({ liveTimeTravel }: { liveTimeTravel: boolean }) {
|
||||
function TooltipContainer({ live }: { live: boolean }) {
|
||||
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<TimeTooltip liveTimeTravel={liveTimeTravel} />
|
||||
<TimeTooltip liveTimeTravel={live} />
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ function Overlay({
|
|||
const showPlayIconLayer = !live && !markedTargets && !inspectorMode && !loading && !showAutoplayTimer;
|
||||
const showLiveStatusText = live && livePlay && liveStatusText && !loading;
|
||||
|
||||
console.log(calling, live)
|
||||
return (
|
||||
<>
|
||||
{live && calling === CallingState.Connecting ? <RequestingWindow /> : null}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import { Duration } from 'luxon';
|
||||
import { durationFormatted, convertTimestampToUtcTimestamp } from 'App/date';
|
||||
import { convertTimestampToUtcTimestamp } from 'App/date';
|
||||
|
||||
interface Props {
|
||||
startTime: any,
|
||||
|
|
@ -10,7 +9,11 @@ interface Props {
|
|||
function Counter({ startTime, className }: Props) {
|
||||
let intervalId: NodeJS.Timer;
|
||||
const [duration, setDuration] = useState(convertTimestampToUtcTimestamp(new Date().getTime()) - convertTimestampToUtcTimestamp(startTime));
|
||||
const formattedDuration = durationFormatted(Duration.fromMillis(duration));
|
||||
|
||||
const secsFull = ~~(duration / 1000)
|
||||
const mins = ~~(secsFull / 60)
|
||||
const secs = secsFull - mins * 60
|
||||
const formattedDuration = `${mins}:${secs < 10 ? 0 : ''}${secs}`
|
||||
|
||||
useEffect(() => {
|
||||
if (!intervalId) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import Resource, { TYPES } from 'Types/session/resource'; // MBTODO: player type
|
|||
import { TYPES as EVENT_TYPES } from 'Types/session/event';
|
||||
import Log from 'Types/session/log';
|
||||
|
||||
import { update, getState } from '../store';
|
||||
import { update } from '../store';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import {
|
||||
|
|
@ -248,7 +248,6 @@ export default class MessageDistributor extends StatedScreen {
|
|||
const onData = (byteArray: Uint8Array) => {
|
||||
const onReadCallback = () => this.setLastRecordedMessageTime(this.lastMessageTime)
|
||||
const msgs = this.readAndDistributeMessages(byteArray, onReadCallback)
|
||||
this.sessionStart = msgs[0].time
|
||||
this.processStateUpdates(msgs)
|
||||
}
|
||||
|
||||
|
|
@ -275,6 +274,8 @@ export default class MessageDistributor extends StatedScreen {
|
|||
this.waitingForFiles = false
|
||||
this.setMessagesLoading(false)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private reloadMessageManagers() {
|
||||
|
|
|
|||
|
|
@ -72,15 +72,15 @@ export default class Player extends MessageDistributor {
|
|||
private _startAnimation() {
|
||||
let prevTime = getState().time;
|
||||
let animationPrevTime = performance.now();
|
||||
|
||||
|
||||
const nextFrame = (animationCurrentTime: number) => {
|
||||
const {
|
||||
speed,
|
||||
const {
|
||||
speed,
|
||||
skip,
|
||||
autoplay,
|
||||
skipIntervals,
|
||||
endTime,
|
||||
live,
|
||||
autoplay,
|
||||
skipIntervals,
|
||||
endTime,
|
||||
live,
|
||||
livePlay,
|
||||
disconnected,
|
||||
messagesLoading,
|
||||
|
|
@ -159,7 +159,7 @@ export default class Player extends MessageDistributor {
|
|||
jump(time = getState().time, index: number) {
|
||||
const { live, liveTimeTravel, endTime } = getState();
|
||||
if (live && !liveTimeTravel) return;
|
||||
|
||||
|
||||
if (getState().playing) {
|
||||
cancelAnimationFrame(this._animationFrameRequestId);
|
||||
// this._animationFrameRequestId = requestAnimationFrame(() => {
|
||||
|
|
@ -188,7 +188,7 @@ export default class Player extends MessageDistributor {
|
|||
const { inspectorMode } = getState();
|
||||
flag = !inspectorMode;
|
||||
}
|
||||
|
||||
|
||||
if (flag) {
|
||||
this.pause();
|
||||
update({ inspectorMode: true });
|
||||
|
|
@ -199,7 +199,7 @@ export default class Player extends MessageDistributor {
|
|||
}
|
||||
}
|
||||
|
||||
markTargets(targets: { selector: string, count: number }[] | null) {
|
||||
markTargets(targets: { selector: string, count: number }[] | null) {
|
||||
this.pause();
|
||||
this.setMarkedTargets(targets);
|
||||
}
|
||||
|
|
@ -207,7 +207,7 @@ export default class Player extends MessageDistributor {
|
|||
activeTarget(index: number) {
|
||||
this.setActiveTarget(index);
|
||||
}
|
||||
|
||||
|
||||
toggleSkipToIssue() {
|
||||
const skipToIssue = !getState().skipToIssue;
|
||||
localStorage.setItem(SKIP_TO_ISSUE_STORAGE_KEY, `${skipToIssue}`);
|
||||
|
|
@ -219,13 +219,13 @@ export default class Player extends MessageDistributor {
|
|||
update({ skipToIssue });
|
||||
return skipToIssue;
|
||||
}
|
||||
|
||||
|
||||
toggleAutoplay() {
|
||||
const autoplay = !getState().autoplay;
|
||||
localStorage.setItem(AUTOPLAY_STORAGE_KEY, `${autoplay}`);
|
||||
update({ autoplay });
|
||||
}
|
||||
|
||||
|
||||
toggleEvents(shouldShow?: boolean) {
|
||||
const showEvents = shouldShow || !getState().showEvents;
|
||||
localStorage.setItem(SHOW_EVENTS_STORAGE_KEY, `${showEvents}`);
|
||||
|
|
@ -252,13 +252,12 @@ export default class Player extends MessageDistributor {
|
|||
this._updateSpeed(Math.max(1, speed/2));
|
||||
}
|
||||
|
||||
toggleTimetravel() {
|
||||
async toggleTimetravel() {
|
||||
if (!getState().liveTimeTravel) {
|
||||
this.reloadWithUnprocessedFile()
|
||||
this.play()
|
||||
return await this.reloadWithUnprocessedFile()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
jumpToLive() {
|
||||
cancelAnimationFrame(this._animationFrameRequestId);
|
||||
this._setTime(getState().endTime);
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ export const requestReleaseRemoteControl = initCheck((...args) => instance.assis
|
|||
export const markTargets = initCheck((...args) => instance.markTargets(...args))
|
||||
export const activeTarget = initCheck((...args) => instance.activeTarget(...args))
|
||||
export const toggleAnnotation = initCheck((...args) => instance.assistManager.toggleAnnotation(...args))
|
||||
/** @type {Player.toggleTimetravel} */
|
||||
export const toggleTimetravel = initCheck((...args) => instance.toggleTimetravel(...args))
|
||||
export const jumpToLive = initCheck((...args) => instance.jumpToLive(...args))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue