daf36908ef
Adds a FileDropZone at the bottom of the day view where users can drop all session files at once. Filenames are regex-matched to subjects using their animal_id_string (word-boundary aware, so "2852" won't match "28520"). Only metadata is recorded — files are never uploaded. Backend: new session_files table (id, daily_status_id, filename, file_size BIGINT, file_type, last_modified, notes). Routes: POST /api/daily-statuses/:id/files (batch create) GET /api/daily-statuses/:id/files DELETE /api/session-files/:id Frontend: FileDropZone shows per-subject match groups, unmatched files, and a warning for subjects with no match. After saving, registered files are displayed with delete capability. test-files/: generate_test_files.sh creates 4 dummy files per subject (2×bin, 2×csv) with correct naming for drag-and-drop testing. Pre-generated for 2026-04-23 with IDs 2852/3076/3077/3078. Tests: 19 tests covering drag state, regex matching, save payload, partial-overlap prevention, multi-subject batching, and delete. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
76 lines
2.5 KiB
Bash
Executable File
76 lines
2.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# Generates dummy session files for drag-and-drop testing on the day view.
|
|
# Files are tiny (just named correctly) — the browser File API only reads metadata.
|
|
#
|
|
# Usage: bash generate_test_files.sh [DATE] [IDS...]
|
|
# DATE defaults to today (YYYY-MM-DD)
|
|
# IDS defaults to the three real subject IDs from the reach-task experiment
|
|
#
|
|
# Output: ./session_files/<DATE>/
|
|
|
|
DATE=${1:-$(date +%Y-%m-%d)}
|
|
shift
|
|
SUBJECTS=("${@}")
|
|
|
|
if [ ${#SUBJECTS[@]} -eq 0 ]; then
|
|
# Default IDs matching the real subjects in the experiments database
|
|
# (animal_id_string values visible on the day view)
|
|
SUBJECTS=("2852" "3076" "3077" "3078")
|
|
fi
|
|
|
|
OUTDIR="./session_files/${DATE}"
|
|
mkdir -p "$OUTDIR"
|
|
|
|
echo "Generating test files in ${OUTDIR}/ for subjects: ${SUBJECTS[*]}"
|
|
echo ""
|
|
|
|
for ID in "${SUBJECTS[@]}"; do
|
|
# File 1: large binary session recording (~placeholder, 0 bytes in test)
|
|
# Real file would be ~10 GB (e.g. raw ephys .bin)
|
|
BIN1="${OUTDIR}/${DATE}_${ID}_ephys_raw.bin"
|
|
touch "$BIN1"
|
|
echo " [~10 GB] ${DATE}_${ID}_ephys_raw.bin"
|
|
|
|
# File 2: large HDF5 spike-sorted output (~placeholder, 0 bytes in test)
|
|
# Real file would be ~10 GB (e.g. kilosort output .h5)
|
|
BIN2="${OUTDIR}/${DATE}_${ID}_kilosort.h5"
|
|
touch "$BIN2"
|
|
echo " [~10 GB] ${DATE}_${ID}_kilosort.h5"
|
|
|
|
# File 3: CSV trial events (~10 MB real, 1 KB here)
|
|
CSV1="${OUTDIR}/${DATE}_${ID}_trials.csv"
|
|
{
|
|
echo "trial_num,timestamp,outcome,reaction_time_ms,reward"
|
|
for i in $(seq 1 20); do
|
|
OUTCOME=$( [ $((RANDOM % 3)) -eq 0 ] && echo "Failure" || echo "Success" )
|
|
printf "%d,%.3f,%s,%d,%d\n" \
|
|
"$i" "$(echo "$i * 0.823 + 1.0" | bc -l 2>/dev/null || echo $i)" \
|
|
"$OUTCOME" "$((RANDOM % 400 + 50))" "$((RANDOM % 2))"
|
|
done
|
|
} > "$CSV1"
|
|
echo " [~10 MB] ${DATE}_${ID}_trials.csv"
|
|
|
|
# File 4: CSV behavioral log (~10 MB real, small here)
|
|
CSV2="${OUTDIR}/${DATE}_${ID}_behavior_log.csv"
|
|
{
|
|
echo "ts,event,value,notes"
|
|
echo "0.000,session_start,1,"
|
|
echo "1.234,trial_start,1,"
|
|
echo "1.856,reach_onset,1,"
|
|
echo "2.102,reach_end,1,"
|
|
echo "2.103,outcome,Success,"
|
|
echo "3.500,trial_start,2,"
|
|
echo "4.100,reach_onset,1,"
|
|
echo "4.950,outcome,Failure,"
|
|
echo "9999.9,session_end,1,"
|
|
} > "$CSV2"
|
|
echo " [~10 MB] ${DATE}_${ID}_behavior_log.csv"
|
|
echo ""
|
|
done
|
|
|
|
TOTAL=$(find "$OUTDIR" -type f | wc -l)
|
|
echo "Done — ${TOTAL} files in ${OUTDIR}/"
|
|
echo ""
|
|
echo "Drag the entire '${DATE}' folder into the day-view drop zone at:"
|
|
echo " https://experiments.sam-tran.com/experiments/<id>/day/${DATE}?field=<fieldId>"
|