Files
Jungfraujoch/frontend/src/App.tsx
T
leonarski_f 64002f1e29
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 11m14s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 10m43s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 11m35s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 9m20s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 10m23s
Build Packages / Generate python client (push) Successful in 39s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 11m24s
Build Packages / Create release (push) Has been skipped
Build Packages / Build documentation (push) Successful in 1m0s
Build Packages / build:rpm (rocky8) (push) Successful in 10m35s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 10m35s
Build Packages / build:rpm (rocky9) (push) Successful in 11m17s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 9m9s
Build Packages / Unit tests (push) Failing after 1h18m57s
v1.0.0-rc.129 (#36)
This is an UNSTABLE release. The release has significant modifications and bug fixes, if things go wrong, it is better to revert to 1.0.0-rc.124.

* jfjoch_broker: Significant improvements in TCP image socket, as a viable alternative for ZeroMQ sockets (only a single port on broker side, dynamically change number of writers, acknowledgments for written files)
* jfjoch_broker: Delta phi is calculated also for still data in Bragg prediction
* jfjoch_broker: Image pusher statistics are accessible via the REST interface
* jfjoch_writer: Supports TCP image socket and for these auto-forking option

Reviewed-on: #36
Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
Co-committed-by: Filip Leonarski <filip.leonarski@psi.ch>
2026-03-05 22:13:12 +01:00

255 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, {Component} from 'react';
import {createTheme, CssBaseline, Grid, Stack, Switch, ThemeProvider, Typography} from "@mui/material";
import {indigo, lime} from "@mui/material/colors";
import DataProcessingSettings from "./components/DataProcessingSettings";
import DetectorSettings from "./components/DetectorSettings";
import Calibration from "./components/Calibration";
import StatusBar from "./components/StatusBar";
import DataProcessingPlots from "./components/DataProcessingPlots";
import DetectorSelection from "./components/DetectorSelection";
import MeasurementStatistics from "./components/MeasurementStatistics";
import DetectorStatus from "./components/DetectorStatus";
import Paper from "@mui/material/Paper";
import PreviewImage from "./components/PreviewImage";
import ROI from "./components/ROI";
import ImageFormatSettings from "./components/ImageFormatSettings";
import InstrumentMetadata from "./components/InstrumentMetadata";
import {JFJOCH_VERSION} from "./version";
import FpgaStatus from "./components/FpgaStatus";
import {broker_status, DefaultService, OpenAPI, plot_type} from "./openapi";
import {jfjoch_statistics} from "./openapi";
import DataCollection from "./components/DataCollection";
import ZeroMQPreview from "./components/ZeroMQPreview";
import PixelMask from "./components/PixelMask";
import ErrorMessage from "./components/ErrorMessage";
import FileWriterSettings from "./components/FileWriterSettings";
import AzIntSettings from "./components/AzIntSettings";
import IndexingSettings from "./components/IndexingSettings";
import DarkMaskSettings from "./components/DarkMaskSettings";
import ImagePusherStatus from "./components/ImagePusherStatus";
const jfjoch_theme = createTheme({
palette: {
primary: indigo,
secondary: lime,
},
});
type MyState = {
show_detector_setup: boolean,
show_module_calibration: boolean,
show_preview: boolean,
show_roi_setup: boolean,
show_fpga_status: boolean,
connection_error: boolean,
show_data_collection: boolean,
s: jfjoch_statistics
}
type MyProps = {}
class App extends Component<MyProps, MyState> {
interval: ReturnType<typeof setInterval> | undefined;
state : MyState = {
show_detector_setup: false,
show_module_calibration: false,
show_preview: false,
show_roi_setup: false,
show_fpga_status: false,
connection_error: true,
show_data_collection: false,
s: {}
}
getValues() {
DefaultService.getStatistics()
.then(data => this.setState({s: data, connection_error: false}))
.catch(_ => {
this.setState({s: {}, connection_error: true});
});
}
componentWillUnmount() {
clearInterval(this.interval);
}
componentDidMount() {
OpenAPI.BASE='';
this.getValues();
this.interval = setInterval(() => this.getValues(), 1000);
}
showPreviewToggle = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({show_preview: event.target.checked});
}
showDetectorSetupToggle = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({show_detector_setup: event.target.checked});
}
showModuleCalibrationToggle = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({show_module_calibration: event.target.checked});
}
showROISetupToggle = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({show_roi_setup: event.target.checked});
}
showFPGAStatusToggle = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({show_fpga_status: event.target.checked});
}
showDataCollectionToggle = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({show_data_collection: event.target.checked});
}
renderTitleWithSwitch = (name: string, checked: boolean, func: ((event: React.ChangeEvent<HTMLInputElement>) => void)) => {
return <Grid item xs={12}>
<Paper style={{textAlign: 'center'}} sx={{height: 60, width: '100%'}} component={Stack}
direction="column" justifyContent="center">
<Grid container spacing={0}>
<Grid xs={1}/>
<Grid xs={10}>
<Typography variant="h5"> {name} </Typography>
</Grid>
<Grid xs={1}>
<Switch checked={checked}
onChange={func}
name="Show detector setup"/>
</Grid>
</Grid>
</Paper>
</Grid>
};
isMeasuring() : boolean {
return (this.state.s.broker !== undefined)
&& (this.state.s.broker.state == broker_status.state.MEASURING);
}
render() {
return <ThemeProvider theme={jfjoch_theme}>
<CssBaseline enableColorScheme/>
<StatusBar s={this.state.s.broker}/> <br/><br/><br/><br/>
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
<Grid container
justifyContent="center"
alignItems="center"
spacing={3}
sx={{width: "95%"}}>
<Grid item xs={2}/>
<Grid item xs={8}>
<ErrorMessage s={this.state.s.broker}/>
</Grid>
<Grid item xs={2}/>
<Grid item xs={8}>
<DataProcessingPlots height={550} type={plot_type.BKG_ESTIMATE}/>
</Grid>
<Grid item xs={4}>
<MeasurementStatistics
s={(this.state.s.measurement === undefined) ? {} : this.state.s.measurement}/>
</Grid>
<Grid item xs={8}>
<DataProcessingPlots height={800} type={plot_type.INDEXING_RATE}/>
</Grid>
<Grid item xs={4}>
<DataProcessingSettings s={this.state.s.data_processing_settings} update={this.getValues}/>
</Grid>
{
this.renderTitleWithSwitch("Live image preview", this.state.show_preview, this.showPreviewToggle)
}
<Grid item xs={12}>
{this.state.show_preview ? <PreviewImage measuring={this.isMeasuring()}
max_image_number={this.state.s.buffer?.max_image_number}
min_image_number={this.state.s.buffer?.min_image_number}/> : ""}
</Grid>
<br/><br/>
{
this.renderTitleWithSwitch("Data collection",
this.state.show_data_collection, this.showDataCollectionToggle)
}
<Grid item xs={2}/>
<Grid item xs={8}>
{this.state.show_data_collection ? <DataCollection frame_time_us={
this.state.s.detector_settings?.frame_time_us ?? 500
}/> : ""}
</Grid>
<Grid item xs={2}/>
<br/><br/>
{
this.renderTitleWithSwitch("Jungfraujoch expert configuration",
this.state.show_detector_setup, this.showDetectorSetupToggle)
}
<Grid item xs={4}>
{this.state.show_detector_setup ? <Stack spacing={2}>
<DetectorSettings s={this.state.s.detector_settings}/>
<PixelMask s={this.state.s.pixel_mask}/>
<DarkMaskSettings s={this.state.s.dark_mask}/>
<FileWriterSettings s={this.state.s.file_writer_settings}/>
</Stack>: ""}
</Grid>
<Grid item xs={4}>
{this.state.show_detector_setup ?
<Stack spacing={2}>
<DetectorSelection s={this.state.s.detector_list}/>
<DetectorStatus s={this.state.s.detector}/>
<ZeroMQPreview s={this.state.s.zeromq_preview}/>
<IndexingSettings s={this.state.s.indexing} status={this.state.s.broker}/>
</Stack> : ""}
</Grid>
<Grid item xs={4}>
{this.state.show_detector_setup ?
<Stack spacing={2}>
<ImageFormatSettings s={this.state.s.image_format_settings}/>
<InstrumentMetadata s={this.state.s.instrument_metadata}/>
<AzIntSettings s={this.state.s.az_int}/>
<ImagePusherStatus s={this.state.s.image_pusher}/>
</Stack> : ""}
</Grid>
<br/><br/>
{
this.renderTitleWithSwitch("JUNGFRAU module calibration",
this.state.show_module_calibration, this.showModuleCalibrationToggle)
}
<Grid item xs={12}>
{this.state.show_module_calibration ? <Calibration s={this.state.s.calibration}/> : ""}
</Grid>
<br/><br/>
{
this.renderTitleWithSwitch("Region of interest (ROI)",
this.state.show_roi_setup, this.showROISetupToggle)
}
<Grid item xs={12}>
{this.state.show_roi_setup ? <ROI s={this.state.s.roi}/> : ""}
</Grid>
<br/><br/>
{
this.renderTitleWithSwitch("FPGA status",
this.state.show_fpga_status, this.showFPGAStatusToggle)
}
<Grid item xs={12}>
{this.state.show_fpga_status ? <FpgaStatus s={this.state.s.fpga}/> : ""}
</Grid>
</Grid>
</div>
<br/>
<center>Developed at Paul Scherrer Institute (2019-2024). Main author: <a
href="mailto:filip.leonarski@psi.ch">Filip Leonarski</a> <br/>
For more information see <a href="https://doi.org/10.1107/S1600577522010268"><i>J. Synchrotron
Rad.</i> (2023). <b>30</b>, 227234</a> <br/>
Version: {JFJOCH_VERSION}&nbsp;&nbsp;&nbsp;
<a href="/frontend/openapi.html">API reference</a>&nbsp;&nbsp;&nbsp;
<a href="https://jungfraujoch.readthedocs.io/">Documentation</a></center>
<br/>
</ThemeProvider>
}
}
export default App;