Enhance dynamic height handling for RunDetails components.
Added support for dynamic height calculation in RunDetails and integrated it with ResultGrid to adjust detail panel heights based on content changes. This ensures proper rendering and improves responsiveness of the UI.
This commit is contained in:
parent
6bd4843d38
commit
91aebae473
@ -102,6 +102,8 @@ interface ResultGridProps {
|
|||||||
const ResultGrid: React.FC<ResultGridProps> = ({ activePgroup }) => {
|
const ResultGrid: React.FC<ResultGridProps> = ({ activePgroup }) => {
|
||||||
const [rows, setRows] = useState<TreeRow[]>([]);
|
const [rows, setRows] = useState<TreeRow[]>([]);
|
||||||
const [basePath, setBasePath] = useState('');
|
const [basePath, setBasePath] = useState('');
|
||||||
|
const [detailPanelHeights, setDetailPanelHeights] = useState<{ [key: string]: number }>({}); // Store dynamic heights
|
||||||
|
|
||||||
const hasProcessingResults = (row: TreeRow): boolean => {
|
const hasProcessingResults = (row: TreeRow): boolean => {
|
||||||
// You can later replace this placeholder with actual logic.
|
// You can later replace this placeholder with actual logic.
|
||||||
// Mocking the logic by returning `true` for demonstration.
|
// Mocking the logic by returning `true` for demonstration.
|
||||||
@ -282,19 +284,38 @@ const ResultGrid: React.FC<ResultGridProps> = ({ activePgroup }) => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const handleDetailPanelHeightChange = (rowId: string, height: number) => {
|
||||||
|
// Update the height of the specific detail panel dynamically
|
||||||
|
setDetailPanelHeights((prev) => {
|
||||||
|
if (prev[rowId] !== height) {
|
||||||
|
return { ...prev, [rowId]: height };
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getDetailPanelContent = (params: any) => {
|
const getDetailPanelContent = (params: any) => {
|
||||||
if (params.row.type === 'run') {
|
if (params.row.type === 'run') {
|
||||||
return <RunDetails run={params.row} />;
|
return (
|
||||||
|
<RunDetails
|
||||||
|
run={params.row}
|
||||||
|
onHeightChange={(height: number) => handleDetailPanelHeightChange(params.row.id, height)} // Pass callback for dynamic height
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDetailPanelHeight = (params: any) => {
|
const getDetailPanelHeight = (params: any) => {
|
||||||
if (params.row.type === 'run') return 300;
|
if (params.row.type === 'run') {
|
||||||
|
// Use the dynamically calculated height from state
|
||||||
|
return detailPanelHeights[params.row.id] || 600; // Fallback to default height if not yet calculated
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataGridPremium
|
<DataGridPremium
|
||||||
rows={rows}
|
rows={rows}
|
||||||
|
@ -1,120 +1,175 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionSummary,
|
AccordionSummary,
|
||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/material';
|
Grid,
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
} from '@mui/material';
|
||||||
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||||
|
import './SampleImage.css';
|
||||||
|
|
||||||
const RunDetails: React.FC<RunDetailsProps> = ({ run }) => {
|
interface RunDetailsProps {
|
||||||
const { beamline_parameters } = run;
|
run: ExperimentParameters;
|
||||||
const { synchrotron, beamline, detector } = beamline_parameters;
|
onHeightChange?: (height: number) => void; // Callback to notify the parent about height changes
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
const RunDetails: React.FC<RunDetailsProps> = ({ run, onHeightChange }) => {
|
||||||
<div style={{ padding: '16px', border: '1px solid #ccc', borderRadius: '4px' }}>
|
const containerRef = useRef<HTMLDivElement | null>(null); // Ref to track component height
|
||||||
<Typography variant="h6" gutterBottom>
|
const [currentHeight, setCurrentHeight] = useState<number>(0);
|
||||||
Run {run.run_number} Details
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="subtitle1" gutterBottom>
|
|
||||||
Beamline: {beamline} | Synchrotron: {synchrotron}
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Accordion>
|
const { beamline_parameters, images } = run;
|
||||||
<AccordionSummary
|
const { synchrotron, beamline, detector } = beamline_parameters;
|
||||||
expandIcon={<ExpandMoreIcon />}
|
|
||||||
aria-controls="detector-content"
|
|
||||||
id="detector-header"
|
|
||||||
>
|
|
||||||
<Typography><strong>Detector Details</strong></Typography>
|
|
||||||
</AccordionSummary>
|
|
||||||
<AccordionDetails>
|
|
||||||
<Typography>Manufacturer: {detector?.manufacturer || 'N/A'}</Typography>
|
|
||||||
<Typography>Model: {detector?.model || 'N/A'}</Typography>
|
|
||||||
<Typography>Type: {detector?.type || 'N/A'}</Typography>
|
|
||||||
<Typography>
|
|
||||||
Beam Center (px): x: {detector?.beamCenterX_px || 'N/A'}, y: {detector?.beamCenterY_px || 'N/A'}
|
|
||||||
</Typography>
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion>
|
|
||||||
|
|
||||||
<Accordion>
|
// Calculate and notify the parent about height changes
|
||||||
<AccordionSummary
|
const updateHeight = () => {
|
||||||
expandIcon={<ExpandMoreIcon />}
|
if (containerRef.current) {
|
||||||
aria-controls="beamline-content"
|
const newHeight = containerRef.current.offsetHeight;
|
||||||
id="beamline-header"
|
if (newHeight !== currentHeight) {
|
||||||
>
|
setCurrentHeight(newHeight);
|
||||||
<Typography><strong>Beamline Details</strong></Typography>
|
if (onHeightChange) {
|
||||||
</AccordionSummary>
|
onHeightChange(newHeight);
|
||||||
<AccordionDetails>
|
}
|
||||||
<Typography>Synchrotron: {beamline_parameters?.synchrotron || 'N/A'}</Typography>
|
}
|
||||||
<Typography>Ring mode: {beamline_parameters?.ringMode || 'N/A'}</Typography>
|
}
|
||||||
<Typography>Ring current: {beamline_parameters?.ringCurrent_A || 'N/A'}</Typography>
|
};
|
||||||
<Typography>Beamline: {beamline_parameters?.beamline || 'N/A'}</Typography>
|
|
||||||
<Typography>Undulator: {beamline_parameters?.undulator || 'N/A'}</Typography>
|
|
||||||
<Typography>Undulator gap: {beamline_parameters?.undulatorgap_mm || 'N/A'}</Typography>
|
|
||||||
<Typography>Focusing optic: {beamline_parameters?.focusingOptic || 'N/A'}</Typography>
|
|
||||||
<Typography>Monochromator: {beamline_parameters?.monochromator || 'N/A'}</Typography>
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion>
|
|
||||||
|
|
||||||
<Accordion>
|
useEffect(() => {
|
||||||
<AccordionSummary
|
updateHeight(); // Update height on initial render
|
||||||
expandIcon={<ExpandMoreIcon />}
|
}, []);
|
||||||
aria-controls="beam-content"
|
|
||||||
id="beam-header"
|
|
||||||
>
|
|
||||||
<Typography><strong>Beam characteristics</strong></Typography>
|
|
||||||
</AccordionSummary>
|
|
||||||
<AccordionDetails>
|
|
||||||
<Typography>Wavelength: {beamline_parameters?.wavelength || 'N/A'}</Typography>
|
|
||||||
<Typography>Energy: {beamline_parameters?.energy || 'N/A'}</Typography>
|
|
||||||
<Typography>Transmission: {beamline_parameters?.transmission || 'N/A'}</Typography>
|
|
||||||
<Typography>Beam focus (µm): vertical: {beamline_parameters?.beamSizeHeight || 'N/A'} , horizontal: {beamline_parameters?.beamSizeWidth || 'N/A'}</Typography>
|
|
||||||
<Typography>Flux at sample (ph/s): {beamline_parameters?.beamlineFluxAtSample_ph_s || 'N/A'}</Typography>
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion>
|
|
||||||
|
|
||||||
<Accordion>
|
useEffect(() => {
|
||||||
<AccordionSummary
|
// Update height whenever the component content changes
|
||||||
expandIcon={<ExpandMoreIcon />}
|
const observer = new ResizeObserver(updateHeight);
|
||||||
aria-controls="sample-content"
|
if (containerRef.current) {
|
||||||
id="sample-header"
|
observer.observe(containerRef.current);
|
||||||
>
|
}
|
||||||
<Typography><strong>Sample environment</strong></Typography>
|
return () => {
|
||||||
</AccordionSummary>
|
observer.disconnect();
|
||||||
<AccordionDetails>
|
};
|
||||||
<Typography>Cryojet temperature (K): {beamline_parameters?.cryojetTemperature_K || 'N/A'}</Typography>
|
}, [containerRef]);
|
||||||
<Typography>Humidifier temperature (K): {beamline_parameters?.humidifierTemperature_K || 'N/A'}</Typography>
|
|
||||||
<Typography>Humidifier humidity (%): {beamline_parameters?.humidifierHumidity || 'N/A'}</Typography>
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion>
|
|
||||||
|
|
||||||
<Accordion>
|
return (
|
||||||
<AccordionSummary
|
<div
|
||||||
expandIcon={<ExpandMoreIcon />}
|
ref={containerRef} // Attach the ref to the main container
|
||||||
aria-controls="images-content"
|
style={{
|
||||||
id="images-header"
|
display: 'flex',
|
||||||
>
|
gap: '16px',
|
||||||
<Typography><strong>Associated Images</strong></Typography>
|
padding: '16px',
|
||||||
</AccordionSummary>
|
border: '1px solid #ccc',
|
||||||
<AccordionDetails>
|
borderRadius: '4px',
|
||||||
{run.images?.map((img) => (
|
alignItems: 'flex-start',
|
||||||
<img
|
}}
|
||||||
key={img.id}
|
>
|
||||||
src={img.filepath}
|
{/* Main Details Section */}
|
||||||
alt={img.comment || 'Sample Image'}
|
<div style={{ flexGrow: 1 }}>
|
||||||
style={{
|
<Typography variant="h6" gutterBottom>
|
||||||
width: '100%',
|
Run {run.run_number} Details
|
||||||
border: '1px solid #ccc',
|
</Typography>
|
||||||
marginTop: 8,
|
<Typography variant="subtitle1" gutterBottom>
|
||||||
}}
|
Beamline: {beamline} | Synchrotron: {synchrotron}
|
||||||
/>
|
</Typography>
|
||||||
)) || 'No Images Available'}
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RunDetails;
|
{/* Detector Details Accordion */}
|
||||||
|
<Accordion>
|
||||||
|
<AccordionSummary
|
||||||
|
expandIcon={<ExpandMoreIcon />}
|
||||||
|
aria-controls="detector-content"
|
||||||
|
id="detector-header"
|
||||||
|
>
|
||||||
|
<Typography>
|
||||||
|
<strong>Detector Details</strong>
|
||||||
|
</Typography>
|
||||||
|
</AccordionSummary>
|
||||||
|
<AccordionDetails>
|
||||||
|
<Typography>Manufacturer: {detector?.manufacturer || 'N/A'}</Typography>
|
||||||
|
<Typography>Model: {detector?.model || 'N/A'}</Typography>
|
||||||
|
<Typography>Type: {detector?.type || 'N/A'}</Typography>
|
||||||
|
<Typography>
|
||||||
|
Beam Center (px): x: {detector?.beamCenterX_px || 'N/A'}, y: {detector?.beamCenterY_px || 'N/A'}
|
||||||
|
</Typography>
|
||||||
|
</AccordionDetails>
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
|
{/* Beamline Details Accordion */}
|
||||||
|
<Accordion>
|
||||||
|
<AccordionSummary
|
||||||
|
expandIcon={<ExpandMoreIcon />}
|
||||||
|
aria-controls="beamline-content"
|
||||||
|
id="beamline-header"
|
||||||
|
>
|
||||||
|
<Typography>
|
||||||
|
<strong>Beamline Details</strong>
|
||||||
|
</Typography>
|
||||||
|
</AccordionSummary>
|
||||||
|
<AccordionDetails>
|
||||||
|
<Typography>Synchrotron: {beamline_parameters?.synchrotron || 'N/A'}</Typography>
|
||||||
|
<Typography>Ring mode: {beamline_parameters?.ringMode || 'N/A'}</Typography>
|
||||||
|
<Typography>Ring current: {beamline_parameters?.ringCurrent_A || 'N/A'}</Typography>
|
||||||
|
<Typography>Beamline: {beamline_parameters?.beamline || 'N/A'}</Typography>
|
||||||
|
<Typography>Undulator: {beamline_parameters?.undulator || 'N/A'}</Typography>
|
||||||
|
<Typography>Undulator gap: {beamline_parameters?.undulatorgap_mm || 'N/A'}</Typography>
|
||||||
|
<Typography>Focusing optic: {beamline_parameters?.focusingOptic || 'N/A'}</Typography>
|
||||||
|
<Typography>Monochromator: {beamline_parameters?.monochromator || 'N/A'}</Typography>
|
||||||
|
</AccordionDetails>
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
|
{/* Beam Characteristics Accordion */}
|
||||||
|
<Accordion>
|
||||||
|
<AccordionSummary
|
||||||
|
expandIcon={<ExpandMoreIcon />}
|
||||||
|
aria-controls="beam-content"
|
||||||
|
id="beam-header"
|
||||||
|
>
|
||||||
|
<Typography>
|
||||||
|
<strong>Beam Characteristics</strong>
|
||||||
|
</Typography>
|
||||||
|
</AccordionSummary>
|
||||||
|
<AccordionDetails>
|
||||||
|
<Typography>Wavelength: {beamline_parameters?.wavelength || 'N/A'}</Typography>
|
||||||
|
<Typography>Energy: {beamline_parameters?.energy || 'N/A'}</Typography>
|
||||||
|
<Typography>Transmission: {beamline_parameters?.transmission || 'N/A'}</Typography>
|
||||||
|
<Typography>
|
||||||
|
Beam focus (µm): vertical: {beamline_parameters?.beamSizeHeight || 'N/A'}, horizontal:{' '}
|
||||||
|
{beamline_parameters?.beamSizeWidth || 'N/A'}
|
||||||
|
</Typography>
|
||||||
|
<Typography>Flux at sample (ph/s): {beamline_parameters?.beamlineFluxAtSample_ph_s || 'N/A'}</Typography>
|
||||||
|
</AccordionDetails>
|
||||||
|
</Accordion>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Image Section */}
|
||||||
|
<div style={{ width: '900px' }}>
|
||||||
|
<Typography variant="h6" gutterBottom>
|
||||||
|
Associated Images
|
||||||
|
</Typography>
|
||||||
|
{images && images.length > 0 ? (
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
{images.map((img) => (
|
||||||
|
<Grid item xs={6} key={img.id}>
|
||||||
|
<div className="image-container">
|
||||||
|
<img
|
||||||
|
src={img.filepath}
|
||||||
|
alt={img.comment || 'Image'}
|
||||||
|
className="zoom-image"
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: '100%',
|
||||||
|
borderRadius: '4px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
) : (
|
||||||
|
<Typography variant="body2" color="textSecondary">
|
||||||
|
No images available.
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RunDetails;
|
Loading…
x
Reference in New Issue
Block a user