feat(import): browser-based genome import workflow UI (#15)#40
Merged
Conversation
Replace CLI-only import with a full browser flow: drag-and-drop upload,
format auto-detection preview, options (profile / min-r² / dry-run),
result stats, and import history.
Backend
- scripts/lib/importer.py: shared detect_file() + import_genome_file()
with an atomic single-transaction import and a profile-conflict guard.
genome_init.py CLI refactored to use it — one code path for CLI and web.
- backend/app/routes/imports_route.py: POST /api/import/detect,
POST /api/import/upload, GET /api/import/history. Uploads streamed to a
temp file (200 MB cap, .zip rejected), parsed in a threadpool, temp
deleted after use. Status codes: 400 undetectable, 409 profile exists,
413 too large, 415 unsupported archive.
Frontend
- components/import/{ImportView,DropZone}, hooks/useImport, wired into
App.tsx as an always-visible "Import" view (#/import). An empty database
lands on Import for first-run onboarding. Accessible dropzone (real
button + aria-live status + focus management; r2 help via aria-describedby).
Tests (TDD): 9 importer + 8 route (pytest), 9 hook/component (vitest); full
suites green (frontend 517). Verified end-to-end in a real browser
(upload -> detect -> import -> history -> empty-DB auto-route).
Design notes, prototype, and codex audit resolutions in docs/import-ui/.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #15.
Replaces CLI-only genome import (
scripts/genome_init.py) with a full browser flow — the highest-leverage onboarding/accessibility win in the backlog, since import previously gated all first use.What's new
#/import, always-visible nav tab; the app lands here automatically on first run when the DB is empty).Backend
scripts/lib/importer.py— shareddetect_file()+import_genome_file()with an atomic single-transaction import and a profile-conflict guard.genome_init.pyCLI refactored to use it, so CLI and web share one tested code path.backend/app/routes/imports_route.py—POST /api/import/detect,POST /api/import/upload,GET /api/import/history. Uploads streamed to a temp file (200 MB cap,.ziprejected), parsed in a threadpool so the event loop never blocks, temp deleted after use. Status codes: 400 undetectable · 409 profile exists · 413 too large · 415 unsupported archive. Temp paths never leak in error responses.Frontend
components/import/{ImportView,DropZone},hooks/useImport, wired intoApp.tsx. Accessible: real<button>dropzone,aria-livestatus, focus moves to the result/error heading, r² help viaaria-describedby.Quality
docs/import-ui/.Notes for reviewers
tscstrict errors and optional-dep test gaps (weasyprint/textual) exist onmainand are unrelated; none are in the import code.🤖 Generated with Claude Code