Files
Jungfraujoch/frontend/src/components/FpgaStatus.tsx
T
leonarski_fandClaude Opus 4.8 237de5a0fc frontend: convert to function components + TanStack Query
Replace all class components with function components and move server-state
polling to @tanstack/react-query.

- add @tanstack/react-query; generate query helpers via the hey-api
  @tanstack/react-query plugin (src/client/@tanstack)
- QueryClientProvider + one-time client.setConfig({ baseUrl: '' }) in index.tsx
- App polls statistics with useQuery(getStatisticsOptions, refetchInterval),
  DataProcessingPlot uses getPreviewPlotOptions; manual setInterval polling gone
- memo() on presentational children; with TanStack structural sharing this
  re-renders a child only when its own statistics slice changes
- PreviewImage stays imperative (binary JPEG -> object URL) using useEffect +
  a ref for the object-URL lifecycle
- fix AzIntSettings correction checkboxes that mutated state in place (relied on
  the poll re-render); they now use setState
- drop dead code uncovered during the port (unused upload/deactivate handlers
  and imports in ImageFormatSettings, DetectorSettings, ROI)

Build (tsc + vite) passes; dev server transforms all entry modules.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 21:32:36 +02:00

101 lines
3.4 KiB
TypeScript

import {memo, ReactNode} from 'react';
import Paper from '@mui/material/Paper';
import {DataGrid, GridCellParams, GridColDef} from "@mui/x-data-grid";
import { fpga_status} from "../client";
function Circles(val: boolean) : ReactNode {
if (val)
return <div style={{color: "green", display: "inline"}} >&#9679;</div>;
else
return <div style={{color: "red", display: "inline"}}>&#9675;</div>;
}
function EthLinkStatus(count: number, status: number) : ReactNode {
if (!Number.isInteger(count) || !Number.isInteger(status) || (count < 1))
return <div>"ERR"</div>;
let arr: boolean[] = [];
for (let i = 0; i < count; i++) {
if (status & (1 << i))
arr.push(true);
else
arr.push(false);
}
return <>
{ arr.map(val => Circles(val)) }
</>;
}
function CardIdle(val: boolean) : ReactNode {
return Circles(val);
}
function LinkSpeed(speed: number, width: number) : ReactNode {
if ((speed === 4) && (width === 8))
return <div style={{display: "inline"}} >Gen{speed}x{width}</div>;
else
return <div style={{color: "red", display: "inline"}} >Gen{speed}x{width}</div>;
}
function DataVolume(count_4kib: number) : string {
if (!Number.isInteger(count_4kib))
return "ERR";
let val = 4096 * count_4kib;
let val_MiB = val / (1024*1024);
let val_GiB = val / (1024*1024*1024);
if (val == 0)
return "0";
else if (val_GiB > 1)
return val_GiB.toFixed(1) + " GiB";
else
return val_MiB.toFixed(1) + " MiB";
}
type MyProps = {
s?: fpga_status;
};
const columns : GridColDef[] = [
{ field: 'pci_dev_id', type: 'string', headerName: 'PCIe ID' },
{ field: 'base_mac_addr', type: 'string', headerName: 'MAC address', width: 200 },
{ field: 'eth_link_status', type: 'string', headerName: 'Link status', align: `center`,
renderCell: (params : GridCellParams) => EthLinkStatus(params.row.eth_link_count,
params.row.eth_link_status)
},
{ field: 'idle', type: 'string', headerName: 'Idle', align: `center`,
renderCell: (params : GridCellParams) => CardIdle(params.row.idle)
},
{ field: 'power_usage_W', type: 'number', headerName: 'Power usage [W]', width: 150},
{ field: 'fpga_temp_C', type: 'number', headerName: 'FPGA temperature [C]', width: 200 },
{ field: 'hbm_temp_C', type: 'number', headerName: 'HBM temperature [C]', width: 200 },
{ field: 'packets_sls', type: 'number', headerName: 'Data (current data collection)', width: 150,
valueGetter: (params, row) => DataVolume(row.packets_sls)},
{ field: "fw_version", type: 'string', headerName: 'Firmware version', width: 150 },
{ field: "pcie_link", type: 'string', headerName: 'PCIe link', width: 100, align: `center`,
renderCell: (params : GridCellParams) => LinkSpeed(params.row.pcie_link_speed, params.row.pcie_link_width)}
];
function FpgaStatus({s}: MyProps) {
return <Paper style={{textAlign: 'center'}} sx={{ height: 500, width: '100%' }}>
{((s !== undefined) && (s.length > 0)) ?
<DataGrid
rows={s}
columns={columns}
getRowId={(row) => row.pci_dev_id}
autosizeOnMount={true}
initialState={{
pagination: { paginationModel: { pageSize: 8 } },
}}
/> : <div> No FPGA available</div>
}
</Paper>
}
export default memo(FpgaStatus);