From 91aebae4737a940742857674ecf1ef72eedd0e1d Mon Sep 17 00:00:00 2001
From: GotthardG <51994228+GotthardG@users.noreply.github.com>
Date: Wed, 5 Mar 2025 11:13:20 +0100
Subject: [PATCH] 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.
---
 frontend/src/components/ResultGrid.tsx |  25 ++-
 frontend/src/components/RunDetails.tsx | 279 +++++++++++++++----------
 2 files changed, 190 insertions(+), 114 deletions(-)

diff --git a/frontend/src/components/ResultGrid.tsx b/frontend/src/components/ResultGrid.tsx
index 970720f..a3aa790 100644
--- a/frontend/src/components/ResultGrid.tsx
+++ b/frontend/src/components/ResultGrid.tsx
@@ -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}
diff --git a/frontend/src/components/RunDetails.tsx b/frontend/src/components/RunDetails.tsx
index d20380a..02cbf63 100644
--- a/frontend/src/components/RunDetails.tsx
+++ b/frontend/src/components/RunDetails.tsx
@@ -1,120 +1,175 @@
-   import React from 'react';
-   import {
-       Accordion,
-       AccordionSummary,
-       AccordionDetails,
-       Typography,
-   } from '@mui/material';
-   import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import React, { useEffect, useRef, useState } from 'react';
+import {
+    Accordion,
+    AccordionSummary,
+    AccordionDetails,
+    Typography,
+    Grid,
+} from '@mui/material';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import './SampleImage.css';
 
-   const RunDetails: React.FC<RunDetailsProps> = ({ run }) => {
-       const { beamline_parameters } = run;
-       const { synchrotron, beamline, detector } = beamline_parameters;
+interface RunDetailsProps {
+    run: ExperimentParameters;
+    onHeightChange?: (height: number) => void; // Callback to notify the parent about height changes
+}
 
-       return (
-           <div style={{ padding: '16px', border: '1px solid #ccc', borderRadius: '4px' }}>
-               <Typography variant="h6" gutterBottom>
-                   Run {run.run_number} Details
-               </Typography>
-               <Typography variant="subtitle1" gutterBottom>
-                   Beamline: {beamline} | Synchrotron: {synchrotron}
-               </Typography>
+const RunDetails: React.FC<RunDetailsProps> = ({ run, onHeightChange }) => {
+    const containerRef = useRef<HTMLDivElement | null>(null); // Ref to track component height
+    const [currentHeight, setCurrentHeight] = useState<number>(0);
 
-               <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>
+    const { beamline_parameters, images } = run;
+    const { synchrotron, beamline, detector } = beamline_parameters;
 
-               <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>
+    // 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);
+                }
+            }
+        }
+    };
 
-               <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>
+    useEffect(() => {
+        updateHeight(); // Update height on initial render
+    }, []);
 
-               <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>
+    useEffect(() => {
+        // Update height whenever the component content changes
+        const observer = new ResizeObserver(updateHeight);
+        if (containerRef.current) {
+            observer.observe(containerRef.current);
+        }
+        return () => {
+            observer.disconnect();
+        };
+    }, [containerRef]);
 
-               <Accordion>
-                   <AccordionSummary
-                       expandIcon={<ExpandMoreIcon />}
-                       aria-controls="images-content"
-                       id="images-header"
-                   >
-                       <Typography><strong>Associated Images</strong></Typography>
-                   </AccordionSummary>
-                   <AccordionDetails>
-                       {run.images?.map((img) => (
-                           <img
-                               key={img.id}
-                               src={img.filepath}
-                               alt={img.comment || 'Sample Image'}
-                               style={{
-                                   width: '100%',
-                                   border: '1px solid #ccc',
-                                   marginTop: 8,
-                               }}
-                           />
-                       )) || 'No Images Available'}
-                   </AccordionDetails>
-               </Accordion>
-           </div>
-       );
-   };
+    return (
+        <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>
+                <Typography variant="subtitle1" gutterBottom>
+                    Beamline: {beamline} | Synchrotron: {synchrotron}
+                </Typography>
 
-   export default RunDetails;
\ No newline at end of file
+                {/* 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;
\ No newline at end of file
-- 
GitLab