Skip to content

Commit

Permalink
wip(dashboard): actually fixed resizing issues + debouncing
Browse files Browse the repository at this point in the history
  • Loading branch information
tabarra committed Jun 3, 2024
1 parent 8bd8f98 commit 3cfb413
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const serverInitiatedExamples = [
`Server shutting down: %s`,
`[txAdmin] Server restarting (scheduled restart at 03:00).`, //not so sure about this
];
const networkingExamples = [
const timeoutExamples = [
`Server->client connection timed out. Pending commands: %d.\nCommand list:\n%s`,
`Server->client connection timed out. Last seen %d msec ago.`,
`Fetching info timed out.`,
Expand Down Expand Up @@ -64,9 +64,9 @@ suite('classifyDropReason', () => {
expect(fnc(reason).category).toBe('server-initiated');
}
});
it('should classify networking reasons', () => {
for (const reason of networkingExamples) {
expect(fnc(reason).category).toBe('networking');
it('should classify timeout reasons', () => {
for (const reason of timeoutExamples) {
expect(fnc(reason).category).toBe('timeout');
}
});
it('should classify security reasons', () => {
Expand Down
6 changes: 3 additions & 3 deletions core/components/StatsManager/playerDrop/classifyDropReason.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const serverInitiatedRules = [
`server shutting down:`,
`[txadmin]`,
];
const networkingRules = [
const timeoutRules = [
`server->client connection timed out`, //basically only see this one
`connection timed out`,
`fetching info timed out`,
Expand Down Expand Up @@ -120,8 +120,8 @@ export const classifyDropReason = (reason: string) => {
return { category: 'user-initiated' };
} else if (serverInitiatedRules.some((rule) => reasonToMatch.startsWith(rule))) {
return { category: 'server-initiated' };
} else if (networkingRules.some((rule) => reasonToMatch.includes(rule))) {
return { category: 'networking' };
} else if (timeoutRules.some((rule) => reasonToMatch.includes(rule))) {
return { category: 'timeout' };
} else if (securityRules.some((rule) => reasonToMatch.includes(rule))) {
return { category: 'security' };
} else if (crashRulesIntl.some((rule) => reasonToMatch.includes(rule))) {
Expand Down
10 changes: 0 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion panel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
"react-hot-toast": "^2.4.1",
"react-icons": "^5.1.0",
"react-markdown": "^9.0.1",
"react-virtualized-auto-sizer": "^1.0.24",
"socket.io-client": "^4.7.5",
"swr": "^2.2.5",
"tailwind-merge": "^2.2.2",
Expand Down
92 changes: 92 additions & 0 deletions panel/src/components/DebouncedResizeContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { debounce } from 'throttle-debounce';
import { useRef, useEffect, useCallback, memo } from 'react';
import { Loader2Icon } from 'lucide-react';

type SizeType = {
width: number;
height: number;
};

type DebouncedResizeContainerProps = {
delay?: number;
onDebouncedResize: ({ width, height }: SizeType) => void;
children: React.ReactNode;
};

/**
* A container that will call onDebouncedResize with the width and height of the container after a resize event.
*/
function DebouncedResizeContainerInner({
delay,
onDebouncedResize,
children,
}: DebouncedResizeContainerProps) {
const containerRef = useRef<HTMLDivElement>(null);
const loaderRef = useRef<HTMLDivElement>(null);
const childRef = useRef<HTMLDivElement>(null);
const lastMeasure = useRef<SizeType>({ width: 0, height: 0 });
if (delay === undefined) delay = 250;

const updateSizeState = () => {
if (!containerRef.current || !containerRef.current.parentNode) return;
const measures = {
width: containerRef.current.clientWidth,
height: containerRef.current.clientHeight
}
lastMeasure.current = measures;
onDebouncedResize(measures);
childRef.current!.style.visibility = 'visible';
loaderRef.current!.style.visibility = 'hidden';
}

const debouncedResizer = useCallback(
debounce(delay, updateSizeState, { atBegin: false }),
[containerRef]
);

useEffect(() => {
if (!containerRef.current) return;
const resizeObserver = new ResizeObserver(() => {
const currHeight = containerRef.current!.clientHeight;
const currWidth = containerRef.current!.clientWidth;
if (currHeight === 0 || currWidth === 0) return;
if (lastMeasure.current.width === currWidth && lastMeasure.current.height === currHeight) return;
if (lastMeasure.current.width === 0 || lastMeasure.current.height === 0) {
updateSizeState();
} else {
debouncedResizer();
childRef.current!.style.visibility = 'hidden';
loaderRef.current!.style.visibility = 'visible';
}
});
resizeObserver.observe(containerRef.current);
updateSizeState();
return () => resizeObserver.disconnect();
}, [containerRef]);

return (
<div
ref={containerRef}
style={{
height: '100%',
width: '100%',
position: 'relative'
}}
>
<div
ref={loaderRef}
className="absolute inset-0 flex items-center justify-center"
>
<Loader2Icon className="animate-spin size-16 text-muted-foreground" />
</div>
<div
className="absolute inset-0"
ref={childRef}
>
{children}
</div>
</div>
);
}

export default memo(DebouncedResizeContainerInner);
17 changes: 8 additions & 9 deletions panel/src/pages/Dashboard/DashboardPage.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useEffect, useMemo, useState } from 'react';
import { GaugeIcon } from 'lucide-react';
import { Button } from '@/components/ui/button';
import PlayerDropCard from './PlayerDropCard';
import ThreadPerfCard from './ThreadPerfCard';
import PlayerDropCard from './PlayerDropCard';
import * as d3ScaleChromatic from 'd3-scale-chromatic';
import { getMinTickIntervalMarker } from './chartingUtils';
import FullPerfCard from './FullPerfCard';
Expand All @@ -22,7 +22,7 @@ export type PlayerDropChartDatum = {
}

export default function DashboardPage() {
const [isRunning, setIsRunning] = useState(true);
const [isRunning, setIsRunning] = useState(false);
const [rndCounter, setRndCounter] = useState(491);
const [ztoCounter, setZtoCounter] = useState(0);

Expand All @@ -48,7 +48,7 @@ export default function DashboardPage() {
data.push({
bucket: boundaries[i],
count: Math.round(Math.random() * 1000),
value: Math.max(0, (Math.sin((indexPct + ztoCounter) * 2 * Math.PI) -1 ) + 1), //rnd
value: Math.max(0, (Math.sin((indexPct + ztoCounter) * 2 * Math.PI) - 1) + 1), //rnd
// value: Math.max(0, Math.sin(i * 0.24 + tmpMultiplier)) / 2.8, //rnd
// value: Math.max(0, Math.sin(i * 0.295 + 0.7)) / 2.8, //good
// value: Math.max(0, Math.sin(i * 0.295 + -0.6)) / 2.8, //bad
Expand Down Expand Up @@ -92,8 +92,8 @@ export default function DashboardPage() {
value: 180 / tmpTotal,
},
{
"id": "networking",
"label": "Networking",
"id": "timeout",
"label": "Timeout",
count: 169,
value: 169 / tmpTotal,
},
Expand All @@ -113,12 +113,11 @@ export default function DashboardPage() {
return data;
}, [rndCounter]);


return (
<div className="w-full flex flex-col items-center justify-center gap-2">
<div className="w-full grid grid-cols-8 gap-4 h-[22rem]">
<div className="w-full flex flex-col items-center justify-center gap-4">
<div className="w-full grid grid-cols-8 gap-4 h-[22rem] max-h-[22rem] overflow-clip">
<ThreadPerfCard data={threadPerfChartData} />
<div className="py-2 px-4 rounded-lg border shadow-sm col-span-2">
<div className="py-2 px-4 rounded-lg border shadow-sm col-span-2 min-w-60 bg-card">
<div className="flex flex-row items-center justify-between space-y-0 pb-2 text-muted-foreground">
<h3 className="tracking-tight text-sm font-medium line-clamp-1">Host stats (last minute)</h3>
<div className='hidden xs:block'><GaugeIcon /></div>
Expand Down
28 changes: 12 additions & 16 deletions panel/src/pages/Dashboard/FullPerfCard.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { BarChartHorizontalIcon } from 'lucide-react';
import { memo, useEffect, useRef, useState } from 'react';
import AutoSizer from "react-virtualized-auto-sizer";
import { BarChartHorizontalIcon, LineChartIcon } from 'lucide-react';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import AutoSizer, { Size, VerticalSize } from "react-virtualized-auto-sizer";
import * as d3 from 'd3';
import { createRandomHslColor } from '@/lib/utils';
import { debounce } from 'throttle-debounce';
import DebouncedResizeContainer from '@/components/DebouncedResizeContainer';

type FullPerfChartProps = any;

Expand All @@ -23,7 +25,7 @@ const FullPerfChart = memo(({
useEffect(() => void d3.select(gx.current).call(d3.axisBottom(x)), [gx, x]);
useEffect(() => void d3.select(gy.current).call(d3.axisLeft(y)), [gy, y]);
return (
<svg width={'100%'} height={height}>
<svg width={'100%'} height={height} style={{ backgroundColor: createRandomHslColor() }}>
<rect
x={(width / 2) - 50} y={0}
width={50} height={10}
Expand All @@ -41,30 +43,24 @@ const FullPerfChart = memo(({
});



type FullPerfCardProps = {
//
};

export default function FullPerfCard({ }: FullPerfCardProps) {
const [chartSize, setChartSize] = useState({ width: 0, height: 0 });
const [data, setData] = useState(() => d3.ticks(-2, 2, 200).map(Math.sin));
function onMouseMove(event) {
const [x, y] = d3.pointer(event);
setData(data.slice(-200).concat(Math.atan2(x, y)));
}

return (
<div className="w-full h-[32rem] py-2 rounded-lg border shadow-sm flex flex-col fill-primary">
<div className="px-4 flex flex-row items-center justify-between space-y-0 pb-2 text-muted-foreground">
<h3 className="tracking-tight text-sm font-medium line-clamp-1">Thread performance (last minute)</h3>
<div className='hidden xs:block'><BarChartHorizontalIcon /></div>
</div>
<div className="size-full">
<AutoSizer style={{ width: '100%' }} onMouseMove={onMouseMove}>
{({ height, width }) => (
<FullPerfChart data={data} height={height} width={width} />
)}
</AutoSizer>
<div className='hidden xs:block'><LineChartIcon /></div>
</div>
<DebouncedResizeContainer onDebouncedResize={setChartSize}>
<FullPerfChart data={data} width={chartSize.width} height={chartSize.height} />
</DebouncedResizeContainer>
</div>
);
}
Loading

0 comments on commit 3cfb413

Please sign in to comment.