Skip to content

Commit e19cedf

Browse files
committed
fix annotation handling in jbrowse page
1 parent 0880ce5 commit e19cedf

4 files changed

Lines changed: 37 additions & 32 deletions

File tree

front/app/jbrowse/page.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function JBrowseContent() {
2525
const [annotationId, setAnnotationId] = useState<string>('')
2626
const [assembly, setAssembly] = useState<AssemblyRecord | null>(null)
2727
const [annotations, setAnnotations] = useState<AnnotationRecord[]>([])
28-
const [selectedAnnotationId, setSelectedAnnotationId] = useState<string | undefined>()
28+
const [selectedAnnotationIds, setSelectedAnnotationIds] = useState<string[]>([])
2929
const [selectedChromosome, setSelectedChromosome] = useState<ChromosomeInterface | null>(null)
3030
const [isDetailsExpanded, setIsDetailsExpanded] = useState(true)
3131
const [isLoading, setIsLoading] = useState(true)
@@ -41,7 +41,7 @@ function JBrowseContent() {
4141
setAccession(accessionParam)
4242
if (annotationIdParam) {
4343
setAnnotationId(annotationIdParam)
44-
setSelectedAnnotationId(annotationIdParam)
44+
setSelectedAnnotationIds([annotationIdParam])
4545
}
4646
setIsInitialized(true)
4747
}
@@ -177,11 +177,11 @@ function JBrowseContent() {
177177
return (
178178
<button
179179
key={annotation.md5_checksum}
180-
onClick={() => setSelectedAnnotationId(
181-
selectedAnnotationId === annotation.md5_checksum ? undefined : annotation.md5_checksum
180+
onClick={() => setSelectedAnnotationIds(
181+
selectedAnnotationIds.includes(annotation.annotation_id as string) ? selectedAnnotationIds.filter((id: string) => id !== annotation.annotation_id as string) : [...selectedAnnotationIds, annotation.annotation_id as string]
182182
)}
183183
className={`p-4 rounded-lg border text-left transition-all ${
184-
selectedAnnotationId === annotation.md5_checksum
184+
selectedAnnotationIds.includes(annotation.annotation_id as string)
185185
? 'border-primary bg-primary/5 shadow-sm'
186186
: 'border-border hover:border-primary/50 hover:bg-muted/50'
187187
}`}
@@ -265,7 +265,7 @@ function JBrowseContent() {
265265
>
266266
<JBrowseLinearGenomeViewComponent
267267
accession={accession}
268-
annotationId={selectedAnnotationId}
268+
annotationIds={selectedAnnotationIds}
269269
selectedChromosome={selectedChromosome}
270270
/>
271271
</Suspense>

front/components/annotations-list.tsx

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useState, useEffect } from "react"
44
import { useSearchParams, useRouter } from "next/navigation"
55
import { Card } from "@/components/ui/card"
66
import { Badge } from "@/components/ui/badge"
7-
import { FileText, Database, BarChart3, Settings2, X, ArrowDown, ArrowUp, Dna, Star } from "lucide-react"
7+
import { FileText, BarChart3, Settings2, X, ArrowDown, ArrowUp, Star } from "lucide-react"
88
import { AnnotationsStatsDashboard } from "@/components/annotations-stats-dashboard"
99
import { AnnotationsFiltersDialog } from "@/components/annotations-filters-dialog"
1010
import { AnnotationsPagination } from "@/components/annotations-pagination"
@@ -32,10 +32,8 @@ export function AnnotationsList({ filterType, filterObject, selectedAssemblyAcce
3232
const [stats, setStats] = useState<any>(null)
3333
const [statsLoading, setStatsLoading] = useState(false)
3434
const [viewMode, setViewMode] = useState<"list" | "statistics">("list")
35-
const [mounted, setMounted] = useState(false)
3635
// Filter states
3736
const [biotypes, setBiotypes] = useState<string[]>([])
38-
const [favIds, setFavIds] = useState<string[]>([])
3937
const [featureTypes, setFeatureTypes] = useState<string[]>([])
4038
const [pipelines, setPipelines] = useState<string[]>([])
4139
const [providers, setProviders] = useState<string[]>([])
@@ -57,13 +55,9 @@ export function AnnotationsList({ filterType, filterObject, selectedAssemblyAcce
5755
const [filtersDialogOpen, setFiltersDialogOpen] = useState(false)
5856

5957
// Zustand store
60-
const { isSelected: isSelectedStore, getSelectedAnnotations } = useSelectedAnnotationsStore()
61-
const isSelected = (id: string) => mounted ? isSelectedStore(id) : false
62-
63-
// Prevent hydration mismatch
64-
useEffect(() => {
65-
setMounted(true)
66-
}, [])
58+
const { isSelected: isSelectedStore, getSelectedAnnotations, getSelectionCount } = useSelectedAnnotationsStore()
59+
const isSelected = (id: string) => isSelectedStore(id)
60+
const favoritesCount = getSelectionCount()
6761

6862
// Fetch filter options
6963
useEffect(() => {
@@ -94,12 +88,16 @@ export function AnnotationsList({ filterType, filterObject, selectedAssemblyAcce
9488
}
9589
}
9690
fetchFilterOptions()
97-
}, [filterType, filterObject, selectedAssemblyAccessions, mostRecentPerSpecies])
91+
}, [filterType, filterObject, selectedAssemblyAccessions, mostRecentPerSpecies, showFavs, favoritesCount])
9892

9993
const getBaseParams = () => {
10094
let params: Record<string, any> = {}
10195
if (showFavs) {
102-
params = { ...params, md5_checksums: favIds.join(',') }
96+
const favoriteAnnotations = getSelectedAnnotations()
97+
const favoriteIds = favoriteAnnotations.map((annotation: Annotation) => annotation.annotation_id)
98+
if (favoriteIds.length > 0) {
99+
params = { ...params, md5_checksums: favoriteIds.join(',') }
100+
}
103101
}
104102
if (filterType === "organism" || filterType === "taxon") {
105103
params = { ...params, taxids: filterObject?.taxid }
@@ -120,8 +118,17 @@ export function AnnotationsList({ filterType, filterObject, selectedAssemblyAcce
120118
let params: Record<string, any> = { limit: itemsPerPage, offset: offset }
121119
if (showFavs) {
122120
const favoriteAnnotations = getSelectedAnnotations()
123-
setFavIds(favoriteAnnotations.map((annotation: Annotation) => annotation.annotation_id))
124-
params = { ...params, md5_checksums: favIds.join(',') }
121+
const favoriteIds = favoriteAnnotations.map((annotation: Annotation) => annotation.annotation_id)
122+
if (favoriteIds.length > 0) {
123+
params = { ...params, md5_checksums: favoriteIds.join(',') }
124+
} else {
125+
// No favorites, return empty results
126+
setAnnotations([])
127+
setTotalAnnotations(0)
128+
setStats(null)
129+
setStatsLoading(false)
130+
return
131+
}
125132
}
126133
// Add base filters
127134
if (filterType === "organism" || filterType === "taxon") {
@@ -182,7 +189,7 @@ export function AnnotationsList({ filterType, filterObject, selectedAssemblyAcce
182189
}
183190
}
184191
fetchData()
185-
}, [filterType, filterObject, selectedAssemblyAccessions, biotypes, featureTypes, pipelines, providers, source, currentPage, itemsPerPage, sortByDate, mostRecentPerSpecies, showFavs, getSelectedAnnotations])
192+
}, [filterType, filterObject, selectedAssemblyAccessions, biotypes, featureTypes, pipelines, providers, source, currentPage, itemsPerPage, sortByDate, mostRecentPerSpecies, showFavs, favoritesCount, getSelectedAnnotations])
186193

187194

188195
const clearAllFilters = () => {
@@ -251,7 +258,7 @@ export function AnnotationsList({ filterType, filterObject, selectedAssemblyAcce
251258
<div>
252259
<h3 className="font-semibold text-foreground">Viewing Favorite Annotations</h3>
253260
<p className="text-sm text-muted-foreground">
254-
Showing {totalAnnotations} favorite annotation{totalAnnotations !== 1 ? 's' : ''}
261+
Showing {favoritesCount} favorite annotation{favoritesCount !== 1 ? 's' : ''}
255262
</p>
256263
</div>
257264
</div>
@@ -367,12 +374,11 @@ export function AnnotationsList({ filterType, filterObject, selectedAssemblyAcce
367374
<div className="flex items-center gap-1 w-fit">
368375
<Button
369376
variant="ghost"
370-
size="lg"
371377
onClick={() => setViewMode("list")}
372378
className={cn(
373379
"gap-2",
374380
viewMode === "list"
375-
? "text-primary"
381+
? "text-primary border-primary border-b-2"
376382
: "text-muted-foreground hover:text-foreground hover:bg-primary",
377383
)}
378384
>
@@ -381,12 +387,11 @@ export function AnnotationsList({ filterType, filterObject, selectedAssemblyAcce
381387
</Button>
382388
<Button
383389
variant="ghost"
384-
size="lg"
385390
onClick={() => setViewMode("statistics")}
386391
className={cn(
387392
"gap-2",
388393
viewMode === "statistics"
389-
? "text-primary"
394+
? "text-primary border-primary border-b-2"
390395
: "text-muted-foreground hover:text-foreground hover:bg-primary",
391396
)}
392397
>

front/components/jbrowse.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ interface ChromosomeInterface {
1818

1919
interface JBrowseLinearGenomeViewComponentProps {
2020
accession: string
21-
annotationId?: string
21+
annotationIds?: string[]
2222
selectedChromosome?: ChromosomeInterface | null
2323
}
2424
// Use relative URLs to leverage Next.js rewrites and avoid CORS issues
@@ -65,7 +65,7 @@ const configuration = {
6565
},
6666
}
6767

68-
export default function JBrowseLinearGenomeViewComponent({ accession, annotationId, selectedChromosome }: JBrowseLinearGenomeViewComponentProps) {
68+
export default function JBrowseLinearGenomeViewComponent({ accession, annotationIds, selectedChromosome }: JBrowseLinearGenomeViewComponentProps) {
6969
const [viewState, setViewState] = useState<ViewModel>()
7070
const [chromosomes, setChromosomes] = useState<any[]>([])
7171
const [annotations, setAnnotations] = useState<any[]>([])
@@ -93,8 +93,8 @@ export default function JBrowseLinearGenomeViewComponent({ accession, annotation
9393
setChromosomes(chromosomeResults)
9494
setAssemblyName(annotationResults[0]?.assembly_name ?? '')
9595

96-
if (annotationId) {
97-
setAnnotations(annotationResults.filter((annotation: any) => annotation.annotation_id === annotationId))
96+
if (annotationIds && annotationIds.length > 0) {
97+
setAnnotations(annotationResults.filter((annotation: any) => annotationIds.includes(annotation.annotation_id)))
9898
} else {
9999
setAnnotations(annotationResults)
100100
}
@@ -107,7 +107,7 @@ export default function JBrowseLinearGenomeViewComponent({ accession, annotation
107107

108108
fetchData()
109109
return () => { cancelled = true }
110-
}, [accession, annotationId])
110+
}, [accession, annotationIds])
111111

112112
// Memoize tracks to prevent recreation on every render
113113
const tracks = useMemo(() => {

front/lib/api/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export interface Pagination<T> {
3737

3838
export interface AnnotationRecord {
3939
md5_checksum?: string
40-
annotation_id?: string
40+
annotation_id: string
4141
name?: string
4242
organism_name?: string
4343
assembly_accession?: string

0 commit comments

Comments
 (0)