feat(ui): allow devtools to be resizeable (#1605)
This commit is contained in:
parent
07046cc2fb
commit
0e3b1df344
10 changed files with 397 additions and 310 deletions
|
|
@ -26,6 +26,7 @@ import { MobilePlayerContext } from 'App/components/Session/playerContext';
|
|||
import { MobileStackEventPanel } from 'Shared/DevTools/StackEventPanel';
|
||||
import ReplayWindow from "Components/Session/Player/MobilePlayer/ReplayWindow";
|
||||
import PerfWarnings from "Components/Session/Player/MobilePlayer/PerfWarnings";
|
||||
import { debounceUpdate, getDefaultPanelHeight } from "Components/Session/Player/ReplayPlayer/PlayerInst";
|
||||
|
||||
interface IProps {
|
||||
fullView: boolean;
|
||||
|
|
@ -42,6 +43,8 @@ interface IProps {
|
|||
}
|
||||
|
||||
function Player(props: IProps) {
|
||||
const defaultHeight = getDefaultPanelHeight()
|
||||
const [panelHeight, setPanelHeight] = React.useState(defaultHeight);
|
||||
const {
|
||||
fullscreen,
|
||||
fullscreenOff,
|
||||
|
|
@ -77,6 +80,30 @@ function Player(props: IProps) {
|
|||
if (!playerContext.player) return null;
|
||||
|
||||
const maxWidth = activeTab ? 'calc(100vw - 270px)' : '100vw';
|
||||
|
||||
const handleResize = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
const startY = e.clientY;
|
||||
const startHeight = panelHeight;
|
||||
|
||||
const handleMouseUp = () => {
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', handleMouseUp);
|
||||
};
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
const deltaY = e.clientY - startY;
|
||||
const diff = startHeight - deltaY;
|
||||
const max = diff > window.innerHeight / 2 ? window.innerHeight / 2 : diff;
|
||||
const newHeight = Math.max(50, max);
|
||||
setPanelHeight(newHeight);
|
||||
debounceUpdate(newHeight)
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(stl.playerBody, 'flex-1 flex flex-col relative', fullscreen && 'pb-2')}
|
||||
|
|
@ -92,11 +119,23 @@ function Player(props: IProps) {
|
|||
</div>
|
||||
</div>
|
||||
{!fullscreen && !!bottomBlock && (
|
||||
<div style={{ maxWidth, width: '100%' }}>
|
||||
<div
|
||||
style={{
|
||||
height: panelHeight,
|
||||
maxWidth,
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
onMouseDown={handleResize}
|
||||
className={'w-full h-2 cursor-ns-resize absolute top-0 left-0 z-20'}
|
||||
/>
|
||||
{bottomBlock === OVERVIEW && <MobileOverviewPanel />}
|
||||
{bottomBlock === CONSOLE && <MobileConsolePanel isLive={false} />}
|
||||
{bottomBlock === CONSOLE && <MobileConsolePanel />}
|
||||
{bottomBlock === STACKEVENTS && <MobileStackEventPanel />}
|
||||
{bottomBlock === NETWORK && <MobileNetworkPanel />}
|
||||
{bottomBlock === NETWORK && <MobileNetworkPanel panelHeight={panelHeight} />}
|
||||
{bottomBlock === PERFORMANCE && <MobilePerformance />}
|
||||
{bottomBlock === EXCEPTIONS && <MobileExceptions />}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ 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 { debounce } from 'App/utils';
|
||||
|
||||
interface IProps {
|
||||
fullView: boolean;
|
||||
|
|
@ -45,7 +46,23 @@ interface IProps {
|
|||
updateLastPlayedSession: (id: string) => void;
|
||||
}
|
||||
|
||||
export const heightKey = 'playerPanelHeight'
|
||||
export const debounceUpdate = debounce((height: number) => {
|
||||
localStorage.setItem(heightKey, height.toString());
|
||||
}, 500)
|
||||
export const getDefaultPanelHeight = () => {
|
||||
const storageHeight = localStorage.getItem(heightKey)
|
||||
if (storageHeight) {
|
||||
const height = parseInt(storageHeight, 10)
|
||||
return height > window.innerHeight / 2 ? window.innerHeight / 2 : height
|
||||
} else {
|
||||
return 300
|
||||
}
|
||||
}
|
||||
|
||||
function Player(props: IProps) {
|
||||
const defaultHeight = getDefaultPanelHeight()
|
||||
const [panelHeight, setPanelHeight] = React.useState(defaultHeight);
|
||||
const { fullscreen, fullscreenOff, nextId, bottomBlock, activeTab, fullView } = props;
|
||||
const playerContext = React.useContext(PlayerContext);
|
||||
const isReady = playerContext.store.get().ready;
|
||||
|
|
@ -69,6 +86,30 @@ function Player(props: IProps) {
|
|||
if (!playerContext.player) return null;
|
||||
|
||||
const maxWidth = activeTab ? 'calc(100vw - 270px)' : '100vw';
|
||||
|
||||
const handleResize = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
const startY = e.clientY;
|
||||
const startHeight = panelHeight;
|
||||
|
||||
const handleMouseUp = () => {
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', handleMouseUp);
|
||||
};
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
const deltaY = e.clientY - startY;
|
||||
const diff = startHeight - deltaY;
|
||||
const max = diff > window.innerHeight / 2 ? window.innerHeight / 2 : diff;
|
||||
const newHeight = Math.max(50, max);
|
||||
setPanelHeight(newHeight);
|
||||
debounceUpdate(newHeight)
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(stl.playerBody, 'flex-1 flex flex-col relative', fullscreen && 'pb-2')}
|
||||
|
|
@ -80,13 +121,25 @@ function Player(props: IProps) {
|
|||
<div className={cn(stl.screenWrapper)} ref={screenWrapper} />
|
||||
</div>
|
||||
{!fullscreen && !!bottomBlock && (
|
||||
<div style={{ maxWidth, width: '100%' }}>
|
||||
<div
|
||||
style={{
|
||||
height: panelHeight,
|
||||
maxWidth,
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
onMouseDown={handleResize}
|
||||
className={'w-full h-2 cursor-ns-resize absolute top-0 left-0 z-20'}
|
||||
/>
|
||||
{bottomBlock === OVERVIEW && <OverviewPanel />}
|
||||
{bottomBlock === CONSOLE && <ConsolePanel />}
|
||||
{bottomBlock === NETWORK && <WebNetworkPanel />}
|
||||
{bottomBlock === NETWORK && <WebNetworkPanel panelHeight={panelHeight} />}
|
||||
{bottomBlock === STACKEVENTS && <WebStackEventPanel />}
|
||||
{bottomBlock === STORAGE && <Storage />}
|
||||
{bottomBlock === PROFILER && <ProfilerPanel />}
|
||||
{bottomBlock === PROFILER && <ProfilerPanel panelHeight={panelHeight} />}
|
||||
{bottomBlock === PERFORMANCE && <ConnectedPerformance />}
|
||||
{bottomBlock === GRAPHQL && <GraphQL />}
|
||||
{bottomBlock === EXCEPTIONS && <Exceptions />}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
background: $white;
|
||||
/* padding-right: 10px; */
|
||||
/* border: solid thin $gray-light; */
|
||||
height: 300px;
|
||||
|
||||
height: 100%;
|
||||
border-top: thin dashed #cccccc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
background: $white;
|
||||
/* padding-right: 10px; */
|
||||
/* border: solid thin $gray-light; */
|
||||
height: 300px;
|
||||
height: 100%;
|
||||
|
||||
border-top: thin dashed #cccccc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ function ConsolePanel({ isLive }: { isLive?: boolean }) {
|
|||
|
||||
return (
|
||||
<BottomBlock
|
||||
style={{ height: '300px' }}
|
||||
style={{ height: '100%' }}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -79,15 +79,11 @@ function MobileConsolePanel() {
|
|||
|
||||
const {
|
||||
logList,
|
||||
// exceptionsList,
|
||||
logListNow,
|
||||
exceptionsListNow,
|
||||
} = store.get();
|
||||
|
||||
const list = logList as ILog[];
|
||||
// useMemo(() => logList.concat(exceptionsList).sort((a, b) => a.time - b.time),
|
||||
// [ logList.length, exceptionsList.length ],
|
||||
// ) as ILog[]
|
||||
let filteredList = useRegExListFilterMemo(list, (l) => l.value, filter);
|
||||
filteredList = useTabListFilterMemo(filteredList, (l) => LEVEL_TAB[l.level], ALL, activeTab);
|
||||
|
||||
|
|
@ -163,7 +159,7 @@ function MobileConsolePanel() {
|
|||
|
||||
return (
|
||||
<BottomBlock
|
||||
style={{ height: '300px' }}
|
||||
style={{ height: '100%' }}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ function renderStatus({ status, cached }: { status: string; cached: boolean }) {
|
|||
);
|
||||
}
|
||||
|
||||
function NetworkPanelCont({ startedAt }: { startedAt: number }) {
|
||||
function NetworkPanelCont({ startedAt, panelHeight }: { startedAt: number; panelHeight: number }) {
|
||||
const { player, store } = React.useContext(PlayerContext);
|
||||
|
||||
const { domContentLoadedTime, loadTime, domBuildingTime, tabStates, currentTab } = store.get();
|
||||
|
|
@ -161,6 +161,7 @@ function NetworkPanelCont({ startedAt }: { startedAt: number }) {
|
|||
return (
|
||||
<NetworkPanelComp
|
||||
loadTime={loadTime}
|
||||
panelHeight={panelHeight}
|
||||
domBuildingTime={domBuildingTime}
|
||||
domContentLoadedTime={domContentLoadedTime}
|
||||
fetchList={fetchList}
|
||||
|
|
@ -173,7 +174,7 @@ function NetworkPanelCont({ startedAt }: { startedAt: number }) {
|
|||
);
|
||||
}
|
||||
|
||||
function MobileNetworkPanelCont({ startedAt }: { startedAt: number }) {
|
||||
function MobileNetworkPanelCont({ startedAt, panelHeight }: { startedAt: number, panelHeight: number }) {
|
||||
const { player, store } = React.useContext(MobilePlayerContext);
|
||||
|
||||
const domContentLoadedTime = undefined;
|
||||
|
|
@ -189,6 +190,7 @@ function MobileNetworkPanelCont({ startedAt }: { startedAt: number }) {
|
|||
return (
|
||||
<NetworkPanelComp
|
||||
isMobile
|
||||
panelHeight={panelHeight}
|
||||
loadTime={loadTime}
|
||||
domBuildingTime={domBuildingTime}
|
||||
domContentLoadedTime={domContentLoadedTime}
|
||||
|
|
@ -219,297 +221,304 @@ interface Props {
|
|||
player: WebPlayer | MobilePlayer;
|
||||
startedAt: number;
|
||||
isMobile?: boolean;
|
||||
panelHeight: number;
|
||||
}
|
||||
|
||||
const NetworkPanelComp = observer(({
|
||||
loadTime,
|
||||
domBuildingTime,
|
||||
domContentLoadedTime,
|
||||
fetchList,
|
||||
resourceList,
|
||||
fetchListNow,
|
||||
resourceListNow,
|
||||
player,
|
||||
startedAt,
|
||||
isMobile
|
||||
}: Props) => {
|
||||
const { showModal } = useModal();
|
||||
const [sortBy, setSortBy] = useState('time');
|
||||
const [sortAscending, setSortAscending] = useState(true);
|
||||
const [showOnlyErrors, setShowOnlyErrors] = useState(false);
|
||||
const NetworkPanelComp = observer(
|
||||
({
|
||||
loadTime,
|
||||
domBuildingTime,
|
||||
domContentLoadedTime,
|
||||
fetchList,
|
||||
resourceList,
|
||||
fetchListNow,
|
||||
resourceListNow,
|
||||
player,
|
||||
startedAt,
|
||||
isMobile,
|
||||
panelHeight,
|
||||
}: Props) => {
|
||||
const { showModal } = useModal();
|
||||
const [sortBy, setSortBy] = useState('time');
|
||||
const [sortAscending, setSortAscending] = useState(true);
|
||||
const [showOnlyErrors, setShowOnlyErrors] = useState(false);
|
||||
|
||||
const [isDetailsModalActive, setIsDetailsModalActive] = useState(false);
|
||||
const {
|
||||
sessionStore: { devTools },
|
||||
} = useStore();
|
||||
const filter = devTools[INDEX_KEY].filter;
|
||||
const activeTab = devTools[INDEX_KEY].activeTab;
|
||||
const activeIndex = devTools[INDEX_KEY].index;
|
||||
const [isDetailsModalActive, setIsDetailsModalActive] = useState(false);
|
||||
const {
|
||||
sessionStore: { devTools },
|
||||
} = useStore();
|
||||
const filter = devTools[INDEX_KEY].filter;
|
||||
const activeTab = devTools[INDEX_KEY].activeTab;
|
||||
const activeIndex = devTools[INDEX_KEY].index;
|
||||
|
||||
const list = useMemo(
|
||||
() =>
|
||||
// TODO: better merge (with body size info) - do it in player
|
||||
resourceList
|
||||
.filter(
|
||||
(res) =>
|
||||
!fetchList.some((ft) => {
|
||||
// res.url !== ft.url doesn't work on relative URLs appearing within fetchList (to-fix in player)
|
||||
if (res.name === ft.name) {
|
||||
if (res.time === ft.time) return true;
|
||||
if (res.url.includes(ft.url)) {
|
||||
return (
|
||||
Math.abs(res.time - ft.time) < 350 ||
|
||||
Math.abs(res.timestamp - ft.timestamp) < 350
|
||||
);
|
||||
const list = useMemo(
|
||||
() =>
|
||||
// TODO: better merge (with body size info) - do it in player
|
||||
resourceList
|
||||
.filter(
|
||||
(res) =>
|
||||
!fetchList.some((ft) => {
|
||||
// res.url !== ft.url doesn't work on relative URLs appearing within fetchList (to-fix in player)
|
||||
if (res.name === ft.name) {
|
||||
if (res.time === ft.time) return true;
|
||||
if (res.url.includes(ft.url)) {
|
||||
return (
|
||||
Math.abs(res.time - ft.time) < 350 ||
|
||||
Math.abs(res.timestamp - ft.timestamp) < 350
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res.name !== ft.name) {
|
||||
return false;
|
||||
}
|
||||
if (Math.abs(res.time - ft.time) > 250) {
|
||||
return false;
|
||||
} // TODO: find good epsilons
|
||||
if (Math.abs(res.duration - ft.duration) > 200) {
|
||||
return false;
|
||||
}
|
||||
if (res.name !== ft.name) {
|
||||
return false;
|
||||
}
|
||||
if (Math.abs(res.time - ft.time) > 250) {
|
||||
return false;
|
||||
} // TODO: find good epsilons
|
||||
if (Math.abs(res.duration - ft.duration) > 200) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
)
|
||||
.concat(fetchList)
|
||||
.sort((a, b) => a.time - b.time),
|
||||
[resourceList.length, fetchList.length]
|
||||
);
|
||||
|
||||
let filteredList = useMemo(() => {
|
||||
if (!showOnlyErrors) {
|
||||
return list;
|
||||
}
|
||||
return list.filter((it) => parseInt(it.status) >= 400 || !it.success);
|
||||
}, [showOnlyErrors, list]);
|
||||
filteredList = useRegExListFilterMemo(
|
||||
filteredList,
|
||||
(it) => [it.status, it.name, it.type],
|
||||
filter
|
||||
);
|
||||
filteredList = useTabListFilterMemo(filteredList, (it) => TYPE_TO_TAB[it.type], ALL, activeTab);
|
||||
|
||||
const onTabClick = (activeTab: (typeof TAP_KEYS)[number]) =>
|
||||
devTools.update(INDEX_KEY, { activeTab });
|
||||
const onFilterChange = ({ target: { value } }: React.ChangeEvent<HTMLInputElement>) =>
|
||||
devTools.update(INDEX_KEY, { filter: value });
|
||||
|
||||
// AutoScroll
|
||||
const [timeoutStartAutoscroll, stopAutoscroll] = useAutoscroll(
|
||||
filteredList,
|
||||
getLastItemTime(fetchListNow, resourceListNow),
|
||||
activeIndex,
|
||||
(index) => devTools.update(INDEX_KEY, { index })
|
||||
);
|
||||
const onMouseEnter = stopAutoscroll;
|
||||
const onMouseLeave = () => {
|
||||
if (isDetailsModalActive) {
|
||||
return;
|
||||
}
|
||||
timeoutStartAutoscroll();
|
||||
};
|
||||
|
||||
const resourcesSize = useMemo(
|
||||
() => resourceList.reduce((sum, { decodedBodySize }) => sum + (decodedBodySize || 0), 0),
|
||||
[resourceList.length]
|
||||
);
|
||||
const transferredSize = useMemo(
|
||||
() =>
|
||||
resourceList.reduce(
|
||||
(sum, { headerSize, encodedBodySize }) => sum + (headerSize || 0) + (encodedBodySize || 0),
|
||||
0
|
||||
),
|
||||
[resourceList.length]
|
||||
);
|
||||
|
||||
const referenceLines = useMemo(() => {
|
||||
const arr = [];
|
||||
|
||||
if (domContentLoadedTime != null) {
|
||||
arr.push({
|
||||
time: domContentLoadedTime.time,
|
||||
color: DOM_LOADED_TIME_COLOR,
|
||||
});
|
||||
}
|
||||
if (loadTime != null) {
|
||||
arr.push({
|
||||
time: loadTime.time,
|
||||
color: LOAD_TIME_COLOR,
|
||||
});
|
||||
}
|
||||
|
||||
return arr;
|
||||
}, [domContentLoadedTime, loadTime]);
|
||||
|
||||
const showDetailsModal = (item: any) => {
|
||||
setIsDetailsModalActive(true);
|
||||
showModal(
|
||||
<FetchDetailsModal
|
||||
time={item.time + startedAt}
|
||||
resource={item}
|
||||
rows={filteredList}
|
||||
fetchPresented={fetchList.length > 0}
|
||||
/>,
|
||||
{
|
||||
right: true,
|
||||
width: 500,
|
||||
onClose: () => {
|
||||
setIsDetailsModalActive(false);
|
||||
timeoutStartAutoscroll();
|
||||
},
|
||||
}
|
||||
return true;
|
||||
})
|
||||
)
|
||||
.concat(fetchList)
|
||||
.sort((a, b) => a.time - b.time),
|
||||
[resourceList.length, fetchList.length]
|
||||
);
|
||||
devTools.update(INDEX_KEY, { index: filteredList.indexOf(item) });
|
||||
stopAutoscroll();
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<BottomBlock
|
||||
style={{ height: '300px' }}
|
||||
className="border"
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<BottomBlock.Header>
|
||||
<div className="flex items-center">
|
||||
<span className="font-semibold color-gray-medium mr-4">Network</span>
|
||||
{isMobile ? null :
|
||||
<Tabs
|
||||
className="uppercase"
|
||||
tabs={TABS}
|
||||
active={activeTab}
|
||||
onClick={onTabClick}
|
||||
border={false}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<Input
|
||||
className="input-small"
|
||||
placeholder="Filter by name, type or value"
|
||||
icon="search"
|
||||
name="filter"
|
||||
onChange={onFilterChange}
|
||||
height={28}
|
||||
width={230}
|
||||
value={filter}
|
||||
/>
|
||||
</BottomBlock.Header>
|
||||
<BottomBlock.Content>
|
||||
<div className="flex items-center justify-between px-4">
|
||||
<div>
|
||||
<Toggler
|
||||
checked={showOnlyErrors}
|
||||
name="test"
|
||||
onChange={() => setShowOnlyErrors(!showOnlyErrors)}
|
||||
label="4xx-5xx Only"
|
||||
/>
|
||||
let filteredList = useMemo(() => {
|
||||
if (!showOnlyErrors) {
|
||||
return list;
|
||||
}
|
||||
return list.filter((it) => parseInt(it.status) >= 400 || !it.success);
|
||||
}, [showOnlyErrors, list]);
|
||||
filteredList = useRegExListFilterMemo(
|
||||
filteredList,
|
||||
(it) => [it.status, it.name, it.type],
|
||||
filter
|
||||
);
|
||||
filteredList = useTabListFilterMemo(filteredList, (it) => TYPE_TO_TAB[it.type], ALL, activeTab);
|
||||
|
||||
const onTabClick = (activeTab: (typeof TAP_KEYS)[number]) =>
|
||||
devTools.update(INDEX_KEY, { activeTab });
|
||||
const onFilterChange = ({ target: { value } }: React.ChangeEvent<HTMLInputElement>) =>
|
||||
devTools.update(INDEX_KEY, { filter: value });
|
||||
|
||||
// AutoScroll
|
||||
const [timeoutStartAutoscroll, stopAutoscroll] = useAutoscroll(
|
||||
filteredList,
|
||||
getLastItemTime(fetchListNow, resourceListNow),
|
||||
activeIndex,
|
||||
(index) => devTools.update(INDEX_KEY, { index })
|
||||
);
|
||||
const onMouseEnter = stopAutoscroll;
|
||||
const onMouseLeave = () => {
|
||||
if (isDetailsModalActive) {
|
||||
return;
|
||||
}
|
||||
timeoutStartAutoscroll();
|
||||
};
|
||||
|
||||
const resourcesSize = useMemo(
|
||||
() => resourceList.reduce((sum, { decodedBodySize }) => sum + (decodedBodySize || 0), 0),
|
||||
[resourceList.length]
|
||||
);
|
||||
const transferredSize = useMemo(
|
||||
() =>
|
||||
resourceList.reduce(
|
||||
(sum, { headerSize, encodedBodySize }) =>
|
||||
sum + (headerSize || 0) + (encodedBodySize || 0),
|
||||
0
|
||||
),
|
||||
[resourceList.length]
|
||||
);
|
||||
|
||||
const referenceLines = useMemo(() => {
|
||||
const arr = [];
|
||||
|
||||
if (domContentLoadedTime != null) {
|
||||
arr.push({
|
||||
time: domContentLoadedTime.time,
|
||||
color: DOM_LOADED_TIME_COLOR,
|
||||
});
|
||||
}
|
||||
if (loadTime != null) {
|
||||
arr.push({
|
||||
time: loadTime.time,
|
||||
color: LOAD_TIME_COLOR,
|
||||
});
|
||||
}
|
||||
|
||||
return arr;
|
||||
}, [domContentLoadedTime, loadTime]);
|
||||
|
||||
const showDetailsModal = (item: any) => {
|
||||
setIsDetailsModalActive(true);
|
||||
showModal(
|
||||
<FetchDetailsModal
|
||||
time={item.time + startedAt}
|
||||
resource={item}
|
||||
rows={filteredList}
|
||||
fetchPresented={fetchList.length > 0}
|
||||
/>,
|
||||
{
|
||||
right: true,
|
||||
width: 500,
|
||||
onClose: () => {
|
||||
setIsDetailsModalActive(false);
|
||||
timeoutStartAutoscroll();
|
||||
},
|
||||
}
|
||||
);
|
||||
devTools.update(INDEX_KEY, { index: filteredList.indexOf(item) });
|
||||
stopAutoscroll();
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<BottomBlock
|
||||
style={{ height: '100%' }}
|
||||
className="border"
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<BottomBlock.Header>
|
||||
<div className="flex items-center">
|
||||
<span className="font-semibold color-gray-medium mr-4">Network</span>
|
||||
{isMobile ? null : (
|
||||
<Tabs
|
||||
className="uppercase"
|
||||
tabs={TABS}
|
||||
active={activeTab}
|
||||
onClick={onTabClick}
|
||||
border={false}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<InfoLine>
|
||||
<InfoLine.Point label={filteredList.length + ''} value=" requests" />
|
||||
<InfoLine.Point
|
||||
label={formatBytes(transferredSize)}
|
||||
value="transferred"
|
||||
display={transferredSize > 0}
|
||||
/>
|
||||
<InfoLine.Point
|
||||
label={formatBytes(resourcesSize)}
|
||||
value="resources"
|
||||
display={resourcesSize > 0}
|
||||
/>
|
||||
<InfoLine.Point
|
||||
label={formatMs(domBuildingTime)}
|
||||
value="DOM Building Time"
|
||||
display={domBuildingTime != null}
|
||||
/>
|
||||
<InfoLine.Point
|
||||
label={domContentLoadedTime && formatMs(domContentLoadedTime.value)}
|
||||
value="DOMContentLoaded"
|
||||
display={domContentLoadedTime != null}
|
||||
dotColor={DOM_LOADED_TIME_COLOR}
|
||||
/>
|
||||
<InfoLine.Point
|
||||
label={loadTime && formatMs(loadTime.value)}
|
||||
value="Load"
|
||||
display={loadTime != null}
|
||||
dotColor={LOAD_TIME_COLOR}
|
||||
/>
|
||||
</InfoLine>
|
||||
</div>
|
||||
<NoContent
|
||||
title={
|
||||
<div className="capitalize flex items-center mt-16">
|
||||
<Icon name="info-circle" className="mr-2" size="18" />
|
||||
No Data
|
||||
<Input
|
||||
className="input-small"
|
||||
placeholder="Filter by name, type or value"
|
||||
icon="search"
|
||||
name="filter"
|
||||
onChange={onFilterChange}
|
||||
height={28}
|
||||
width={230}
|
||||
value={filter}
|
||||
/>
|
||||
</BottomBlock.Header>
|
||||
<BottomBlock.Content>
|
||||
<div className="flex items-center justify-between px-4">
|
||||
<div>
|
||||
<Toggler
|
||||
checked={showOnlyErrors}
|
||||
name="test"
|
||||
onChange={() => setShowOnlyErrors(!showOnlyErrors)}
|
||||
label="4xx-5xx Only"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
size="small"
|
||||
show={filteredList.length === 0}
|
||||
>
|
||||
<TimeTable
|
||||
rows={filteredList}
|
||||
referenceLines={referenceLines}
|
||||
renderPopup
|
||||
onRowClick={showDetailsModal}
|
||||
sortBy={sortBy}
|
||||
sortAscending={sortAscending}
|
||||
onJump={(row: any) => {
|
||||
devTools.update(INDEX_KEY, { index: filteredList.indexOf(row) });
|
||||
player.jump(row.time);
|
||||
}}
|
||||
activeIndex={activeIndex}
|
||||
<InfoLine>
|
||||
<InfoLine.Point label={filteredList.length + ''} value=" requests" />
|
||||
<InfoLine.Point
|
||||
label={formatBytes(transferredSize)}
|
||||
value="transferred"
|
||||
display={transferredSize > 0}
|
||||
/>
|
||||
<InfoLine.Point
|
||||
label={formatBytes(resourcesSize)}
|
||||
value="resources"
|
||||
display={resourcesSize > 0}
|
||||
/>
|
||||
<InfoLine.Point
|
||||
label={formatMs(domBuildingTime)}
|
||||
value="DOM Building Time"
|
||||
display={domBuildingTime != null}
|
||||
/>
|
||||
<InfoLine.Point
|
||||
label={domContentLoadedTime && formatMs(domContentLoadedTime.value)}
|
||||
value="DOMContentLoaded"
|
||||
display={domContentLoadedTime != null}
|
||||
dotColor={DOM_LOADED_TIME_COLOR}
|
||||
/>
|
||||
<InfoLine.Point
|
||||
label={loadTime && formatMs(loadTime.value)}
|
||||
value="Load"
|
||||
display={loadTime != null}
|
||||
dotColor={LOAD_TIME_COLOR}
|
||||
/>
|
||||
</InfoLine>
|
||||
</div>
|
||||
<NoContent
|
||||
title={
|
||||
<div className="capitalize flex items-center mt-16">
|
||||
<Icon name="info-circle" className="mr-2" size="18" />
|
||||
No Data
|
||||
</div>
|
||||
}
|
||||
size="small"
|
||||
show={filteredList.length === 0}
|
||||
>
|
||||
{[
|
||||
// {
|
||||
// label: 'Start',
|
||||
// width: 120,
|
||||
// render: renderStart,
|
||||
// },
|
||||
{
|
||||
label: 'Status',
|
||||
dataKey: 'status',
|
||||
width: 90,
|
||||
render: renderStatus,
|
||||
},
|
||||
{
|
||||
label: 'Type',
|
||||
dataKey: 'type',
|
||||
width: 90,
|
||||
render: renderType,
|
||||
},
|
||||
{
|
||||
label: 'Name',
|
||||
width: 240,
|
||||
dataKey: 'name',
|
||||
render: renderName,
|
||||
},
|
||||
{
|
||||
label: 'Size',
|
||||
width: 80,
|
||||
dataKey: 'decodedBodySize',
|
||||
render: renderSize,
|
||||
hidden: activeTab === XHR,
|
||||
},
|
||||
{
|
||||
label: 'Duration',
|
||||
width: 80,
|
||||
dataKey: 'duration',
|
||||
render: renderDuration,
|
||||
},
|
||||
]}
|
||||
</TimeTable>
|
||||
</NoContent>
|
||||
</BottomBlock.Content>
|
||||
</BottomBlock>
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
{/*@ts-ignore*/}
|
||||
<TimeTable
|
||||
rows={filteredList}
|
||||
tableHeight={panelHeight - 102}
|
||||
referenceLines={referenceLines}
|
||||
renderPopup
|
||||
onRowClick={showDetailsModal}
|
||||
sortBy={sortBy}
|
||||
sortAscending={sortAscending}
|
||||
onJump={(row: any) => {
|
||||
devTools.update(INDEX_KEY, { index: filteredList.indexOf(row) });
|
||||
player.jump(row.time);
|
||||
}}
|
||||
activeIndex={activeIndex}
|
||||
>
|
||||
{[
|
||||
// {
|
||||
// label: 'Start',
|
||||
// width: 120,
|
||||
// render: renderStart,
|
||||
// },
|
||||
{
|
||||
label: 'Status',
|
||||
dataKey: 'status',
|
||||
width: 90,
|
||||
render: renderStatus,
|
||||
},
|
||||
{
|
||||
label: 'Type',
|
||||
dataKey: 'type',
|
||||
width: 90,
|
||||
render: renderType,
|
||||
},
|
||||
{
|
||||
label: 'Name',
|
||||
width: 240,
|
||||
dataKey: 'name',
|
||||
render: renderName,
|
||||
},
|
||||
{
|
||||
label: 'Size',
|
||||
width: 80,
|
||||
dataKey: 'decodedBodySize',
|
||||
render: renderSize,
|
||||
hidden: activeTab === XHR,
|
||||
},
|
||||
{
|
||||
label: 'Duration',
|
||||
width: 80,
|
||||
dataKey: 'duration',
|
||||
render: renderDuration,
|
||||
},
|
||||
]}
|
||||
</TimeTable>
|
||||
</NoContent>
|
||||
</BottomBlock.Content>
|
||||
</BottomBlock>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const WebNetworkPanel = connect((state: any) => ({
|
||||
startedAt: state.getIn(['sessions', 'current']).startedAt,
|
||||
|
|
@ -519,7 +528,4 @@ const MobileNetworkPanel = connect((state: any) => ({
|
|||
startedAt: state.getIn(['sessions', 'current']).startedAt,
|
||||
}))(observer(MobileNetworkPanelCont));
|
||||
|
||||
export {
|
||||
WebNetworkPanel,
|
||||
MobileNetworkPanel
|
||||
}
|
||||
export { WebNetworkPanel, MobileNetworkPanel };
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import { useRegExListFilterMemo } from '../useListFilter'
|
|||
const renderDuration = (p: any) => `${p.duration}ms`;
|
||||
const renderName = (p: any) => <TextEllipsis text={p.name} />;
|
||||
|
||||
function ProfilerPanel() {
|
||||
function ProfilerPanel({ panelHeight }: { panelHeight: number }) {
|
||||
const { store } = React.useContext(PlayerContext)
|
||||
const { tabStates, currentTab } = store.get()
|
||||
const profiles = tabStates[currentTab].profilesList || [] as any[] // TODO lest internal types
|
||||
|
|
@ -26,7 +26,7 @@ function ProfilerPanel() {
|
|||
showModal(<ProfilerModal profile={profile} />, { right: true, width: 500 });
|
||||
};
|
||||
return (
|
||||
<BottomBlock>
|
||||
<BottomBlock style={{ height: '100%' }}>
|
||||
<BottomBlock.Header>
|
||||
<div className="flex items-center">
|
||||
<span className="font-semibold color-gray-medium mr-4">Profiler</span>
|
||||
|
|
@ -41,7 +41,7 @@ function ProfilerPanel() {
|
|||
/>
|
||||
</BottomBlock.Header>
|
||||
<BottomBlock.Content>
|
||||
<TimeTable rows={filtered} onRowClick={onRowClick} hoverable>
|
||||
<TimeTable tableHeight={panelHeight - 40} rows={filtered} onRowClick={onRowClick} hoverable>
|
||||
{[
|
||||
{
|
||||
label: 'Name',
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ function EventsPanel({
|
|||
|
||||
return (
|
||||
<BottomBlock
|
||||
style={{ height: '300px' }}
|
||||
style={{ height: '100%' }}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -143,12 +143,6 @@ export default class TimeTable extends React.PureComponent<Props, State> {
|
|||
scroller = React.createRef<List>();
|
||||
autoScroll = true;
|
||||
|
||||
// componentDidMount() {
|
||||
// if (this.scroller.current) {
|
||||
// this.scroller.current.scrollToRow(this.props.activeIndex);
|
||||
// }
|
||||
// }
|
||||
|
||||
adjustScroll(prevActiveIndex: number) {
|
||||
if (
|
||||
this.props.activeIndex &&
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue