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 [rows, setRows] = useState<TreeRow[]>([]);
|
||||
const [basePath, setBasePath] = useState('');
|
||||
const [detailPanelHeights, setDetailPanelHeights] = useState<{ [key: string]: number }>({}); // Store dynamic heights
|
||||
|
||||
const hasProcessingResults = (row: TreeRow): boolean => {
|
||||
// You can later replace this placeholder with actual logic.
|
||||
// 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) => {
|
||||
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;
|
||||
};
|
||||
|
||||
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 (
|
||||
<DataGridPremium
|
||||
rows={rows}
|
||||
|
@ -1,18 +1,68 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionSummary,
|
||||
AccordionDetails,
|
||||
Typography,
|
||||
} from '@mui/material';
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
Grid,
|
||||
} from '@mui/material';
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import './SampleImage.css';
|
||||
|
||||
const RunDetails: React.FC<RunDetailsProps> = ({ run }) => {
|
||||
const { beamline_parameters } = run;
|
||||
interface RunDetailsProps {
|
||||
run: ExperimentParameters;
|
||||
onHeightChange?: (height: number) => void; // Callback to notify the parent about height changes
|
||||
}
|
||||
|
||||
const RunDetails: React.FC<RunDetailsProps> = ({ run, onHeightChange }) => {
|
||||
const containerRef = useRef<HTMLDivElement | null>(null); // Ref to track component height
|
||||
const [currentHeight, setCurrentHeight] = useState<number>(0);
|
||||
|
||||
const { beamline_parameters, images } = run;
|
||||
const { synchrotron, beamline, detector } = beamline_parameters;
|
||||
|
||||
// Calculate and notify the parent about height changes
|
||||
const updateHeight = () => {
|
||||
if (containerRef.current) {
|
||||
const newHeight = containerRef.current.offsetHeight;
|
||||
if (newHeight !== currentHeight) {
|
||||
setCurrentHeight(newHeight);
|
||||
if (onHeightChange) {
|
||||
onHeightChange(newHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
updateHeight(); // Update height on initial render
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Update height whenever the component content changes
|
||||
const observer = new ResizeObserver(updateHeight);
|
||||
if (containerRef.current) {
|
||||
observer.observe(containerRef.current);
|
||||
}
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
};
|
||||
}, [containerRef]);
|
||||
|
||||
return (
|
||||
<div style={{ padding: '16px', border: '1px solid #ccc', borderRadius: '4px' }}>
|
||||
<div
|
||||
ref={containerRef} // Attach the ref to the main container
|
||||
style={{
|
||||
display: 'flex',
|
||||
gap: '16px',
|
||||
padding: '16px',
|
||||
border: '1px solid #ccc',
|
||||
borderRadius: '4px',
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
{/* Main Details Section */}
|
||||
<div style={{ flexGrow: 1 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Run {run.run_number} Details
|
||||
</Typography>
|
||||
@ -20,13 +70,16 @@
|
||||
Beamline: {beamline} | Synchrotron: {synchrotron}
|
||||
</Typography>
|
||||
|
||||
{/* Detector Details Accordion */}
|
||||
<Accordion>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon />}
|
||||
aria-controls="detector-content"
|
||||
id="detector-header"
|
||||
>
|
||||
<Typography><strong>Detector Details</strong></Typography>
|
||||
<Typography>
|
||||
<strong>Detector Details</strong>
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Typography>Manufacturer: {detector?.manufacturer || 'N/A'}</Typography>
|
||||
@ -38,13 +91,16 @@
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
||||
{/* Beamline Details Accordion */}
|
||||
<Accordion>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon />}
|
||||
aria-controls="beamline-content"
|
||||
id="beamline-header"
|
||||
>
|
||||
<Typography><strong>Beamline Details</strong></Typography>
|
||||
<Typography>
|
||||
<strong>Beamline Details</strong>
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Typography>Synchrotron: {beamline_parameters?.synchrotron || 'N/A'}</Typography>
|
||||
@ -58,63 +114,62 @@
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
||||
{/* Beam Characteristics Accordion */}
|
||||
<Accordion>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon />}
|
||||
aria-controls="beam-content"
|
||||
id="beam-header"
|
||||
>
|
||||
<Typography><strong>Beam characteristics</strong></Typography>
|
||||
<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>
|
||||
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>
|
||||
|
||||
<Accordion>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon />}
|
||||
aria-controls="sample-content"
|
||||
id="sample-header"
|
||||
>
|
||||
<Typography><strong>Sample environment</strong></Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Typography>Cryojet temperature (K): {beamline_parameters?.cryojetTemperature_K || 'N/A'}</Typography>
|
||||
<Typography>Humidifier temperature (K): {beamline_parameters?.humidifierTemperature_K || 'N/A'}</Typography>
|
||||
<Typography>Humidifier humidity (%): {beamline_parameters?.humidifierHumidity || 'N/A'}</Typography>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
||||
<Accordion>
|
||||
<AccordionSummary
|
||||
expandIcon={<ExpandMoreIcon />}
|
||||
aria-controls="images-content"
|
||||
id="images-header"
|
||||
>
|
||||
<Typography><strong>Associated Images</strong></Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
{run.images?.map((img) => (
|
||||
{/* 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
|
||||
key={img.id}
|
||||
src={img.filepath}
|
||||
alt={img.comment || 'Sample Image'}
|
||||
alt={img.comment || 'Image'}
|
||||
className="zoom-image"
|
||||
style={{
|
||||
width: '100%',
|
||||
border: '1px solid #ccc',
|
||||
marginTop: 8,
|
||||
maxWidth: '100%',
|
||||
borderRadius: '4px',
|
||||
}}
|
||||
/>
|
||||
)) || 'No Images Available'}
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</div>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
) : (
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
No images available.
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
export default RunDetails;
|
||||
export default RunDetails;
|
Loading…
x
Reference in New Issue
Block a user