Add default values to optional fields in SampleUpdate

This commit is contained in:
GotthardG
2025-01-09 22:51:26 +01:00
parent ac38bc3bb6
commit 0f6759e417
4 changed files with 213 additions and 64 deletions

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState } from "react";
import { DataGrid, GridColDef, GridCellEditStopParams } from "@mui/x-data-grid";
import { DataGrid, GridColDef, GridCellEditStopParams, GridRowModel } from "@mui/x-data-grid";
import { DewarsService } from "../../openapi";
interface SampleSpreadsheetProps {
@ -34,6 +34,24 @@ const SampleSpreadsheet: React.FC<SampleSpreadsheetProps> = ({ dewarId }) => {
totalrange,
transmission,
dose,
targetresolution,
aperture,
datacollectiontype,
processingpipeline,
spacegroupnumber,
cellparameters,
rescutkey,
rescutvalue,
userresolution,
pdbid,
autoprocfull,
procfull,
adpenabled,
noano,
ffcscampaig,
trustedhigh,
autoprocextraparams,
chiphiangles
} = sample.data_collection_parameters || {};
allRows.push({
@ -53,7 +71,24 @@ const SampleSpreadsheet: React.FC<SampleSpreadsheetProps> = ({ dewarId }) => {
totalRange: totalrange || null,
transmission: transmission || null,
dose: dose || null,
dataCollectionParameters: sample.data_collection_parameters || {}, // Ensure this is never undefined
targetresolution: targetresolution || null,
aperture: aperture || null,
datacollectiontype: datacollectiontype || null,
processingpipeline: processingpipeline || null,
spacegroupnumber: spacegroupnumber || null,
cellparameters: cellparameters || {},
rescutkey: rescutkey || null,
rescutvalue: rescutvalue || null,
userresolution: userresolution || null,
pdbid: pdbid || null,
autoprocfull: autoprocfull || null,
procfull: procfull || null,
adpenabled: adpenabled || null,
noano: noano || null,
ffcscampaig: ffcscampaig || null,
trustedhigh: trustedhigh || null,
autoprocextraparams: autoprocextraparams || {},
chiphiangles: chiphiangles || null,
});
});
});
@ -62,30 +97,38 @@ const SampleSpreadsheet: React.FC<SampleSpreadsheetProps> = ({ dewarId }) => {
// Define columns for the grid
setColumns([
{ field: "dewarName", headerName: "Dewar Name", width: 150, editable: false },
{ field: "puckName", headerName: "Puck Name", width: 150 },
{ field: "puckType", headerName: "Puck Type", width: 150 },
{ field: "crystalName", headerName: "Crystal Name", width: 200, editable: true },
{ field: "proteinName", headerName: "Protein Name", width: 200, editable: true },
{ field: "dewarName", headerName: "Dewar Name", width: 150, editable: false }, // not editable for now
{ field: "puckName", headerName: "Puck Name", width: 150, editable: false }, // not editable for now
{ field: "puckType", headerName: "Puck Type", width: 150, editable: false }, // not editable for now
{ field: "crystalName", headerName: "Crystal Name", width: 200, editable: false }, // not editable for now
{ field: "proteinName", headerName: "Protein Name", width: 200, editable: false }, // not editable for now
{ field: "position", headerName: "Position", width: 100, editable: true, type: "number" },
{ field: "priority", headerName: "Priority", width: 100, editable: true, type: "number" },
{ field: "comments", headerName: "Comments", width: 300, editable: true },
{ field: "directory", headerName: "Directory", width: 200 },
{ field: "directory", headerName: "Directory", width: 200, editable: true },
{ field: "oscillation", headerName: "Oscillation", width: 150, editable: true, type: "number" },
{ field: "exposure", headerName: "Exposure", width: 150, editable: true, type: "number" },
{ field: "totalRange", headerName: "Total Range", width: 150, editable: true, type: "number" },
{ field: "transmission", headerName: "Transmission", width: 150, editable: true, type: "number" },
{ field: "dose", headerName: "Dose", width: 150, editable: true, type: "number" },
{
field: "dataCollectionParameters",
headerName: "Data Collection Parameters (Raw)",
width: 300,
valueGetter: (params) =>
params.row?.dataCollectionParameters
? JSON.stringify(params.row.dataCollectionParameters)
: "N/A", // Fallback if undefined
editable: false,
},
{ field: "targetresolution", headerName: "Target Resolution", width: 150, editable: true, type: "number" },
{ field: "aperture", headerName: "Aperture", width: 150, editable: true },
{ field: "datacollectiontype", headerName: "Data Collection Type", width: 200, editable: true },
{ field: "processingpipeline", headerName: "Processing Pipeline", width: 200, editable: true },
{ field: "spacegroupnumber", headerName: "Space Group Number", width: 200, editable: true },
{ field: "cellparameters", headerName: "Cell Parameters", width: 300, editable: true },
{ field: "rescutkey", headerName: "ResCut Key", width: 150, editable: true },
{ field: "rescutvalue", headerName: "ResCut Value", width: 150, editable: true, editable: true },
{ field: "userresolution", headerName: "User Resolution", width: 150, editable: true, editable: true },
{ field: "pdbid", headerName: "PDB ID", width: 150, editable: true },
{ field: "autoprocfull", headerName: "AutoProc Full", width: 200, editable: true },
{ field: "procfull", headerName: "Proc Full", width: 200, editable: true },
{ field: "adpenabled", headerName: "ADP Enabled", width: 150, editable: true },
{ field: "noano", headerName: "No Anomalous", width: 150, editable: true },
{ field: "ffcscampaig", headerName: "FFCS Campaign", width: 150, editable: true },
{ field: "trustedhigh", headerName: "Trusted High", width: 150, editable: true },
{ field: "autoprocextraparams", headerName: "AutoProc Extra Params", width: 300, editable: true },
{ field: "chiphiangles", headerName: "Chi Phi Angles", width: 150, editable: true },
]);
} catch (error) {
console.error("Error fetching dewar samples:", error);
@ -98,19 +141,112 @@ const SampleSpreadsheet: React.FC<SampleSpreadsheetProps> = ({ dewarId }) => {
// Handle cell editing to persist changes to the backend
const handleCellEditStop = async (params: GridCellEditStopParams) => {
const { id, field, value } = params;
// Validation to ensure we have valid data from the cell edit
if (!id || !field || value === undefined) {
console.error("Invalid edit inputs");
console.error("Invalid edit inputs:", { id, field, value });
return;
}
// Fetch the current row data (old state) based on its ID
const updatedRow = rows.find((row) => row.id === id);
if (!updatedRow) {
console.error("Row not found for ID:", id);
return;
}
// Create the updated sample, force-overwriting the changed cell value
const updatedSample = {
...updatedRow, // Include other fields from the existing row
[field]: value, // Explicitly overwrite the updated field with new value
};
console.log("Payload sent to the backend:", updatedSample); // Log fixed payload
try {
// Call the update_sample API endpoint
await DewarsService.updateSampleSampleIdPut(id as number, {
[field]: value,
});
console.log("Sample updated successfully");
// Optimistically update UI for better experience
setRows((prevRows) =>
prevRows.map((row) =>
row.id === id ? { ...row, [field]: value } : row
)
);
// API call to persist changes
await DewarsService.updateSampleDewarsSamplesSampleIdPut(Number(id), updatedSample);
console.log(`Sample with ID ${id} successfully updated.`);
} catch (error) {
console.error(`Error updating sample (id: ${id}):`, error);
console.error(`Failed to update sample with ID ${id}:`, error);
// Revert optimistic update on error
setRows((prevRows) =>
prevRows.map((row) => (row.id === id ? updatedRow : row))
);
}
};
const processRowUpdate = async (newRow: GridRowModel, oldRow: GridRowModel) => {
try {
console.log("Old row:", oldRow); // Log the original row
console.log("Updated row:", newRow); // Log the updated data from the grid
// Reconstruct 'data_collection_parameters' from the flat table structure
const updatedDataCollectionParameters = {
...(oldRow.data_collection_parameters || {}), // Preserve old values
directory: newRow.directory ?? oldRow.data_collection_parameters?.directory,
oscillation: newRow.oscillation ?? oldRow.data_collection_parameters?.oscillation,
exposure: newRow.exposure ?? oldRow.data_collection_parameters?.exposure,
totalrange: newRow.totalRange ?? oldRow.data_collection_parameters?.totalrange,
transmission: newRow.transmission ?? oldRow.data_collection_parameters?.transmission,
dose: newRow.dose ?? oldRow.data_collection_parameters?.dose,
targetresolution: newRow.targetresolution ?? oldRow.data_collection_parameters?.targetresolution,
aperture: newRow.aperture ?? oldRow.data_collection_parameters?.aperture,
datacollectiontype: newRow.datacollectiontype ?? oldRow.data_collection_parameters?.datacollectiontype,
processingpipeline: newRow.processingpipeline ?? oldRow.data_collection_parameters?.processingpipeline,
spacegroupnumber: newRow.spacegroupnumber ?? oldRow.data_collection_parameters?.spacegroupnumber,
//cellparameters: newRow.cellparameters ?? oldRow.data_collection_parameters?.cellparameters,
rescutkey: newRow.rescutkey ?? oldRow.data_collection_parameters?.rescutkey,
rescutvalue: newRow.rescutvalue ?? oldRow.data_collection_parameters?.rescutvalue,
userresolution: newRow.userresolution ?? oldRow.data_collection_parameters?.userresolution,
pdbid: newRow.pdbid ?? oldRow.data_collection_parameters?.pdbid,
autoprocfull: newRow.autoprocfull ?? oldRow.data_collection_parameters?.autoprocfull,
procfull: newRow.procfull ?? oldRow.data_collection_parameters?.procfull,
adpenabled: newRow.adpenabled ?? oldRow.data_collection_parameters?.adpenabled,
noano: newRow.noano ?? oldRow.data_collection_parameters?.noano,
ffcscampaig: newRow.ffcscampaig ?? oldRow.data_collection_parameters?.ffcscampaig,
trustedhigh: newRow.trustedhigh ?? oldRow.data_collection_parameters?.trustedhigh,
//autoprocextraparams: newRow.autoprocextraparams ?? oldRow.data_collection_parameters?.autoprocextraparams,
chiphiangles: newRow.chiphiangles ?? oldRow.data_collection_parameters?.chiphiangles,
};
// Assemble the final payload
const payload = {
...oldRow, // Include all original fields
...newRow, // Overwrite or add updated fields
data_collection_parameters: updatedDataCollectionParameters, // Include the merged/validated structure
};
console.log("Final payload sent to backend:", payload);
// Optimistically update the UI
setRows((prevRows) =>
prevRows.map((row) =>
row.id === newRow.id ? { ...row, ...payload } : row
)
);
// Send the payload to the backend
await DewarsService.updateSampleDewarsSamplesSampleIdPut(Number(newRow.id), payload);
console.log(`Successfully updated sample with ID ${newRow.id}.`);
return payload; // Return the updated row
} catch (error) {
console.error(`Failed to update sample with ID ${newRow.id}:`, error);
// On failure, revert to the old row
return oldRow;
}
};
@ -120,7 +256,7 @@ const SampleSpreadsheet: React.FC<SampleSpreadsheetProps> = ({ dewarId }) => {
rows={rows}
columns={columns}
pageSize={10}
onCellEditStop={handleCellEditStop}
processRowUpdate={processRowUpdate} // Exclusively handle updates
/>
</div>
);