diff --git a/backend/app/routers/dewar.py b/backend/app/routers/dewar.py
index 5dd7b8c..ce7299e 100644
--- a/backend/app/routers/dewar.py
+++ b/backend/app/routers/dewar.py
@@ -595,14 +595,23 @@ async def assign_beamtime_to_dewar(
db: Session = Depends(get_db),
):
dewar = db.query(DewarModel).filter(DewarModel.id == dewar_id).first()
- if not dewar: # <- Move check earlier!
+ if not dewar:
raise HTTPException(status_code=404, detail="Dewar not found")
- if beamtime_id == 0:
- dewar.beamtime_id = None
- else:
- dewar.beamtime_id = beamtime_id
+
+ dewar.beamtime_id = None if beamtime_id == 0 else beamtime_id
db.commit()
db.refresh(dewar)
+ for puck in dewar.pucks:
+ puck.beamtime_id = None if beamtime_id == 0 else beamtime_id
+ for sample in puck.samples:
+ has_sample_event = (
+ db.query(SampleEvent).filter(SampleEvent.sample_id == sample.id).count()
+ > 0
+ )
+ if not has_sample_event:
+ sample.beamtime_id = None if beamtime_id == 0 else beamtime_id
+
+ db.commit()
return {"status": "success", "dewar_id": dewar.id, "beamtime_id": beamtime_id}
diff --git a/backend/app/routers/puck.py b/backend/app/routers/puck.py
index 953bd00..5da02dd 100644
--- a/backend/app/routers/puck.py
+++ b/backend/app/routers/puck.py
@@ -20,6 +20,7 @@ from app.models import (
Sample as SampleModel,
LogisticsEvent as LogisticsEventModel,
Dewar as DewarModel,
+ SampleEvent,
)
from app.dependencies import get_db
import logging
@@ -669,10 +670,16 @@ async def assign_beamtime_to_puck(
puck = db.query(PuckModel).filter(PuckModel.id == puck_id).first()
if not puck:
raise HTTPException(status_code=404, detail="Puck not found")
- if beamtime_id == 0:
- puck.beamtime_id = None
- else:
- puck.beamtime_id = beamtime_id
+
+ puck.beamtime_id = None if beamtime_id == 0 else beamtime_id
db.commit()
db.refresh(puck)
+ # Update samples
+ for sample in puck.samples:
+ has_sample_event = (
+ db.query(SampleEvent).filter(SampleEvent.sample_id == sample.id).count() > 0
+ )
+ if not has_sample_event:
+ sample.beamtime_id = None if beamtime_id == 0 else beamtime_id
+ db.commit()
return {"status": "success", "puck_id": puck.id, "beamtime_id": beamtime_id}
diff --git a/frontend/src/components/Calendar.tsx b/frontend/src/components/Calendar.tsx
index 3c06b7c..cbd6945 100644
--- a/frontend/src/components/Calendar.tsx
+++ b/frontend/src/components/Calendar.tsx
@@ -268,12 +268,11 @@ const Calendar: React.FC = () => {
return;
}
- // Find out if it's already assigned to this shift!
+ // Get current association state
const prev = eventAssociations[selectedEventId] || { dewars: [], pucks: [] };
const isAssigned = prev.pucks.includes(puckId);
if (!isAssigned) {
- // Assign it immediately
assignPuckToBeamtime(Number(puckId), Number(beamtimeId))
.then(() => {
setEventAssociations(prevAssoc => {
@@ -291,7 +290,6 @@ const Calendar: React.FC = () => {
console.error("Failed to assign puck to beamtime", e);
});
} else {
- // Unassign (patch to None) immediately
unassignPuckFromBeamtime(Number(puckId))
.then(() => {
setEventAssociations(prevAssoc => {
@@ -387,10 +385,8 @@ const Calendar: React.FC = () => {
Select Dewars
{shipments.map(dewar => {
- // Are *all* pucks assigned to this event? (Assigned at Dewar level)
- const thisEvent = eventAssociations[selectedEventId] || {dewars: [], pucks: []};
+ const thisEvent = eventAssociations[selectedEventId] || { dewars: [], pucks: [] };
const dewarAssigned = thisEvent.dewars.includes(dewar.id);
- const puckAssignments = thisEvent.pucks;
return (
-
@@ -405,8 +401,20 @@ const Calendar: React.FC = () => {
{!dewarAssigned && dewar.pucks && dewar.pucks.length > 0 && (
{(dewar.pucks || []).map(puck => {
- const isAssigned =
- !!eventAssociations[selectedEventId]?.pucks.includes(puck.id);
+ // Find eventId for this puck, if assigned
+ const associatedEventId = Object.keys(eventAssociations).find(eid =>
+ eventAssociations[eid]?.pucks.includes(puck.id)
+ );
+ const associatedEvent = associatedEventId
+ ? events.find(ev => ev.id === associatedEventId)
+ : null;
+
+ const associatedShift = associatedEvent?.beamtime_shift;
+ const associatedDate = associatedEvent?.start;
+ const associatedBeamline = associatedEvent?.beamline;
+
+ const currentShift = eventDetails?.beamtime_shift;
+ const isAssignedToCurrentShift = associatedShift && currentShift && associatedShift === currentShift;
return (
@@ -415,32 +423,67 @@ const Calendar: React.FC = () => {
type="button"
style={{
marginLeft: 8,
- background: isAssigned ? '#4CAF50' : '#e0e0e0',
- color: isAssigned ? 'white' : 'black',
- border: isAssigned ? '1px solid #388e3c' : '1px solid #bdbdbd',
+ background: isAssignedToCurrentShift ? '#4CAF50' : (associatedShift ? '#B3E5B3' : '#e0e0e0'),
+ color: isAssignedToCurrentShift ? 'white' : 'black',
+ border: isAssignedToCurrentShift ? '1px solid #388e3c' : '1px solid #bdbdbd',
borderRadius: 4,
padding: '4px 10px',
cursor: 'pointer',
transition: 'background 0.2s',
}}
- onClick={() => handlePuckAssignment(dewar.id, puck.id)}
+ onClick={() => handlePuckAssignment(puck.id)}
>
- {isAssigned ? puck.puck_name : puck.puck_name}
+ {puck.puck_name}
- {/* Optionally show assignment info, as before */}
- {findAssociatedEventForPuck(puck.id) && (
- ← Assigned to shift: {findAssociatedEventForPuck(puck.id)}
+ {associatedEvent && (
+
+ ← Assigned to shift: {associatedShift}
+ {associatedDate && (
+ <> on {new Date(associatedDate).toLocaleDateString()}>
+ )}
+ {associatedBeamline && (
+ <> ({associatedBeamline})>
+ )}
+
)}
);
})}
-
)}
- {/* Show associated shift, if any */}
- {findAssociatedEventForDewar(dewar.id) && (
- ← Assigned to shift: {findAssociatedEventForDewar(dewar.id)}
- )}
+ {/* Show associated shift, date, and beamline for Dewar, if any */}
+ {(() => {
+ const associatedEventId = Object.keys(eventAssociations).find(eid =>
+ eventAssociations[eid]?.dewars.includes(dewar.id)
+ );
+ const associatedEvent = associatedEventId
+ ? events.find(ev => ev.id === associatedEventId)
+ : null;
+ const associatedShift = associatedEvent?.beamtime_shift;
+ const associatedDate = associatedEvent?.start;
+ const associatedBeamline = associatedEvent?.beamline;
+
+ const currentShift = eventDetails?.beamtime_shift;
+ const isAssignedToCurrentShift = associatedShift && currentShift && associatedShift === currentShift;
+
+ return associatedEvent && (
+
+ ← Assigned to shift: {associatedShift}
+ {associatedDate && (
+ <> on {new Date(associatedDate).toLocaleDateString()}>
+ )}
+ {associatedBeamline && (
+ <> ({associatedBeamline})>
+ )}
+
+ );
+ })()}
);
})}