feat(ui) - overview - vertical line follow and jump

This commit is contained in:
Shekar Siri 2022-08-11 17:09:28 +02:00
parent 8805c84735
commit 930e502f25
8 changed files with 144 additions and 75 deletions

View file

@ -10,6 +10,8 @@ import FeatureSelection from './components/FeatureSelection/FeatureSelection';
import TimelinePointer from './components/TimelinePointer';
import VerticalPointerLine from './components/VerticalPointerLine';
import cn from 'classnames';
import VerticalLine from './components/VerticalLine';
import OverviewPanelContainer from './components/OverviewPanelContainer';
interface Props {
resourceList: any[];
@ -21,22 +23,24 @@ interface Props {
}
function OverviewPanel(props: Props) {
const { resourceList, exceptionsList, eventsList, stackEventList, issuesList } = props;
const clickRageList = React.useMemo(() => {
return eventsList.filter((item: any) => item.type === TYPES.CLICKRAGE);
}, [eventsList]);
// const scale = 100 / endTime;
const [selectedFeatures, setSelectedFeatures] = React.useState(['PERFORMANCE', 'ERRORS', 'EVENTS']);
const resources: any = {
NETWORK: resourceList,
ERRORS: exceptionsList,
EVENTS: stackEventList,
CLICKRAGE: clickRageList,
PERFORMANCE: issuesList,
};
const resources: any = React.useMemo(() => {
return {
NETWORK: resourceList,
ERRORS: exceptionsList,
EVENTS: stackEventList,
CLICKRAGE: clickRageList,
PERFORMANCE: issuesList,
};
}, [resourceList, exceptionsList, stackEventList, clickRageList, issuesList]);
return (
<BottomBlock style={{ height: '263px' }}>
<BottomBlock style={{ height: '260px' }}>
<BottomBlock.Header>
<span className="font-semibold color-gray-medium mr-4">Overview</span>
<div className="flex items-center h-20">
@ -44,9 +48,9 @@ function OverviewPanel(props: Props) {
</div>
</BottomBlock.Header>
<BottomBlock.Content>
<div className="overflow-x-auto overflow-y-hidden bg-gray-lightest">
<OverviewPanelContainer>
<TimelineScale />
<div style={{ width: '100%' }} className="transition relative">
<div style={{ width: '100%', height: '200px' }} className="transition relative">
<VerticalPointerLine />
{selectedFeatures.map((feature: any, index: number) => (
<div className={cn('', { 'bg-white border-t border-b': index % 2 })}>
@ -59,17 +63,20 @@ function OverviewPanel(props: Props) {
</div>
))}
</div>
</div>
</OverviewPanelContainer>
</BottomBlock.Content>
</BottomBlock>
);
}
export default connect((state: any) => ({
issuesList: state.getIn(['sessions', 'current', 'issues']),
}), {
toggleBottomBlock,
})(
export default connect(
(state: any) => ({
issuesList: state.getIn(['sessions', 'current', 'issues']),
}),
{
toggleBottomBlock,
}
)(
connectPlayer((state: any) => ({
resourceList: state.resourceList.filter((r: any) => r.isRed() || r.isYellow()),
exceptionsList: state.exceptionsList,

View file

@ -0,0 +1,44 @@
import React from 'react';
import VerticalLine from '../VerticalLine';
import { connectPlayer, Controls } from 'App/player';
interface Props {
children: React.ReactNode;
endTime: number;
}
function OverviewPanelContainer(props: Props) {
const { endTime } = props;
const [mouseX, setMouseX] = React.useState(0);
const [mouseIn, setMouseIn] = React.useState(false);
const onClickTrack = (e: any) => {
const p = e.nativeEvent.offsetX / e.target.offsetWidth;
const time = Math.max(Math.round(p * endTime), 0);
Controls.jump(time);
};
const onMouseMoveCapture = (e: any) => {
if (!mouseIn) {
return;
}
const p = e.nativeEvent.offsetX / e.target.offsetWidth;
setMouseX(p * 100);
};
return (
<div
className="overflow-x-auto overflow-y-hidden bg-gray-lightest"
onClick={onClickTrack}
onMouseMoveCapture={onMouseMoveCapture}
// onMouseOver={() => setMouseIn(true)}
// onMouseOut={() => setMouseIn(false)}
>
{mouseIn && <VerticalLine left={mouseX} className="border-gray-medium" />}
<div className="">{props.children}</div>
</div>
);
}
export default connectPlayer((state: any) => ({
endTime: state.endTime,
}))(OverviewPanelContainer);

View file

@ -0,0 +1 @@
export { default } from './OverviewPanelContainer';

View file

@ -0,0 +1,15 @@
import React from 'react';
import cn from 'classnames';
interface Props {
left: number;
className?: string;
height?: string;
width?: string;
}
function VerticalLine(props: Props) {
const { left, className = 'border-gray-dark', height = '221px', width = '1px' } = props;
return <div className={cn('absolute border-r border-dashed z-10', className)} style={{ left: `${left}%`, height, width }} />;
}
export default VerticalLine;

View file

@ -0,0 +1 @@
export { default } from './VerticalLine'

View file

@ -1,5 +1,6 @@
import React from 'react';
import { connectPlayer } from 'App/player';
import VerticalLine from '../VerticalLine';
interface Props {
time: number;
@ -8,7 +9,7 @@ interface Props {
function VerticalPointerLine(props: Props) {
const { time, scale } = props;
const left = time * scale;
return <div className="absolute border-r border-teal border-dashed z-10" style={{ left: `${left}%`, height: '250px', width: '1px' }} />;
return <VerticalLine left={left} className="border-teal" />;
}
export default connectPlayer((state: any) => ({

View file

@ -1,8 +1,8 @@
import React from 'react';
import { connect } from 'react-redux';
import cn from 'classnames';
// import cn from 'classnames';
import { connectPlayer, Controls } from 'Player';
import { TimelinePointer, Icon } from 'UI';
// import { TimelinePointer, Icon } from 'UI';
import TimeTracker from './TimeTracker';
import stl from './timeline.module.css';
import { TYPES } from 'Types/session/event';
@ -10,7 +10,7 @@ import { setTimelinePointer } from 'Duck/sessions';
import DraggableCircle from './DraggableCircle';
import CustomDragLayer from './CustomDragLayer';
import { debounce } from 'App/utils';
import { Tooltip } from 'react-tippy';
// import { Tooltip } from 'react-tippy';
const BOUNDRY = 0;
@ -20,46 +20,46 @@ function getTimelinePosition(value, scale) {
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';
// 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';
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';
}
// 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';
};
// return 'info';
// };
let deboucneJump = () => null;
@connectPlayer((state) => ({
@ -73,11 +73,11 @@ let deboucneJump = () => null;
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,
// logList: state.logList,
// exceptionsList: state.exceptionsList,
// resourceList: state.resourceList,
// stackList: state.stackList,
// fetchList: state.fetchList,
}))
@connect(
(state) => ({
@ -141,14 +141,14 @@ export default class Timeline extends React.PureComponent {
skipIntervals,
disabled,
endTime,
live,
logList,
exceptionsList,
resourceList,
clickRageTime,
stackList,
fetchList,
issues,
// live,
// logList,
// exceptionsList,
// resourceList,
// clickRageTime,
// stackList,
// fetchList,
// issues,
} = this.props;
const scale = 100 / endTime;
@ -175,9 +175,9 @@ export default class Timeline extends React.PureComponent {
/>
))}
<div className={stl.timeline} />
{/* {events.map((e) => (
{events.map((e) => (
<div key={e.key} className={stl.event} style={{ left: `${getTimelinePosition(e.time, scale)}%` }} />
))} */}
))}
{/* {issues.map((iss) => (
<div
style={{

View file

@ -28,7 +28,7 @@ function ErrorDetails(props: Props) {
}, []);
return (
<div className="bg-white p-5 h-screen" style={{ width: '700px' }}>
<div className="bg-white p-5 h-screen">
{!sourcemapUploaded && (
<div
style={{ backgroundColor: 'rgba(204, 0, 0, 0.1)' }}