now creating dewars, pucks and samples from spreadsheet and replacing dewars if a dewar with the same name exists

This commit is contained in:
GotthardG
2024-11-12 17:03:38 +01:00
parent 86883133a7
commit 8f7c90bab0
5 changed files with 327 additions and 134 deletions

View File

@ -11,7 +11,12 @@ import {
TextField,
Typography,
Button,
Box
Box,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle
} from '@mui/material';
import { SpreadsheetService, ShipmentsService, DewarsService, ApiError } from '../../openapi';
import * as ExcelJS from 'exceljs';
@ -30,6 +35,9 @@ const SpreadsheetTable = ({
const [editingCell, setEditingCell] = useState({});
const [nonEditableCells, setNonEditableCells] = useState(new Set());
const [isSubmitting, setIsSubmitting] = useState(false);
const [showUpdateDialog, setShowUpdateDialog] = useState(false);
const [dewarsToReplace, setDewarsToReplace] = useState([]);
const [dewarsToCreate, setDewarsToCreate] = useState(new Map());
const initialNewDewarState = {
number_of_pucks: 0,
@ -44,7 +52,7 @@ const SpreadsheetTable = ({
dewar_name: '',
tracking_number: 'UNKNOWN',
status: 'In preparation',
pucks: []
pucks: [] // Ensure 'pucks' array exists
};
const [newDewar, setNewDewar] = useState(initialNewDewarState);
@ -141,36 +149,80 @@ const SpreadsheetTable = ({
'dewarname': 0,
'puckname': 1,
'pucktype': 2,
// Add other fields as needed
'crystalname': 3,
'positioninpuck': 4,
'priority': 5,
'comments': 6,
'directory': 7,
'proteinname': 8,
'oscillation': 9,
'aperture': 10,
'exposure': 11,
'totalrange': 12,
'transmission': 13,
'dose': 14,
'targetresolution': 15,
'datacollectiontype': 16,
'processingpipeline': 17,
'spacegroupnumber': 18,
'cellparameters': 19,
'rescutkey': 20,
'rescutvalue': 21,
'userresolution': 22,
'pdbid': 23,
'autoprocfull': 24,
'procfull': 25,
'adpenabled': 26,
'noano': 27,
'ffcscampaign': 28,
'trustedhigh': 29,
'autoprocextraparams': 30,
'chiphiangles': 31
};
const createDewarsFromSheet = async (data, contactPerson, returnAddress) => {
const checkIfDewarExists = async (dewarName) => {
if (!selectedShipment) return null;
try {
const shipDewars = await ShipmentsService.getDewarsByShipmentIdShipmentsShipmentIdDewarsGet(selectedShipment.id);
return shipDewars.find((d) => d.dewar_name === dewarName);
} catch (error) {
console.error('Failed to fetch existing dewars:', error);
return null;
}
};
const createOrUpdateDewarsFromSheet = async (data, contactPerson, returnAddress) => {
if (!contactPerson?.id || !returnAddress?.id) {
console.error('contact_person_id or return_address_id is missing');
return null;
}
const dewars = new Map();
const puckPositionMap = new Map();
const dewarsToReplace = [];
const dewarNameIdx = fieldToCol['dewarname'];
const puckNameIdx = fieldToCol['puckname'];
const puckTypeIdx = fieldToCol['pucktype'];
const sampleNameIdx = fieldToCol['crystalname'];
const samplePositionIdx = fieldToCol['positioninpuck'];
let puckPositionInDewar = 1;
for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {
const row = data[rowIndex];
for (const row of data) {
if (!row.data) {
console.error(`Row data is missing`);
console.error('Row data is missing');
continue;
}
const dewarName = typeof row.data[dewarNameIdx] === 'string' ? row.data[dewarNameIdx].trim() : null;
const puckName = typeof row.data[puckNameIdx] === 'string' ? row.data[puckNameIdx].trim() : null;
const puckName = row.data[puckNameIdx] !== undefined && row.data[puckNameIdx] !== null ? String(row.data[puckNameIdx]).trim() : null;
const puckType = typeof row.data[puckTypeIdx] === 'string' ? row.data[puckTypeIdx] : 'Unipuck';
const sampleName = typeof row.data[sampleNameIdx] === 'string' ? row.data[sampleNameIdx].trim() : null;
const samplePosition = row.data[samplePositionIdx] !== undefined && row.data[samplePositionIdx] !== null ? Number(row.data[samplePositionIdx]) : null;
console.log(`Processing Dewar: ${dewarName}, Puck: ${puckName}, Type: ${puckType}`);
if (dewarName) {
if (dewarName && puckName) {
let dewar;
if (!dewars.has(dewarName)) {
dewar = {
@ -181,44 +233,116 @@ const SpreadsheetTable = ({
pucks: []
};
dewars.set(dewarName, dewar);
puckPositionInDewar = 1;
console.log(`Created new dewar: ${dewarName}`);
puckPositionMap.set(dewarName, new Map());
// Check if the dewar exists in the shipment
const existingDewar = await checkIfDewarExists(dewarName);
if (existingDewar) {
dewarsToReplace.push(existingDewar);
}
} else {
dewar = dewars.get(dewarName);
puckPositionInDewar++;
console.log(`Found existing dewar: ${dewarName}`);
}
const puck = {
puck_name: puckName || 'test', // Fixed puck name
puck_type: puckType || 'Unipuck', // Fixed puck type
puck_position_in_dewar: puckPositionInDewar
};
dewar.pucks.push(puck);
let puckPositions = puckPositionMap.get(dewarName);
if (!puckPositions.has(puckName)) {
puckPositions.set(puckName, puckPositions.size + 1);
}
const puckPosition = puckPositions.get(puckName);
console.log(`Added puck: ${JSON.stringify(puck)}`);
let puck = dewar.pucks.find(p => p.puck_name === puckName);
if (!puck) {
puck = {
puck_name: puckName,
puck_type: puckType,
puck_location_in_dewar: puckPosition,
samples: []
};
dewar.pucks.push(puck);
}
const sample = {
sample_name: sampleName,
position: samplePosition,
results: null // Placeholder for results field
};
if (isNaN(sample.position)) {
console.error(`Invalid sample position for sample ${sample.sample_name} in puck ${puckName}`);
} else {
puck.samples.push(sample);
}
} else {
console.error('Dewar name is missing in the row');
if (!dewarName) {
console.error(`Dewar name is missing in row ${rowIndex}`);
}
if (!puckName) {
console.error(`Puck name is missing in row ${rowIndex}`);
}
}
}
const dewarsArray = Array.from(dewars.values());
// Save dewars array for later use in handleConfirmUpdate
setDewarsToCreate(dewars);
if (dewarsArray.length > 0 && dewarsToReplace.length > 0) {
setDewarsToReplace(dewarsToReplace);
setShowUpdateDialog(true);
} else {
await handleDewarCreation(dewarsArray);
}
};
const handleConfirmUpdate = async () => {
if (dewarsToReplace.length === 0) return;
try {
for (const dewar of dewarsToReplace) {
await DewarsService.deleteDewarDewarsDewarIdDelete(dewar.id);
}
const dewarsArray = Array.from(dewarsToCreate.values());
await handleDewarCreation(dewarsArray);
console.log('Dewars replaced successfully');
} catch (error) {
console.error('Error replacing dewar', error);
if (error instanceof ApiError && error.body) {
console.error('Validation errors:', error.body.detail);
} else {
console.error('Unexpected error:', error);
}
}
setShowUpdateDialog(false);
setDewarsToReplace([]);
setDewarsToCreate(new Map());
};
const handleCancelUpdate = () => {
setShowUpdateDialog(false);
setDewarsToReplace([]);
setDewarsToCreate(new Map());
};
const handleDewarCreation = async (dewarsArray) => {
for (const dewar of dewarsArray) {
try {
// Call to create the dewar
const createdDewar = await DewarsService.createDewarDewarsPost(dewar);
console.log(`Created dewar: ${createdDewar.id}`);
if (!dewar.pucks || dewar.pucks.length === 0) {
console.error(`Dewar ${dewar.dewar_name} does not have any pucks.`);
continue;
}
const createdDewar = await DewarsService.createDewarDewarsPost(dewar);
// Add dewar to the shipment if created successfully
if (createdDewar && selectedShipment) {
await ShipmentsService.addDewarToShipmentShipmentsShipmentIdAddDewarPost(
selectedShipment.id,
createdDewar.id
);
console.log(`Added dewar to shipment: ${createdDewar.id}`);
console.log(`Dewar ${createdDewar.dewar_name} with ID ${createdDewar.id} created and added to the shipment.`);
}
} catch (error) {
console.error(`Error adding dewar`, error);
console.error('Error adding dewar', error);
if (error instanceof ApiError && error.body) {
console.error('Validation errors:', error.body.detail);
} else {
@ -226,8 +350,6 @@ const SpreadsheetTable = ({
}
}
}
return dewarsArray;
};
const handleSubmit = async () => {
@ -241,18 +363,12 @@ const SpreadsheetTable = ({
setIsSubmitting(true);
console.log('All data is valid. Proceeding with submission...');
const processedDewars = await createDewarsFromSheet(
await createOrUpdateDewarsFromSheet(
raw_data,
selectedShipment?.contact_person,
selectedShipment?.return_address
);
if (processedDewars && processedDewars.length > 0) {
console.log('Dewars processed successfully.');
} else {
console.error('No valid dewars were created.');
}
setIsSubmitting(false);
} else {
console.log('There are validation errors in the dataset. Please correct them before submission.');
@ -270,22 +386,12 @@ const SpreadsheetTable = ({
});
});
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
saveAs(blob, 'corrected_data.xlsx');
workbook.xlsx.writeBuffer().then((buffer) => {
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
saveAs(blob, 'corrected_spreadsheet.xlsx');
});
};
useEffect(() => {
console.log('Raw data:', raw_data);
console.log('Errors:', localErrors);
console.log('Headers:', headers);
}, [raw_data, localErrors, headers]);
if (!raw_data || !headers) {
return <div>Loading...</div>;
}
return (
<TableContainer component={Paper}>
<Table>
@ -323,21 +429,25 @@ const SpreadsheetTable = ({
return (
<TableCell key={colIndex} align="center">
<Tooltip title={errorMessage || ""} arrow disableHoverListener={!isInvalid}>
<TextField
value={editingValue !== undefined ? editingValue : cellValue}
onChange={(e) => setEditingCell({ ...editingCell, [`${rowIndex}-${colIndex}`]: e.target.value })}
onKeyDown={(e) => {
if (e.key === "Enter") {
handleCellEdit(rowIndex, colIndex);
}
}}
onBlur={() => handleCellBlur(rowIndex, colIndex)}
error={isInvalid}
fullWidth
variant="outlined"
size="small"
disabled={isReadonly}
/>
{isInvalid ? (
<TextField
value={editingValue !== undefined ? editingValue : cellValue}
onChange={(e) => setEditingCell({ ...editingCell, [`${rowIndex}-${colIndex}`]: e.target.value })}
onKeyDown={(e) => {
if (e.key === "Enter") {
handleCellEdit(rowIndex, colIndex);
}
}}
onBlur={() => handleCellBlur(rowIndex, colIndex)}
error={isInvalid}
fullWidth
variant="outlined"
size="small"
disabled={isReadonly}
/>
) : (
cellValue
)}
</Tooltip>
</TableCell>
);
@ -346,6 +456,28 @@ const SpreadsheetTable = ({
))}
</TableBody>
</Table>
<Dialog
open={showUpdateDialog}
onClose={handleCancelUpdate}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Replace Dewars</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
The following dewars already exist: {dewarsToReplace.map(dewar => dewar.dewar_name).join(', ')}. Would you like to replace them?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleCancelUpdate} color="primary">
Cancel
</Button>
<Button onClick={handleConfirmUpdate} color="primary" autoFocus>
Replace
</Button>
</DialogActions>
</Dialog>
</TableContainer>
);
};