-
- {!live && (
-
- )}
-
- { live && !closedLive && (
-
-
livePlay ? null : jumpToLive()} />
-
-
- {!liveTimeTravel && (
-
- See Past Activity
-
- )}
+ return (
+
+
+
- )}
-
+
+ );
+ };
-
- { !live &&
}
- {/* ! TEMP DISABLED !
+ controlIcon = (icon, size, action, isBackwards, additionalClasses) => (
+
+
+
+ );
+
+ render() {
+ const {
+ bottomBlock,
+ toggleBottomBlock,
+ live,
+ livePlay,
+ skip,
+ speed,
+ disabled,
+ logCount,
+ logRedCount,
+ resourceRedCount,
+ fetchRedCount,
+ showStack,
+ stackCount,
+ stackRedCount,
+ profilesCount,
+ storageCount,
+ showStorage,
+ storageType,
+ showProfiler,
+ showGraphql,
+ showFetch,
+ fetchCount,
+ graphqlCount,
+ exceptionsCount,
+ showExceptions,
+ fullscreen,
+ inspectorMode,
+ closedLive,
+ toggleSpeed,
+ toggleSkip,
+ liveTimeTravel,
+ } = this.props;
+
+ const toggleBottomTools = (blockName) => {
+ if (blockName === INSPECTOR) {
+ toggleInspectorMode();
+ bottomBlock && toggleBottomBlock();
+ } else {
+ toggleInspectorMode(false);
+ toggleBottomBlock(blockName);
+ }
+ };
+
+ return (
+
+ {!live || liveTimeTravel ? (
+
+ ) : null}
+ {!fullscreen && (
+
+
+ {!live && (
+ <>
+
+ {/*
*/}
+
+
toggleBottomTools(OVERVIEW)} />
+ >
+ )}
+
+ {live && !closedLive && (
+
+
(livePlay ? null : jumpToLive())} />
+
+
+ {!liveTimeTravel && (
+
+ See Past Activity
+
+ )}
+
+ )}
+
+
+
+ {/* { !live &&
} */}
+ {/* ! TEMP DISABLED !
{!live && (
)} */}
-
toggleBottomTools(OVERVIEW) }
active={ bottomBlock === OVERVIEW && !inspectorMode}
@@ -360,132 +358,132 @@ export default class Controls extends React.Component {
// count={ logCount }
// hasErrors={ logRedCount > 0 }
containerClassName="mx-2"
- />
- toggleBottomTools(CONSOLE) }
- active={ bottomBlock === CONSOLE && !inspectorMode}
- label="CONSOLE"
- noIcon
- labelClassName="!text-base font-semibold"
- count={ logCount }
- hasErrors={ logRedCount > 0 }
- 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"
- />
- }
- {showFetch &&
- toggleBottomTools(FETCH) }
- active={ bottomBlock === FETCH && !inspectorMode }
- hasErrors={ fetchRedCount > 0 }
- count={ fetchCount }
- label="FETCH"
- noIcon
- labelClassName="!text-base font-semibold"
- containerClassName="mx-2"
- />
- }
- { !live && showGraphql &&
- toggleBottomTools(GRAPHQL) }
- active={ bottomBlock === GRAPHQL && !inspectorMode }
- count={ graphqlCount }
- label="GRAPHQL"
- noIcon
- labelClassName="!text-base font-semibold"
- containerClassName="mx-2"
- />
- }
- { !live && showStorage &&
- toggleBottomTools(STORAGE) }
- active={ bottomBlock === STORAGE && !inspectorMode }
- count={ storageCount }
- label={ getStorageName(storageType) }
- noIcon
- labelClassName="!text-base font-semibold"
- containerClassName="mx-2"
- />
- }
- { showExceptions &&
- toggleBottomTools(EXCEPTIONS) }
- active={ bottomBlock === EXCEPTIONS && !inspectorMode }
- label="EXCEPTIONS"
- noIcon
- labelClassName="!text-base font-semibold"
- containerClassName="mx-2"
- count={ exceptionsCount }
- hasErrors={ exceptionsCount > 0 }
- />
- }
- { !live && showStack &&
- toggleBottomTools(STACKEVENTS) }
- active={ bottomBlock === STACKEVENTS && !inspectorMode }
- label="EVENTS"
- noIcon
- labelClassName="!text-base font-semibold"
- containerClassName="mx-2"
- count={ stackCount }
- hasErrors={ stackRedCount > 0 }
- />
- }
- { !live && showProfiler &&
- toggleBottomTools(PROFILER) }
- active={ bottomBlock === PROFILER && !inspectorMode }
- count={ profilesCount }
- label="PROFILER"
- noIcon
- labelClassName="!text-base font-semibold"
- containerClassName="mx-2"
- />
- }
- { !live && }
- { !live && (
-
- {this.controlIcon("arrows-angle-extend", 18, this.props.fullscreenOn, false, "rounded hover:bg-gray-light-shade color-gray-medium")}
-
- )
- }
+ /> */}
+ toggleBottomTools(CONSOLE)}
+ active={bottomBlock === CONSOLE && !inspectorMode}
+ label="CONSOLE"
+ noIcon
+ labelClassName="!text-base font-semibold"
+ count={logCount}
+ hasErrors={logRedCount > 0}
+ 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"
+ />
+ )}
+ {showFetch && (
+ toggleBottomTools(FETCH)}
+ active={bottomBlock === FETCH && !inspectorMode}
+ hasErrors={fetchRedCount > 0}
+ count={fetchCount}
+ label="FETCH"
+ noIcon
+ labelClassName="!text-base font-semibold"
+ containerClassName="mx-2"
+ />
+ )}
+ {!live && showGraphql && (
+ toggleBottomTools(GRAPHQL)}
+ active={bottomBlock === GRAPHQL && !inspectorMode}
+ count={graphqlCount}
+ label="GRAPHQL"
+ noIcon
+ labelClassName="!text-base font-semibold"
+ containerClassName="mx-2"
+ />
+ )}
+ {!live && showStorage && (
+ toggleBottomTools(STORAGE)}
+ active={bottomBlock === STORAGE && !inspectorMode}
+ count={storageCount}
+ label={getStorageName(storageType)}
+ noIcon
+ labelClassName="!text-base font-semibold"
+ containerClassName="mx-2"
+ />
+ )}
+ {showExceptions && (
+ toggleBottomTools(EXCEPTIONS)}
+ active={bottomBlock === EXCEPTIONS && !inspectorMode}
+ label="EXCEPTIONS"
+ noIcon
+ labelClassName="!text-base font-semibold"
+ containerClassName="mx-2"
+ count={exceptionsCount}
+ hasErrors={exceptionsCount > 0}
+ />
+ )}
+ {!live && showStack && (
+ toggleBottomTools(STACKEVENTS)}
+ active={bottomBlock === STACKEVENTS && !inspectorMode}
+ label="EVENTS"
+ noIcon
+ labelClassName="!text-base font-semibold"
+ containerClassName="mx-2"
+ count={stackCount}
+ hasErrors={stackRedCount > 0}
+ />
+ )}
+ {!live && showProfiler && (
+ toggleBottomTools(PROFILER)}
+ active={bottomBlock === PROFILER && !inspectorMode}
+ count={profilesCount}
+ label="PROFILER"
+ noIcon
+ labelClassName="!text-base font-semibold"
+ containerClassName="mx-2"
+ />
+ )}
+ {!live && }
+ {!live && (
+
+ {this.controlIcon(
+ 'arrows-angle-extend',
+ 18,
+ this.props.fullscreenOn,
+ false,
+ 'rounded hover:bg-gray-light-shade color-gray-medium'
+ )}
+
+ )}
+
+
+ )}
-
- }
-
- );
- }
+ );
+ }
}
diff --git a/frontend/app/components/Session_/Player/Controls/Timeline.js b/frontend/app/components/Session_/Player/Controls/Timeline.js
index c177c14e0..5ae8d67d2 100644
--- a/frontend/app/components/Session_/Player/Controls/Timeline.js
+++ b/frontend/app/components/Session_/Player/Controls/Timeline.js
@@ -13,393 +13,392 @@ import { debounce } from 'App/utils';
import { Tooltip } from 'react-tippy';
import TooltipContainer from './components/TooltipContainer';
-const BOUNDRY = 15
+const BOUNDRY = 0;
function getTimelinePosition(value, scale) {
- const pos = value * scale;
+ const pos = value * scale;
- return pos > 100 ? 100 : pos;
+ return pos > 100 ? 100 : pos;
}
const getPointerIcon = (type) => {
- // exception,
- switch(type) {
- case 'fetch':
- return 'funnel/file-earmark-minus-fill';
- case 'exception':
- return 'funnel/exclamation-circle-fill';
- case 'log':
- return 'funnel/exclamation-circle-fill';
- case 'stack':
- return 'funnel/patch-exclamation-fill';
- case 'resource':
- return 'funnel/file-earmark-minus-fill';
+ // exception,
+ switch (type) {
+ case 'fetch':
+ return 'funnel/file-earmark-minus-fill';
+ case 'exception':
+ return 'funnel/exclamation-circle-fill';
+ case 'log':
+ return 'funnel/exclamation-circle-fill';
+ case 'stack':
+ return 'funnel/patch-exclamation-fill';
+ case 'resource':
+ return 'funnel/file-earmark-minus-fill';
- case 'dead_click':
- return 'funnel/dizzy';
- case 'click_rage':
- return 'funnel/dizzy';
- case 'excessive_scrolling':
- return 'funnel/mouse';
- case 'bad_request':
- return 'funnel/file-medical-alt';
- case 'missing_resource':
- return 'funnel/file-earmark-minus-fill';
- case 'memory':
- return 'funnel/sd-card';
- case 'cpu':
- return 'funnel/microchip';
- case 'slow_resource':
- return 'funnel/hourglass-top';
- case 'slow_page_load':
- return 'funnel/hourglass-top';
- case 'crash':
- return 'funnel/file-exclamation';
- case 'js_exception':
- return 'funnel/exclamation-circle-fill';
- }
-
- return 'info';
-}
+ case 'dead_click':
+ return 'funnel/dizzy';
+ case 'click_rage':
+ return 'funnel/dizzy';
+ case 'excessive_scrolling':
+ return 'funnel/mouse';
+ case 'bad_request':
+ return 'funnel/file-medical-alt';
+ case 'missing_resource':
+ return 'funnel/file-earmark-minus-fill';
+ case 'memory':
+ return 'funnel/sd-card';
+ case 'cpu':
+ return 'funnel/microchip';
+ case 'slow_resource':
+ return 'funnel/hourglass-top';
+ case 'slow_page_load':
+ return 'funnel/hourglass-top';
+ case 'crash':
+ return 'funnel/file-exclamation';
+ case 'js_exception':
+ return 'funnel/exclamation-circle-fill';
+ }
+ return 'info';
+};
let deboucneJump = () => null;
let debounceTooltipChange = () => null;
-@connectPlayer(state => ({
- playing: state.playing,
- time: state.time,
- skipIntervals: state.skipIntervals,
- events: state.eventList,
- skip: state.skip,
- // not updating properly rn
- // skipToIssue: state.skipToIssue,
- disabled: state.cssLoading || state.messagesLoading || state.markedTargets,
- endTime: state.endTime,
- live: state.live,
- logList: state.logList,
- exceptionsList: state.exceptionsList,
- resourceList: state.resourceList,
- stackList: state.stackList,
- fetchList: state.fetchList,
+@connectPlayer((state) => ({
+ playing: state.playing,
+ time: state.time,
+ skipIntervals: state.skipIntervals,
+ events: state.eventList,
+ skip: state.skip,
+ // not updating properly rn
+ // skipToIssue: state.skipToIssue,
+ disabled: state.cssLoading || state.messagesLoading || state.markedTargets,
+ endTime: state.endTime,
+ live: state.live,
+ logList: state.logList,
+ exceptionsList: state.exceptionsList,
+ resourceList: state.resourceList,
+ stackList: state.stackList,
+ fetchList: state.fetchList,
}))
-@connect(state => ({
- issues: state.getIn([ 'sessions', 'current', 'issues' ]),
- clickRageTime: state.getIn([ 'sessions', 'current', 'clickRage' ]) &&
- state.getIn([ 'sessions', 'current', 'clickRageTime' ]),
- returningLocationTime: state.getIn([ 'sessions', 'current', 'returningLocation' ]) &&
- state.getIn([ 'sessions', 'current', 'returningLocationTime' ]),
- tooltipVisible: state.getIn(['sessions', 'timeLineTooltip', 'isVisible'])
-}), { setTimelinePointer, setTimelineHoverTime })
+@connect(
+ (state) => ({
+ issues: state.getIn(['sessions', 'current', 'issues']),
+ clickRageTime: state.getIn(['sessions', 'current', 'clickRage']) && state.getIn(['sessions', 'current', 'clickRageTime']),
+ returningLocationTime:
+ state.getIn(['sessions', 'current', 'returningLocation']) && state.getIn(['sessions', 'current', 'returningLocationTime']),
+ tooltipVisible: state.getIn(['sessions', 'timeLineTooltip', 'isVisible']),
+ }),
+ { setTimelinePointer, setTimelineHoverTime }
+)
export default class Timeline extends React.PureComponent {
- progressRef = React.createRef()
- timelineRef = React.createRef()
- wasPlaying = false
+ progressRef = React.createRef();
+ timelineRef = React.createRef();
+ wasPlaying = false;
- seekProgress = (e) => {
- const time = this.getTime(e)
- this.props.jump(time);
- this.hideTimeTooltip()
- }
+ seekProgress = (e) => {
+ const time = this.getTime(e);
+ this.props.jump(time);
+ this.hideTimeTooltip();
+ };
- getTime = (e) => {
- const { endTime } = this.props;
- const p = e.nativeEvent.offsetX / e.target.offsetWidth;
- const time = Math.max(Math.round(p * endTime), 0);
+ getTime = (e) => {
+ const { endTime } = this.props;
+ const p = e.nativeEvent.offsetX / e.target.offsetWidth;
+ const time = Math.max(Math.round(p * endTime), 0);
- return time
- }
+ return time;
+ };
- createEventClickHandler = pointer => (e) => {
- e.stopPropagation();
- this.props.jump(pointer.time);
- this.props.setTimelinePointer(pointer);
- }
+ createEventClickHandler = (pointer) => (e) => {
+ e.stopPropagation();
+ this.props.jump(pointer.time);
+ this.props.setTimelinePointer(pointer);
+ };
- componentDidMount() {
- const { issues } = this.props;
- const skipToIssue = Controls.updateSkipToIssue();
- const firstIssue = issues.get(0);
- deboucneJump = debounce(this.props.jump, 500);
- debounceTooltipChange = debounce(this.props.setTimelineHoverTime, 50);
+ componentDidMount() {
+ const { issues } = this.props;
+ const skipToIssue = Controls.updateSkipToIssue();
+ const firstIssue = issues.get(0);
+ deboucneJump = debounce(this.props.jump, 500);
+ debounceTooltipChange = debounce(this.props.setTimelineHoverTime, 50);
- if (firstIssue && skipToIssue) {
- this.props.jump(firstIssue.time);
+ if (firstIssue && skipToIssue) {
+ this.props.jump(firstIssue.time);
+ }
}
- }
- onDragEnd = () => {
- if (this.wasPlaying) {
- this.props.togglePlay();
+ onDragEnd = () => {
+ if (this.wasPlaying) {
+ this.props.togglePlay();
+ }
+ };
+
+ onDrag = (offset) => {
+ const { endTime } = this.props;
+
+ const p = (offset.x - BOUNDRY) / this.progressRef.current.offsetWidth;
+ const time = Math.max(Math.round(p * endTime), 0);
+ deboucneJump(time);
+ this.hideTimeTooltip();
+ if (this.props.playing) {
+ this.wasPlaying = true;
+ this.props.pause();
+ }
+ };
+
+ 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,
+ };
+ debounceTooltipChange(timeLineTooltip);
+ };
+
+ hideTimeTooltip = () => {
+ const timeLineTooltip = { isVisible: false };
+ debounceTooltipChange(timeLineTooltip);
+ };
+
+ render() {
+ const {
+ events,
+ skip,
+ skipIntervals,
+ disabled,
+ endTime,
+ exceptionsList,
+ resourceList,
+ clickRageTime,
+ stackList,
+ fetchList,
+ issues,
+ liveTimeTravel,
+ } = this.props;
+
+ const scale = 100 / endTime;
+
+ return (
+
+
+
+ {/* custo color is live */}
+
+
+
+
+ {skip &&
+ skipIntervals.map((interval) => (
+
+ ))}
+
+
+ {events.map((e) => (
+
+ ))}
+ {/* {issues.map((iss) => (
+
+
+ {iss.name}
+
+ }
+ >
+
+
+
+ ))}
+ {events
+ .filter((e) => e.type === TYPES.CLICKRAGE)
+ .map((e) => (
+
+
+ {'Click Rage'}
+
+ }
+ >
+
+
+
+ ))}
+ {typeof clickRageTime === 'number' && (
+
+
+ {'Click Rage'}
+
+ }
+ >
+
+
+
+ )}
+ {exceptionsList.map((e) => (
+
+ }
+ >
+