Update SampleTracker to support dynamic activePgroup

Enhanced the `SampleTracker` component to accept and utilize an `activePgroup` prop, allowing dynamic filtering of data based on the current project group. Adjusted related polling and data fetching logic to respond to changes in `activePgroup`. Removed excessive code from the test notebook for cleanup.
This commit is contained in:
GotthardG 2025-02-27 11:20:04 +01:00
parent 2f5cb3032a
commit 548a86678b
4 changed files with 46 additions and 22 deletions

View File

@ -46,23 +46,44 @@ async def get_samples_with_events(puck_id: int, db: Session = Depends(get_db)):
@router.get("/pucks-samples", response_model=List[PuckSchema]) @router.get("/pucks-samples", response_model=List[PuckSchema])
async def get_all_pucks_with_samples_and_events(db: Session = Depends(get_db)): async def get_all_pucks_with_samples_and_events(
logging.info("Fetching all pucks with samples and events") active_pgroup: str, db: Session = Depends(get_db)
):
logging.info(
"Fetching all pucks with " "samples and events for active_pgroup: %s",
active_pgroup,
)
pucks = ( pucks = (
db.query(PuckModel) db.query(PuckModel)
.join(PuckModel.samples) # Join samples related to the puck
.join(PuckModel.dewar) # Join the dewar from the puck
.join(SampleModel.events) # Join sample events
.filter(DewarModel.pgroups == active_pgroup) # Filter by the dewar's group
.options( .options(
joinedload(PuckModel.samples).joinedload( joinedload(PuckModel.samples).joinedload(SampleModel.events),
SampleModel.events joinedload(PuckModel.dewar),
), # Correct nested relationship
joinedload(PuckModel.events), # If Puck has its own events relationship
) )
.distinct() # Avoid duplicate puck rows if there are multiple events/samples
.all() .all()
) )
if not pucks: if not pucks:
raise HTTPException(status_code=404, detail="No pucks found in the database") raise HTTPException(
status_code=404,
detail="No pucks found with" " sample events for the active pgroup",
)
# Extract samples from each puck if needed
filtered_samples = []
for puck in pucks:
if puck.dewar and getattr(puck.dewar, "pgroups", None) == active_pgroup:
for sample in puck.samples:
filtered_samples.append(sample)
# Depending on what your endpoint expects,
# you may choose to return pucks or samples.
# For now, we're returning the list of pucks.
return pucks return pucks

View File

@ -26,35 +26,37 @@ interface Puck {
samples: Sample[]; samples: Sample[];
} }
const SampleTracker: React.FC = () => { interface SampleTrackerProps {
activePgroup: string;
}
const SampleTracker: React.FC<SampleTrackerProps> = ({ activePgroup }) => {
const [pucks, setPucks] = useState<Puck[]>([]); const [pucks, setPucks] = useState<Puck[]>([]);
const [hoveredSample, setHoveredSample] = useState<{ name: string; status: string } | null>(null); const [hoveredSample, setHoveredSample] = useState<{ name: string; status: string } | null>(null);
// Fetch latest sample data // Fetch latest sample data
const fetchPucks = async () => { const fetchPucks = async () => {
try { try {
const data: Puck[] = await SamplesService.getAllPucksWithSamplesAndEventsSamplesPucksSamplesGet(); const data: Puck[] = await SamplesService.getAllPucksWithSamplesAndEventsSamplesPucksSamplesGet(activePgroup);
console.log('Fetched Pucks:', data);
console.log('Fetched Pucks:', data); // Check for dynamic mount_count and unmount_count
setPucks(data); setPucks(data);
} catch (error) { } catch (error) {
console.error('Error fetching pucks', error); console.error('Error fetching pucks', error);
} }
}; };
// Polling logic using a 1-second interval // Polling logic using a 1-second interval
useEffect(() => { useEffect(() => {
// Fetch data immediately on component mount
fetchPucks(); fetchPucks();
// Set up polling every 1 second
const interval = setInterval(() => { const interval = setInterval(() => {
fetchPucks(); fetchPucks();
}, 100000); }, 1000);
// Clear interval on component unmount
return () => clearInterval(interval); return () => clearInterval(interval);
}, []); }, [activePgroup]);
const getSampleColor = (events: Event[] = []) => { const getSampleColor = (events: Event[] = []) => {
const hasMounted = events.some((e) => e.event_type === 'Mounted'); const hasMounted = events.some((e) => e.event_type === 'Mounted');

View File

@ -14,7 +14,7 @@ const ResultsView: React.FC<ResultsViewProps> = ({activePgroup
return ( return (
<div> <div>
<h1>Results Page</h1> <h1>Results Page</h1>
<SampleTracker /> <SampleTracker activePgroup={activePgroup}/>
<ResultGrid activePgroup={activePgroup} /> <ResultGrid activePgroup={activePgroup} />
</div> </div>

View File

@ -528,8 +528,8 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-02-26T13:17:13.591355Z", "end_time": "2025-02-26T16:15:33.052345Z",
"start_time": "2025-02-26T13:17:13.561947Z" "start_time": "2025-02-26T16:15:33.022632Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@ -560,6 +560,7 @@
" headers = {\n", " headers = {\n",
" \"accept\": \"application/json\"\n", " \"accept\": \"application/json\"\n",
" }\n", " }\n",
" comment = \"before loop centering\"\n",
"\n", "\n",
" # Set verify=False to bypass certificate verification (only use in development)\n", " # Set verify=False to bypass certificate verification (only use in development)\n",
" response = requests.post(url, headers=headers, files=files, verify=False)\n", " response = requests.post(url, headers=headers, files=files, verify=False)\n",
@ -580,7 +581,7 @@
"text": [ "text": [
"API Response:\n", "API Response:\n",
"200\n", "200\n",
"{'pgroup': 'p20001', 'sample_id': 16, 'filepath': 'images/p20001/2025-02-26/Dewar One/PUCK-001/16/IMG_1942.jpg', 'status': 'active', 'comment': None, 'id': 3}\n" "{'pgroup': 'p20001', 'sample_id': 16, 'filepath': 'images/p20001/2025-02-26/Dewar One/PUCK-001/16/IMG_1942.jpg', 'status': 'active', 'comment': None, 'id': 4}\n"
] ]
}, },
{ {
@ -592,7 +593,7 @@
] ]
} }
], ],
"execution_count": 88 "execution_count": 89
}, },
{ {
"metadata": {}, "metadata": {},