refactor(ui/player): remove more connectplayer, swap some player instance calls with context

This commit is contained in:
sylenien 2022-11-23 16:14:44 +01:00
parent 62d6262857
commit e4af3bd6a3
20 changed files with 165 additions and 228 deletions

View file

@ -6,7 +6,7 @@ import stl from './chatWindow.module.css';
import ChatControls from '../ChatControls/ChatControls';
import Draggable from 'react-draggable';
import type { LocalStream } from 'Player';
import { toggleVideoLocalStream } from 'Player'
import { PlayerContext } from 'App/components/Session/playerContext';
export interface Props {
incomeStream: MediaStream[] | null;
@ -17,6 +17,10 @@ export interface Props {
}
function ChatWindow({ userId, incomeStream, localStream, endCall, isPrestart }: Props) {
const { player } = React.useContext(PlayerContext)
const toggleVideoLocalStream = player.assistManager.toggleVideoLocalStream;
const [localVideoEnabled, setLocalVideoEnabled] = useState(false);
const [anyRemoteEnabled, setRemoteEnabled] = useState(false);

View file

@ -1,9 +1,13 @@
import React, { useEffect } from 'react'
import { Input, Icon } from 'UI'
import { connectPlayer, toggleEvents, scale } from 'Player';
import { PlayerContext } from 'App/components/Session/playerContext';
function EventSearch(props) {
const { onChange, clearSearch, value, header, toggleEvents, setActiveTab } = props;
const { player } = React.useContext(PlayerContext)
const { onChange, clearSearch, value, header, setActiveTab } = props;
const toggleEvents = () => player.toggleEvents()
useEffect(() => {
return () => {
@ -42,4 +46,4 @@ function EventSearch(props) {
)
}
export default connectPlayer(() => ({}), { toggleEvents })(EventSearch)
export default EventSearch

View file

@ -1,27 +1,27 @@
import React, { useEffect, useState, useRef } from 'react';
import { toggleInspectorMode, markElement } from 'Player';
import ElementView from './ElementView';
import BottomBlock from '../BottomBlock';
import stl from './inspector.module.css'
import stl from './inspector.module.css';
import { PlayerContext } from 'App/components/Session/playerContext';
// TODO: refactor: use Layout from the Sessions and put everything there under the WebPlayer folder
// function onMount(element, setOpen) { // TODO: through the MobX
// element.setOpen = setOpen;
// }
export default function Inspector() {
const { player } = React.useContext(PlayerContext);
const toggleInspectorMode = player.toggleInspectorMode;
const markElement = player.mark;
export default function Inspector () {
const [doc, setDoc] = useState(null);
const [openChain, setOpenChain] = useState([]);
const [selectedElement, _setSelectedElement] = useState(null);
const selectedElementRef = useRef(selectedElement);
const setSelectedElement = elem => {
const setSelectedElement = (elem) => {
selectedElementRef.current = elem;
_setSelectedElement(elem);
}
};
useEffect(() => {
useEffect(() => {
const doc = toggleInspectorMode(true, ({ target }) => {
const openChain = [];
let currentTarget = target;
@ -33,9 +33,9 @@ export default function Inspector () {
setSelectedElement(target);
});
setDoc(doc);
setOpenChain([ doc.documentElement ]);
setOpenChain([doc.documentElement]);
const onKeyPress = e => {
const onKeyPress = (e) => {
if (e.key === 'Backspace' || e.key === 'Delete') {
const elem = selectedElementRef.current;
if (elem !== null && elem.parentElement !== null) {
@ -43,30 +43,30 @@ export default function Inspector () {
setSelectedElement(null);
}
}
}
window.addEventListener("keydown", onKeyPress);
};
window.addEventListener('keydown', onKeyPress);
return () => {
toggleInspectorMode(false);
window.removeEventListener("keydown", onKeyPress);
}
window.removeEventListener('keydown', onKeyPress);
};
}, []);
if (!doc) return null;
return (
<BottomBlock>
if (!doc) return null;
return (
<BottomBlock>
<BottomBlock.Content>
<div onMouseLeave={ () => markElement(null) } className={stl.wrapper}>
<ElementView
element={ doc.documentElement }
<div onMouseLeave={() => markElement(null)} className={stl.wrapper}>
<ElementView
element={doc.documentElement}
level={0}
context={doc.defaultView}
openChain={ openChain }
selectedElement={ selectedElement }
setSelectedElement={ setSelectedElement }
onHover={ markElement }
openChain={openChain}
selectedElement={selectedElement}
setSelectedElement={setSelectedElement}
onHover={(e) => markElement(e)}
/>
</div>
</BottomBlock.Content>
</BottomBlock>
);
);
}

View file

@ -1,7 +1,7 @@
import React from 'react';
import cn from 'classnames';
import { connectPlayer, jump, pause } from 'Player';
import { Tooltip, Button, TextEllipsis } from 'UI';
import { connectPlayer, } from 'Player';
import { Tooltip, TextEllipsis } from 'UI';
import { getRE } from 'App/utils';
import { TYPES } from 'Types/session/resource';
import stl from './network.module.css';

View file

@ -1,6 +1,5 @@
import React from 'react';
import cn from 'classnames';
// import { connectPlayer } from 'Player';
import { QuestionMarkHint, Tooltip, Tabs, Input, NoContent, Icon, Toggler, Button } from 'UI';
import { getRE } from 'App/utils';
import { TYPES } from 'Types/session/resource';
@ -12,7 +11,6 @@ import BottomBlock from '../BottomBlock';
import InfoLine from '../BottomBlock/InfoLine';
import stl from './network.module.css';
import { Duration } from 'luxon';
import { jump } from 'Player';
const ALL = 'ALL';
const XHR = 'xhr';
@ -112,8 +110,6 @@ function renderSize(r) {
content = 'Not captured';
} else {
const headerSize = r.headerSize || 0;
const encodedSize = r.encodedBodySize || 0;
const transferred = headerSize + encodedSize;
const showTransferred = r.headerSize != null;
triggerText = formatBytes(r.decodedBodySize);

View file

@ -1,6 +1,5 @@
import { connectPlayer } from 'Player';
import { toggleBottomBlock } from 'Duck/components/player';
import React, { useEffect } from 'react';
import { toggleBottomBlock } from 'Duck/components/player';
import BottomBlock from '../BottomBlock';
import EventRow from './components/EventRow';
import { TYPES } from 'Types/session/event';
@ -10,38 +9,38 @@ import FeatureSelection, { HELP_MESSAGE } from './components/FeatureSelection/Fe
import TimelinePointer from './components/TimelinePointer';
import VerticalPointerLine from './components/VerticalPointerLine';
import cn from 'classnames';
// import VerticalLine from './components/VerticalLine';
import OverviewPanelContainer from './components/OverviewPanelContainer';
import { NoContent, Icon } from 'UI';
import { observer } from 'mobx-react-lite';
import { PlayerContext } from 'App/components/Session/playerContext';
function OverviewPanel({ issuesList }: { issuesList: any[] }) {
const { store } = React.useContext(PlayerContext)
interface Props {
resourceList: any[];
exceptionsList: any[];
eventsList: any[];
toggleBottomBlock: any;
stackEventList: any[];
issuesList: any[];
performanceChartData: any;
endTime: number;
}
function OverviewPanel(props: Props) {
const [dataLoaded, setDataLoaded] = React.useState(false);
const [selectedFeatures, setSelectedFeatures] = React.useState([
'PERFORMANCE',
'ERRORS',
// 'EVENTS',
'NETWORK',
]);
const resources: any = React.useMemo(() => {
const {
resourceList,
exceptionsList,
eventsList,
stackEventList,
issuesList,
endTime,
performanceChartData,
} = props;
stackList: stackEventList,
eventList: eventsList,
exceptionsList,
resourceList: resourceListUnmap,
fetchList,
graphqlList,
} = store.get()
const resourceList = resourceListUnmap
.filter((r: any) => r.isRed() || r.isYellow())
.concat(fetchList.filter((i: any) => parseInt(i.status) >= 400))
.concat(graphqlList.filter((i: any) => parseInt(i.status) >= 400)),
const resources: any = React.useMemo(() => {
return {
NETWORK: resourceList,
ERRORS: exceptionsList,
@ -57,25 +56,24 @@ function OverviewPanel(props: Props) {
}
if (
props.resourceList.length > 0 ||
props.exceptionsList.length > 0 ||
props.eventsList.length > 0 ||
props.stackEventList.length > 0 ||
props.issuesList.length > 0 ||
props.performanceChartData.length > 0
resourceList.length > 0 ||
exceptionsList.length > 0 ||
eventsList.length > 0 ||
stackEventList.length > 0 ||
issuesList.length > 0 ||
performanceChartData.length > 0
) {
setDataLoaded(true);
}
}, [
props.resourceList,
props.exceptionsList,
props.eventsList,
props.stackEventList,
props.performanceChartData,
resourceList,
exceptionsList,
eventsList,
stackEventList,
performanceChartData,
]);
return (
<Wrapper {...props}>
<BottomBlock style={{ height: '245px' }}>
<BottomBlock.Header>
<span className="font-semibold color-gray-medium mr-4">X-RAY</span>
@ -84,8 +82,8 @@ function OverviewPanel(props: Props) {
</div>
</BottomBlock.Header>
<BottomBlock.Content>
<OverviewPanelContainer endTime={props.endTime}>
<TimelineScale endTime={props.endTime} />
<OverviewPanelContainer endTime={endTime}>
<TimelineScale endTime={endTime} />
<div style={{ width: '100%', height: '187px', overflow: 'hidden' }} className="transition relative">
<NoContent
show={selectedFeatures.length === 0}
@ -109,7 +107,7 @@ function OverviewPanel(props: Props) {
renderElement={(pointer: any) => (
<TimelinePointer pointer={pointer} type={feature} />
)}
endTime={props.endTime}
endTime={endTime}
message={HELP_MESSAGE[feature]}
/>
</div>
@ -119,7 +117,6 @@ function OverviewPanel(props: Props) {
</OverviewPanelContainer>
</BottomBlock.Content>
</BottomBlock>
</Wrapper>
);
}
@ -131,19 +128,5 @@ export default connect(
toggleBottomBlock,
}
)(
connectPlayer((state: any) => ({
resourceList: state.resourceList
.filter((r: any) => r.isRed() || r.isYellow())
.concat(state.fetchList.filter((i: any) => parseInt(i.status) >= 400))
.concat(state.graphqlList.filter((i: any) => parseInt(i.status) >= 400)),
exceptionsList: state.exceptionsList,
eventsList: state.eventList,
stackEventList: state.stackList,
performanceChartData: state.performanceChartData,
endTime: state.endTime,
}))(OverviewPanel)
observer(OverviewPanel)
);
const Wrapper = React.memo((props: any) => {
return <>{props.children}</>;
});

View file

@ -1,48 +1,33 @@
import React from 'react';
import VerticalLine from '../VerticalLine';
import { connectPlayer, Controls } from 'Player';
import { PlayerContext } from 'App/components/Session/playerContext';
interface Props {
children: React.ReactNode;
endTime: number;
children: React.ReactNode;
endTime: number;
}
const OverviewPanelContainer = React.memo((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);
if (time) {
Controls.jump(time);
}
};
const { player } = React.useContext(PlayerContext)
// const onMouseMoveCapture = (e: any) => {
// if (!mouseIn) {
// return;
// }
// const p = e.nativeEvent.offsetX / e.target.offsetWidth;
// setMouseX(p * 100);
// };
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);
if (time) {
player.jump(time);
}
};
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>
);
return (
<div className="overflow-x-auto overflow-y-hidden bg-gray-lightest" onClick={onClickTrack}>
{mouseIn && <VerticalLine left={mouseX} className="border-gray-medium" />}
<div className="">{props.children}</div>
</div>
);
});
export default OverviewPanelContainer;
// export default connectPlayer((state: any) => ({
// endTime: state.endTime,
// }))(OverviewPanelContainer);

View file

@ -1,6 +1,5 @@
import React from 'react';
import { connectPlayer } from 'Player';
import { AreaChart, Area, Tooltip, ResponsiveContainer } from 'recharts';
import { AreaChart, Area, ResponsiveContainer } from 'recharts';
interface Props {
list: any;

View file

@ -1,5 +1,4 @@
import React from 'react';
import { Controls } from 'Player';
import { NETWORK, EXCEPTIONS } from 'Duck/components/player';
import { useModal } from 'App/components/Modal';
import { Icon, Tooltip } from 'UI';
@ -7,6 +6,7 @@ import StackEventModal from '../StackEventModal';
import ErrorDetailsModal from 'App/components/Dashboard/components/Errors/ErrorDetailsModal';
import FetchDetails from 'Shared/FetchDetailsModal';
import GraphQLDetailsModal from 'Shared/GraphQLDetailsModal';
import { PlayerContext } from 'App/components/Session/playerContext';
interface Props {
pointer: any;
@ -14,11 +14,13 @@ interface Props {
noClick?: boolean;
}
const TimelinePointer = React.memo((props: Props) => {
const { player } = React.useContext(PlayerContext)
const { showModal } = useModal();
const createEventClickHandler = (pointer: any, type: any) => (e: any) => {
if (props.noClick) return;
e.stopPropagation();
Controls.jump(pointer.time);
player.jump(pointer.time);
if (!type) {
return;
}

View file

@ -1,5 +1,4 @@
import React from 'react';
import { connectPlayer } from 'Player';
import { millisToMinutesAndSeconds } from 'App/utils';
interface Props {
@ -17,9 +16,6 @@ function TimelineScale(props: Props) {
for (var i = 0; i < part; i++) {
const txt = millisToMinutesAndSeconds(i * (endTime / part));
const el = document.createElement('div');
// el.style.height = '10px';
// el.style.width = '1px';
// el.style.backgroundColor = '#ccc';
el.style.position = 'absolute';
el.style.left = `${i * gap}px`;
el.style.paddingTop = '1px';
@ -38,23 +34,11 @@ function TimelineScale(props: Props) {
}
drawScale(scaleRef.current);
// const resize = () => drawScale(scaleRef.current);
// window.addEventListener('resize', resize);
// return () => {
// window.removeEventListener('resize', resize);
// };
}, [scaleRef]);
return (
<div className="h-6 bg-gray-darkest w-full" ref={scaleRef}>
{/* <div ref={scaleRef} className="w-full h-10 bg-gray-300 relative"></div> */}
</div>
);
}
export default TimelineScale;
// export default connectPlayer((state: any) => ({
// endTime: state.endTime,
// }))(TimelineScale);

View file

@ -1,18 +1,16 @@
import React from 'react';
import { connectPlayer } from 'Player';
import { PlayerContext } from 'App/components/Session/playerContext';
import { observer } from 'mobx-react-lite';
import VerticalLine from '../VerticalLine';
interface Props {
time: number;
scale: number;
}
function VerticalPointerLine(props: Props) {
const { time, scale } = props;
function VerticalPointerLine() {
const { store } = React.useContext(PlayerContext)
const { time, endTime } = store.get();
const scale = 100 / endTime;
const left = time * scale;
return <VerticalLine left={left} className="border-teal" />;
}
export default connectPlayer((state: any) => ({
time: state.time,
scale: 100 / state.endTime,
}))(VerticalPointerLine);
export default observer(VerticalPointerLine);

View file

@ -3,7 +3,8 @@ import { Loader, Icon } from 'UI';
import { connect } from 'react-redux';
import { fetchInsights } from 'Duck/sessions';
import SelectorsList from './components/SelectorsList/SelectorsList';
import { markTargets, Controls as Player } from 'Player';
import { PlayerContext } from 'App/components/Session/playerContext';
import Select from 'Shared/Select';
import SelectDateRange from 'Shared/SelectDateRange';
import Period from 'Types/app/period';
@ -22,6 +23,9 @@ interface Props {
}
function PageInsightsPanel({ filters, fetchInsights, events = [], insights, urlOptions, host, loading = true, setActiveTab }: Props) {
const { player: Player } = React.useContext(PlayerContext)
const markTargets = (t: any) => Player.markTargets(t)
const [insightsFilters, setInsightsFilters] = useState(filters);
const defaultValue = urlOptions && urlOptions[0] ? urlOptions[0].value : '';

View file

@ -1,16 +1,15 @@
import React from 'react';
import { NoContent } from 'UI';
import { connectPlayer } from 'Player';
import { PlayerContext } from 'App/components/Session/playerContext';
import { observer } from 'mobx-react-lite';
import SelectorCard from '../SelectorCard/SelectorCard';
import type { MarkedTarget } from 'Player';
import stl from './selectorList.module.css';
interface Props {
targets: Array<MarkedTarget>;
activeTargetIndex: number;
}
function SelectorsList() {
const { store } = React.useContext(PlayerContext)
const { markedTargets: targets, activeTargetIndex } = store.get()
function SelectorsList({ targets, activeTargetIndex }: Props) {
return (
<NoContent title="No data available." size="small" show={targets && targets.length === 0}>
<div className={stl.wrapper}>
@ -20,7 +19,4 @@ function SelectorsList({ targets, activeTargetIndex }: Props) {
);
}
export default connectPlayer((state: any) => ({
targets: state.markedTargets,
activeTargetIndex: state.activeTargetIndex,
}))(SelectorsList);
export default observer(SelectorsList);

View file

@ -6,12 +6,12 @@ import {
STORAGE_TYPES,
selectStorageType,
selectStorageListNow,
jumpToLive,
toggleInspectorMode,
} from 'Player';
import LiveTag from 'Shared/LiveTag';
import { jumpToLive } from 'Player';
import { Icon, Tooltip } from 'UI';
import { toggleInspectorMode } from 'Player';
import {
fullscreenOn,
fullscreenOff,

View file

@ -1,19 +1,22 @@
import React from 'react';
import { connectPlayer } from 'Player';
import { PlayerContext } from 'App/components/Session/playerContext';
import { observer } from 'mobx-react-lite';
import styles from './timeTracker.module.css';
import cn from 'classnames'
const TimeTracker = ({ time, scale, live, left }) => (
const TimeTracker = ({ scale, live, left }) => {
const { store } = React.useContext(PlayerContext)
const time = store.get().time
return (
<React.Fragment>
<span
className={ cn(styles.playedTimeline, live && left > 99 ? styles.liveTime : null) }
style={ { width: `${ time * scale }%` } }
/>
</React.Fragment>
);
);}
TimeTracker.displayName = 'TimeTracker';
export default connectPlayer(state => ({
time: state.time,
}))(TimeTracker);
export default observer(TimeTracker);

View file

@ -1,6 +1,5 @@
import React from 'react';
import { getStatusText } from 'Player';
import { CallingState, ConnectionStatus, RemoteControlStatus } from 'Player';
import { CallingState, ConnectionStatus, RemoteControlStatus, getStatusText } from 'Player';
import AutoplayTimer from './Overlay/AutoplayTimer';
import PlayIconLayer from './Overlay/PlayIconLayer';

View file

@ -1,13 +1,15 @@
import React from 'react';
import { connect } from 'react-redux';
import { hideHint } from 'Duck/components/player';
import {
connectPlayer,
selectStorageType,
STORAGE_TYPES,
selectStorageListNow,
selectStorageList,
} from 'Player';
// import {
// connectPlayer,
// selectStorageType,
// STORAGE_TYPES,
// selectStorageListNow,
// selectStorageList,
// } from 'Player';
import { PlayerContext } from 'App/components/Session/playerContext';
import { observer } from 'mobx-react-lite';
import { JSONTree, NoContent, Tooltip } from 'UI';
import { formatMs } from 'App/date';
import { diff } from 'deep-diff';
@ -32,11 +34,11 @@ function getActionsName(type) {
}
}
@connectPlayer((state) => ({
type: selectStorageType(state),
list: selectStorageList(state),
listNow: selectStorageListNow(state),
}))
// @connectPlayer((state) => ({
// type: selectStorageType(state),
// list: selectStorageList(state),
// listNow: selectStorageListNow(state),
// }))
@connect(
(state) => ({
hintIsHidden: state.getIn(['components', 'player', 'hiddenHints', 'storage']),

View file

@ -66,6 +66,7 @@ function ConsolePanel() {
errorId,
})
);
// @ts-ignore
const logs = logList.concat(logExceptions)
const additionalHeight = 0;

View file

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import { Controls as Player } from 'Player';
import { Tooltip } from 'UI';
import { INDEXES } from 'App/constants/zindex';
import { PlayerContext } from 'App/components/Session/playerContext';
export const FEATURE_KEYS = {
XRAY: 'featureViewed',
@ -16,6 +16,8 @@ interface IProps {
}
export default function GuidePopup({ children, title, description }: IProps) {
const { player: Player } = React.useContext(PlayerContext)
const [showGuide, setShowGuide] = useState(!localStorage.getItem(FEATURE_KEYS.NOTES));
useEffect(() => {
if (!showGuide) {

View file

@ -2,15 +2,16 @@ import React, { useEffect, useState } from 'react';
import stl from './xrayButton.module.css';
import cn from 'classnames';
import { Tooltip } from 'UI';
import GuidePopup, { FEATURE_KEYS } from 'Shared/GuidePopup';
import { Controls as Player } from 'Player';
import { INDEXES } from 'App/constants/zindex';
import { FEATURE_KEYS } from 'Shared/GuidePopup';
import { PlayerContext } from 'App/components/Session/playerContext';
interface Props {
onClick?: () => void;
isActive?: boolean;
}
function XRayButton(props: Props) {
const { player: Player } = React.useContext(PlayerContext);
const { isActive } = props;
const [showGuide, setShowGuide] = useState(!localStorage.getItem(FEATURE_KEYS.XRAY));
useEffect(() => {
@ -38,40 +39,14 @@ function XRayButton(props: Props) {
></div>
)}
<div className="relative">
{showGuide ? (
// <GuidePopup
// title={<div className="color-gray-dark">Introducing <span className={stl.text}>X-Ray</span></div>}
// description={"Get a quick overview on the issues in this session."}
// >
<button
className={cn(stl.wrapper, { [stl.default]: !isActive, [stl.active]: isActive })}
onClick={onClick}
style={{ zIndex: INDEXES.POPUP_GUIDE_BTN, position: 'relative' }}
>
<span className="z-1">X-RAY</span>
</button>
// <div
// className="absolute bg-white top-0 left-0 z-0"
// style={{
// zIndex: INDEXES.POPUP_GUIDE_BG,
// width: '100px',
// height: '50px',
// borderRadius: '30px',
// margin: '-10px -16px',
// }}
// ></div>
// </GuidePopup>
) : (
<Tooltip title="Get a quick overview on the issues in this session." disabled={isActive}>
<button
className={cn(stl.wrapper, { [stl.default]: !isActive, [stl.active]: isActive })}
onClick={onClick}
>
<span className="z-1">X-RAY</span>
</button>
</Tooltip>
)}
<Tooltip title="Get a quick overview on the issues in this session." disabled={isActive}>
<button
className={cn(stl.wrapper, { [stl.default]: !isActive, [stl.active]: isActive })}
onClick={onClick}
>
<span className="z-1">X-RAY</span>
</button>
</Tooltip>
</div>
</>
);