diff --git a/frontend/src/components/DataProcessingSettings.tsx b/frontend/src/components/DataProcessingSettings.tsx index 86c9cb79..6c216457 100644 --- a/frontend/src/components/DataProcessingSettings.tsx +++ b/frontend/src/components/DataProcessingSettings.tsx @@ -1,8 +1,10 @@ import {ChangeEvent, memo, useEffect, useState} from 'react'; import {Grid, Slider, Switch, Typography} from "@mui/material"; -import {putConfigSpotFinding, spot_finding_settings} from "../client"; +import {spot_finding_settings} from "../client"; +import {putConfigSpotFindingMutation} from "../client/@tanstack/react-query.gen"; import SettingsPanel from "./SettingsPanel"; +import {useUpload} from "./useUpload"; import _ from "lodash"; type MyProps = { @@ -25,17 +27,20 @@ const default_spot_finding_settings: spot_finding_settings = { high_res_gap_Q_recipA: 1.5 }; -function putValues(x: spot_finding_settings) { - putConfigSpotFinding({ body: x, throwOnError: true }) - .catch(error => console.log(error) ); -} - function DataProcessingSettings({s: serverS, update}: MyProps) { const [s, setS] = useState(default_spot_finding_settings); const [lastDownloadedS, setLastDownloadedS] = useState(default_spot_finding_settings); const [highResGap, setHighResGap] = useState(1.5); const [highResLimit, setHighResLimit] = useState(2.5); + const { submit, snackbar } = useUpload({ + ...putConfigSpotFindingMutation(), + // A rejected PUT would otherwise leave the panel showing a value the broker is not using: + // the poll keeps returning the old value, which still equals lastDownloadedS, so the + // effect below never corrects it. Put the server's value back. + onError: () => { if (serverS !== undefined) setS(serverS); }, + }); + // Only adopt the server copy when it actually changed, otherwise the // 1 s statistics poll would overwrite edits the user is making. useEffect(() => { @@ -50,38 +55,20 @@ function DataProcessingSettings({s: serverS, update}: MyProps) { const apply = (next: spot_finding_settings) => { setS(next); - putValues(next); + submit(next); update(); }; - const setPhotonCountThreshold = (event: Event, newValue: number | number[]) => - apply({...s, photon_count_threshold: newValue as number}); - - const setSignalToNoiseThreshold = (event: Event, newValue: number | number[]) => - apply({...s, signal_to_noise_threshold: newValue as number}); - - const setMinPixPerSpot = (event: Event, newValue: number | number[]) => - apply({...s, min_pix_per_spot: newValue as number}); - - const setLowResolutionLimit = (event: Event, newValue: number | number[]) => - apply({...s, low_resolution_limit: newValue as number}); - - const setHighResolutionLimit = (event: Event, newValue: number | number[]) => { - const v = newValue as number; - setHighResLimit(v); - apply({...s, high_resolution_limit: v}); - }; + // While the knob is dragged only the panel moves; the value is sent on release. MUI fires + // onChange for every intermediate position, and each one is a PUT that reconfigures spot + // finding on the running acquisition - one drag across the ice-ring width was ~200 of them. + const preview = (patch: Partial) => + setS(prev => ({...prev, ...patch})); // No high-resolution limit means spot finding goes as far as the detector reaches. const autoHighResolutionLimitToggle = (event: ChangeEvent) => apply({...s, high_resolution_limit: event.target.checked ? undefined : highResLimit}); - const setHighResolutionLimitForCountingLowResSpots = (event: Event, newValue: number | number[]) => - apply({...s, high_resolution_limit_for_spot_count_low_res: newValue as number}); - - const setIceRingWidth = (event: Event, newValue: number | number[]) => - apply({...s, ice_ring_width_q_recipA: newValue as number}); - const enableSpotFindingToggle = (event: ChangeEvent) => apply({...s, enable: event.target.checked}); @@ -94,14 +81,8 @@ function DataProcessingSettings({s: serverS, update}: MyProps) { const enableHighResGapToggle = (event: ChangeEvent) => apply({...s, high_res_gap_Q_recipA: event.target.checked ? highResGap : undefined}); - const handleHighResGap = (event: Event, newValue: number | number[]) => { - const v = newValue as number; - setHighResGap(v); - apply({...s, high_res_gap_Q_recipA: v}); - }; - return ( - + @@ -113,13 +94,15 @@ function DataProcessingSettings({s: serverS, update}: MyProps) { Count threshold preview({photon_count_threshold: v as number})} + onChangeCommitted={(e, v) => apply({...s, photon_count_threshold: v as number})} min={1} max={50} step={1} valueLabelDisplay="auto"/>
Signal-to-noise threshold preview({signal_to_noise_threshold: v as number})} + onChangeCommitted={(e, v) => apply({...s, signal_to_noise_threshold: v as number})} min={2} max={10} step={0.5} @@ -130,12 +113,14 @@ function DataProcessingSettings({s: serverS, update}: MyProps) {
Minimum pixel / spot preview({min_pix_per_spot: v as number})} + onChangeCommitted={(e, v) => apply({...s, min_pix_per_spot: v as number})} min={1} max={8} step={1} valueLabelDisplay="auto"/> Low resolution limit [Å] preview({low_resolution_limit: v as number})} + onChangeCommitted={(e, v) => apply({...s, low_resolution_limit: v as number})} min={10} max={100} step={0.1} valueLabelDisplay="auto" valueLabelFormat={(value) => value.toFixed(1)} /> @@ -147,21 +132,24 @@ function DataProcessingSettings({s: serverS, update}: MyProps) { High resolution limit [Å] { setHighResLimit(v as number); preview({high_resolution_limit: v as number}); }} + onChangeCommitted={(e, v) => apply({...s, high_resolution_limit: v as number})} min={1} max={5} step={0.1} valueLabelDisplay="auto" valueLabelFormat={(value) => value.toFixed(1)} /> High resolution limit for counting low resolution spots [Å] preview({high_resolution_limit_for_spot_count_low_res: v as number})} + onChangeCommitted={(e, v) => apply({...s, high_resolution_limit_for_spot_count_low_res: v as number})} min={2} max={8} step={0.1} valueLabelDisplay="auto" valueLabelFormat={(value) => value.toFixed(1)} /> Ice ring width in Q-space [Å-1] preview({ice_ring_width_q_recipA: v as number})} + onChangeCommitted={(e, v) => apply({...s, ice_ring_width_q_recipA: v as number})} min={0.0} max={0.2} step={0.001} valueLabelDisplay="auto" valueLabelFormat={(value) => value.toFixed(3)} /> @@ -176,7 +164,8 @@ function DataProcessingSettings({s: serverS, update}: MyProps) { { setHighResGap(v as number); preview({high_res_gap_Q_recipA: v as number}); }} + onChangeCommitted={(e, v) => apply({...s, high_res_gap_Q_recipA: v as number})} min={0.1} max={5.0} step={0.01}