Add mount_count and unmount_count tracking for samples
Introduced `mount_count` and `unmount_count` fields to track mounting events for samples. Updated models, schemas, and front-end components to support dynamic calculation and display of these counts. Enhanced backend queries and API responses to include the new data.
This commit is contained in:
parent
3d804c1635
commit
3b315f2997
@ -151,6 +151,16 @@ class Sample(Base):
|
||||
puck = relationship("Puck", back_populates="samples")
|
||||
events = relationship("SampleEvent", back_populates="sample")
|
||||
|
||||
@property
|
||||
def mount_count(self) -> int:
|
||||
# Dynamically calculate mount_count
|
||||
return len([event for event in self.events if event.event_type == "Mounted"])
|
||||
|
||||
@property
|
||||
def unmount_count(self) -> int:
|
||||
# Dynamically calculate unmount_count
|
||||
return len([event for event in self.events if event.event_type == "Unmounted"])
|
||||
|
||||
|
||||
class Slot(Base):
|
||||
__tablename__ = "slots"
|
||||
|
@ -9,6 +9,7 @@ from app.schemas import (
|
||||
Sample as SampleSchema,
|
||||
SampleEventResponse,
|
||||
SampleEventCreate,
|
||||
Sample,
|
||||
)
|
||||
from app.models import (
|
||||
Puck as PuckModel,
|
||||
@ -17,6 +18,8 @@ from app.models import (
|
||||
)
|
||||
from app.dependencies import get_db
|
||||
import logging
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@ -43,22 +46,25 @@ async def get_samples_with_events(puck_id: int, db: Session = Depends(get_db)):
|
||||
async def get_all_pucks_with_samples_and_events(db: Session = Depends(get_db)):
|
||||
logging.info("Fetching all pucks with samples and events")
|
||||
|
||||
pucks = db.query(PuckModel).all()
|
||||
logging.info(f"Found {len(pucks)} pucks in the database")
|
||||
for puck in pucks:
|
||||
if puck.dewar_id is None:
|
||||
puck.dewar_id = -1
|
||||
logging.info(f"Puck ID: {puck.id}, Name: {puck.puck_name}")
|
||||
pucks = (
|
||||
db.query(PuckModel)
|
||||
.options(
|
||||
joinedload(PuckModel.samples).joinedload(
|
||||
SampleModel.events
|
||||
), # Correct nested relationship
|
||||
joinedload(PuckModel.events), # If Puck has its own events relationship
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
if not pucks:
|
||||
raise HTTPException(
|
||||
status_code=404, detail="No pucks found in the database"
|
||||
) # More descriptive
|
||||
raise HTTPException(status_code=404, detail="No pucks found in the database")
|
||||
|
||||
return pucks
|
||||
|
||||
|
||||
# Route to post a new sample event
|
||||
@router.post("/samples/{sample_id}/events", response_model=SampleEventResponse)
|
||||
@router.post("/samples/{sample_id}/events", response_model=Sample)
|
||||
async def create_sample_event(
|
||||
sample_id: int, event: SampleEventCreate, db: Session = Depends(get_db)
|
||||
):
|
||||
@ -77,10 +83,13 @@ async def create_sample_event(
|
||||
db.commit()
|
||||
db.refresh(sample_event)
|
||||
|
||||
return (
|
||||
sample_event # Response will automatically use the SampleEventResponse schema
|
||||
# Load events for the sample to be serialized in the response
|
||||
sample.events = (
|
||||
db.query(SampleEventModel).filter(SampleEventModel.sample_id == sample_id).all()
|
||||
)
|
||||
|
||||
return sample # Return the sample, now including `mount_count`
|
||||
|
||||
|
||||
# Route to fetch the last (most recent) sample event
|
||||
@router.get("/samples/{sample_id}/events/last", response_model=SampleEventResponse)
|
||||
|
@ -424,6 +424,9 @@ class Sample(BaseModel):
|
||||
comments: Optional[str] = None
|
||||
data_collection_parameters: Optional[DataCollectionParameters]
|
||||
events: List[SampleEventResponse] = []
|
||||
mount_count: Optional[int] = None
|
||||
unmount_count: Optional[int] = None
|
||||
# results: Optional[Results] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
@ -13,6 +13,8 @@ interface Sample {
|
||||
crystalname?: string;
|
||||
positioninpuck?: number;
|
||||
events: Event[];
|
||||
mount_count: number; // Add this
|
||||
unmount_count: number; // Add this
|
||||
}
|
||||
|
||||
interface Puck {
|
||||
@ -32,6 +34,8 @@ const SampleTracker: React.FC = () => {
|
||||
const fetchPucks = async () => {
|
||||
try {
|
||||
const data: Puck[] = await SamplesService.getAllPucksWithSamplesAndEventsSamplesPucksSamplesGet();
|
||||
|
||||
console.log('Fetched Pucks:', data); // Check for dynamic mount_count and unmount_count
|
||||
setPucks(data);
|
||||
} catch (error) {
|
||||
console.error('Error fetching pucks', error);
|
||||
@ -110,12 +114,29 @@ const SampleTracker: React.FC = () => {
|
||||
border: sample && sample.events.some((e) => e.event_type === 'Lost')
|
||||
? '1px solid red'
|
||||
: '1px solid lightgray',
|
||||
position: 'relative', // Add for overlay positioning
|
||||
}}
|
||||
onMouseEnter={() =>
|
||||
sample && setHoveredSample({ name: sample.sample_name, status })
|
||||
}
|
||||
onMouseLeave={() => setHoveredSample(null)}
|
||||
></div>
|
||||
>
|
||||
{sample && sample.mount_count > 0 && ( // Render only if mount_count > 0
|
||||
<span
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
color: 'white',
|
||||
fontSize: '8px',
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
>
|
||||
{sample.mount_count}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user