feat(web): layout & auto-update debug page

This commit is contained in:
Paul Armstrong 2021-01-18 10:49:00 -08:00 committed by Blake Blackshear
parent 16121ffd00
commit a3d6bf214c
4 changed files with 108 additions and 24 deletions

View File

@ -21,6 +21,7 @@ module.exports = {
}, },
], ],
], ],
routes: [{ match: 'routes', src: '.*', dest: '/index.html' }],
packageOptions: { packageOptions: {
sourcemap: false, sourcemap: false,
}, },

View File

@ -24,9 +24,9 @@ export default function App() {
<div /> <div />
) : ( ) : (
<Config.Provider value={config}> <Config.Provider value={config}>
<div className="md:flex flex-col md:flex-row md:min-h-screen w-full bg-gray-100 dark:bg-gray-800 "> <div className="flex md:min-h-screen w-full bg-gray-100 dark:bg-gray-800">
<Sidebar /> <Sidebar />
<div className="p-4"> <div className="p-4 min-w-0">
<Router> <Router>
<CameraMap path="/cameras/:camera/editor" /> <CameraMap path="/cameras/:camera/editor" />
<Camera path="/cameras/:camera" /> <Camera path="/cameras/:camera" />

View File

@ -1,16 +1,97 @@
import { h } from 'preact'; import { h } from 'preact';
import { ApiHost } from './context'; import Heading from './components/Heading';
import { useContext, useEffect, useState } from 'preact/hooks'; import Link from './components/Link';
import { ApiHost, Config } from './context';
import { Table, Tbody, Thead, Tr, Th, Td } from './components/Table';
import { useCallback, useContext, useEffect, useState } from 'preact/hooks';
export default function Debug() { export default function Debug() {
const apiHost = useContext(ApiHost); const apiHost = useContext(ApiHost);
const [config, setConfig] = useState({}); const config = useContext(Config);
const [stats, setStats] = useState({});
const [timeoutId, setTimeoutId] = useState(null);
useEffect(async () => { const fetchStats = useCallback(async () => {
const response = await fetch(`${apiHost}/api/stats`); const statsResponse = await fetch(`${apiHost}/api/stats`);
const data = response.ok ? await response.json() : {}; const stats = statsResponse.ok ? await statsResponse.json() : {};
setConfig(data); setStats(stats);
setTimeoutId(setTimeout(fetchStats, 1000));
}, [setStats]);
useEffect(() => {
fetchStats();
}, []); }, []);
return <pre>{JSON.stringify(config, null, 2)}</pre>; useEffect(() => {
return () => {
clearTimeout(timeoutId);
};
}, [timeoutId]);
const { detectors, detection_fps, service, ...cameras } = stats;
if (!service) {
return 'loading…';
}
const detectorNames = Object.keys(detectors);
const detectorDataKeys = Object.keys(detectors[detectorNames[0]]);
const cameraNames = Object.keys(cameras);
const cameraDataKeys = Object.keys(cameras[cameraNames[0]]);
return (
<div>
<Heading>
Debug <span className="text-sm">{service.version}</span>
</Heading>
<Table className="w-full">
<Thead>
<Tr>
<Th>detector</Th>
{detectorDataKeys.map((name) => (
<Th>{name.replace('_', ' ')}</Th>
))}
</Tr>
</Thead>
<Tbody>
{detectorNames.map((detector, i) => (
<Tr index={i}>
<Td>{detector}</Td>
{detectorDataKeys.map((name) => (
<Td key={`${name}-${detector}`}>{detectors[detector][name]}</Td>
))}
</Tr>
))}
</Tbody>
</Table>
<Table className="w-full">
<Thead>
<Tr>
<Th>camera</Th>
{cameraDataKeys.map((name) => (
<Th>{name.replace('_', ' ')}</Th>
))}
</Tr>
</Thead>
<Tbody>
{cameraNames.map((camera, i) => (
<Tr index={i}>
<Td>
<Link href={`/cameras/${camera}`}>{camera}</Link>
</Td>
{cameraDataKeys.map((name) => (
<Td key={`${name}-${camera}`}>{cameras[camera][name]}</Td>
))}
</Tr>
))}
</Tbody>
</Table>
<Heading size="sm">Config</Heading>
<pre className="font-mono overflow-y-scroll overflow-x-scroll max-h-96 rounded bg-white dark:bg-gray-900">
{JSON.stringify(config, null, 2)}
</pre>
</div>
);
} }

View File

@ -1,29 +1,31 @@
import { h } from 'preact'; import { h } from 'preact';
export function Table({ children }) { export function Table({ children, className }) {
return <table className="table-auto border-collapse text-gray-900 dark:text-gray-200">{children}</table>; return (
<table className={`table-auto border-collapse text-gray-900 dark:text-gray-200 ${className}`}>{children}</table>
);
} }
export function Thead({ children }) { export function Thead({ children, className }) {
return <thead className="">{children}</thead>; return <thead className={`${className}`}>{children}</thead>;
} }
export function Tbody({ children }) { export function Tbody({ children, className }) {
return <tbody className="">{children}</tbody>; return <tbody className={`${className}`}>{children}</tbody>;
} }
export function Tfoot({ children }) { export function Tfoot({ children, className }) {
return <tfoot className="">{children}</tfoot>; return <tfoot className={`${className}`}>{children}</tfoot>;
} }
export function Tr({ children, index }) { export function Tr({ children, className, index }) {
return <tr className={`${index % 2 ? 'bg-gray-200 ' : ''}`}>{children}</tr>; return <tr className={`${index % 2 ? 'bg-gray-200 ' : ''} ${className}`}>{children}</tr>;
} }
export function Th({ children }) { export function Th({ children, className }) {
return <th className="border-b-2 border-gray-400 p-4 text-left">{children}</th>; return <th className={`border-b-2 border-gray-400 p-4 text-left ${className}`}>{children}</th>;
} }
export function Td({ children }) { export function Td({ children, className }) {
return <td className="p-4">{children}</td>; return <td className={`p-4 ${className}`}>{children}</td>;
} }