From 8b40856205f6f9cf605c7759150408b20561804d Mon Sep 17 00:00:00 2001 From: Experiments DB Dev Date: Thu, 23 Apr 2026 12:13:05 -0400 Subject: [PATCH] fix: hide subjects with no data in day modal; fix failure bar rendering - Day modal now only shows animals that have a status record for that day - Removed '+ Add' button and 'No data' placeholder for absent subjects - Fixed failure bars disappearing in recharts: removed radius from all bars, added minPointSize=2 on failure bar so zero-value bars remain visible Co-Authored-By: Claude Sonnet 4.6 --- .../src/components/ExperimentCalendar.jsx | 27 ++++++++++--------- frontend/tests/ExperimentCalendar.test.jsx | 5 ++-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/ExperimentCalendar.jsx b/frontend/src/components/ExperimentCalendar.jsx index 3a3c05f..6797490 100644 --- a/frontend/src/components/ExperimentCalendar.jsx +++ b/frontend/src/components/ExperimentCalendar.jsx @@ -72,10 +72,16 @@ function DayPanel({ date, animals, allStatuses, template, experimentId, selected const fieldLabel = fieldOptions.find((f) => f.value === selectedField)?.label; + // Only show animals that have a status record for this day + const animalsWithData = animals.filter((a) => statusByAnimal[a.id]); + return (
+ {animalsWithData.length === 0 && ( +

No data recorded for this day.

+ )} {/* Per-animal data for this day */} - {animals.map((animal) => { + {animalsWithData.map((animal) => { const existing = statusByAnimal[animal.id]; const isEditing = editingAnimalId === animal.id; return ( @@ -93,7 +99,7 @@ function DayPanel({ date, animals, allStatuses, template, experimentId, selected onClick={() => setEditingAnimalId(animal.id)} className="text-xs text-blue-600 hover:text-blue-800 border border-blue-200 rounded px-2 py-0.5 hover:bg-blue-50 transition-colors" > - {existing ? 'Edit' : '+ Add'} + Edit )}
@@ -102,17 +108,12 @@ function DayPanel({ date, animals, allStatuses, template, experimentId, selected animalId={animal.id} experimentId={experimentId} template={template} - existing={existing ? { ...existing, date: dateStr } : undefined} - onSuccess={(saved) => { - if (existing) { onStatusChange(saved); } else { onStatusCreate(saved); } - setEditingAnimalId(null); - }} + existing={{ ...existing, date: dateStr }} + onSuccess={(saved) => { onStatusChange(saved); setEditingAnimalId(null); }} onCancel={() => setEditingAnimalId(null)} /> - ) : existing ? ( - ) : ( -

No data recorded for this day.

+ )} ); @@ -132,9 +133,9 @@ function DayPanel({ date, animals, allStatuses, template, experimentId, selected - - - + + +
diff --git a/frontend/tests/ExperimentCalendar.test.jsx b/frontend/tests/ExperimentCalendar.test.jsx index b3b1f23..e1cd366 100644 --- a/frontend/tests/ExperimentCalendar.test.jsx +++ b/frontend/tests/ExperimentCalendar.test.jsx @@ -227,8 +227,9 @@ describe('day click modal', () => { expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); }); - it('shows all animals in the modal (with and without data)', async () => { + it('shows only animals with data — excludes subjects with no record that day', async () => { const dateStr = todayStr(); + // Only Rat A has a record; Rat B does not const statuses = [ makeStatus('a1000000-0000-0000-0000-000000000001', dateStr, { 'ww000000-0000-0000-0000-000000000099': '320' }), ]; @@ -239,7 +240,7 @@ describe('day click modal', () => { await waitFor(() => { const dialog = screen.getByRole('dialog'); expect(within(dialog).getAllByText('Rat A').length).toBeGreaterThan(0); - expect(within(dialog).getAllByText('Rat B').length).toBeGreaterThan(0); + expect(within(dialog).queryAllByText('Rat B')).toHaveLength(0); }); }); });