Debug.jsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import { h, Fragment } from 'preact';
  2. import ActivityIndicator from '../components/ActivityIndicator';
  3. import Button from '../components/Button';
  4. import Heading from '../components/Heading';
  5. import Link from '../components/Link';
  6. import { useMqtt } from '../api/mqtt';
  7. import { useConfig, useStats } from '../api';
  8. import { Table, Tbody, Thead, Tr, Th, Td } from '../components/Table';
  9. import { useCallback } from 'preact/hooks';
  10. const emptyObject = Object.freeze({});
  11. export default function Debug() {
  12. const { data: config } = useConfig();
  13. const {
  14. value: { payload: stats },
  15. } = useMqtt('stats');
  16. const { data: initialStats } = useStats();
  17. const { detectors, service = {}, detection_fps, ...cameras } = stats || initialStats || emptyObject;
  18. const detectorNames = Object.keys(detectors || emptyObject);
  19. const detectorDataKeys = Object.keys(detectors ? detectors[detectorNames[0]] : emptyObject);
  20. const cameraNames = Object.keys(cameras || emptyObject);
  21. const cameraDataKeys = Object.keys(cameras[cameraNames[0]] || emptyObject);
  22. const handleCopyConfig = useCallback(() => {
  23. async function copy() {
  24. await window.navigator.clipboard.writeText(JSON.stringify(config, null, 2));
  25. }
  26. copy();
  27. }, [config]);
  28. return (
  29. <div className="space-y-4">
  30. <Heading>
  31. Debug <span className="text-sm">{service.version}</span>
  32. </Heading>
  33. {!detectors ? (
  34. <div>
  35. <ActivityIndicator />
  36. </div>
  37. ) : (
  38. <Fragment>
  39. <div data-testid="detectors" className="min-w-0 overflow-auto">
  40. <Table className="w-full">
  41. <Thead>
  42. <Tr>
  43. <Th>detector</Th>
  44. {detectorDataKeys.map((name) => (
  45. <Th>{name.replace('_', ' ')}</Th>
  46. ))}
  47. </Tr>
  48. </Thead>
  49. <Tbody>
  50. {detectorNames.map((detector, i) => (
  51. <Tr index={i}>
  52. <Td>{detector}</Td>
  53. {detectorDataKeys.map((name) => (
  54. <Td key={`${name}-${detector}`}>{detectors[detector][name]}</Td>
  55. ))}
  56. </Tr>
  57. ))}
  58. </Tbody>
  59. </Table>
  60. </div>
  61. <div data-testid="cameras" className="min-w-0 overflow-auto">
  62. <Table className="w-full">
  63. <Thead>
  64. <Tr>
  65. <Th>camera</Th>
  66. {cameraDataKeys.map((name) => (
  67. <Th>{name.replace('_', ' ')}</Th>
  68. ))}
  69. </Tr>
  70. </Thead>
  71. <Tbody>
  72. {cameraNames.map((camera, i) => (
  73. <Tr index={i}>
  74. <Td>
  75. <Link href={`/cameras/${camera}`}>{camera}</Link>
  76. </Td>
  77. {cameraDataKeys.map((name) => (
  78. <Td key={`${name}-${camera}`}>{cameras[camera][name]}</Td>
  79. ))}
  80. </Tr>
  81. ))}
  82. </Tbody>
  83. </Table>
  84. </div>
  85. <p>Debug stats update automatically every {config.mqtt.stats_interval} seconds.</p>
  86. </Fragment>
  87. )}
  88. <div className="relative">
  89. <Heading size="sm">Config</Heading>
  90. <Button className="absolute top-8 right-4" onClick={handleCopyConfig}>
  91. Copy to Clipboard
  92. </Button>
  93. <pre className="overflow-auto font-mono text-gray-900 dark:text-gray-100 rounded bg-gray-100 dark:bg-gray-800 p-2 max-h-96">
  94. {JSON.stringify(config, null, 2)}
  95. </pre>
  96. </div>
  97. </div>
  98. );
  99. }