mirror of
https://github.com/azaion/ui.git
synced 2026-06-21 13:51:11 +00:00
feat(dataset): per-detection cards, in-browser editor, bulk-validate for local saves
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react'
|
||||
import { AnnotationSource, AnnotationStatus } from '../types'
|
||||
import type { Detection } from '../types'
|
||||
|
||||
export interface SavedDetection {
|
||||
id: string
|
||||
annotationLocalId: string
|
||||
mediaId: string
|
||||
mediaName: string
|
||||
thumbnail: string
|
||||
fullFrame: string
|
||||
status: AnnotationStatus
|
||||
source: AnnotationSource
|
||||
createdDate: string
|
||||
detection: Detection
|
||||
time: string | null
|
||||
flightId: string | null
|
||||
}
|
||||
|
||||
interface SavedAnnotationsState {
|
||||
saved: SavedDetection[]
|
||||
addMany: (items: SavedDetection[]) => void
|
||||
replaceGroup: (annotationLocalId: string, items: SavedDetection[]) => void
|
||||
updateStatus: (ids: string[], status: AnnotationStatus) => void
|
||||
removeSaved: (id: string) => void
|
||||
clear: () => void
|
||||
}
|
||||
|
||||
const STORAGE_KEY = 'az.savedAnnotations.v2'
|
||||
|
||||
const SavedAnnotationsContext = createContext<SavedAnnotationsState>(null!)
|
||||
|
||||
export function useSavedAnnotations() {
|
||||
return useContext(SavedAnnotationsContext)
|
||||
}
|
||||
|
||||
export function SavedAnnotationsProvider({ children }: { children: ReactNode }) {
|
||||
const [saved, setSaved] = useState<SavedDetection[]>(() => {
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY)
|
||||
return raw ? (JSON.parse(raw) as SavedDetection[]) : []
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
try { localStorage.setItem(STORAGE_KEY, JSON.stringify(saved)) } catch {}
|
||||
}, [saved])
|
||||
|
||||
const addMany = useCallback((items: SavedDetection[]) => {
|
||||
if (!items.length) return
|
||||
const ids = new Set(items.map(i => i.id))
|
||||
setSaved(prev => [...items, ...prev.filter(x => !ids.has(x.id))])
|
||||
}, [])
|
||||
|
||||
const replaceGroup = useCallback((annotationLocalId: string, items: SavedDetection[]) => {
|
||||
setSaved(prev => [
|
||||
...items,
|
||||
...prev.filter(x => x.annotationLocalId !== annotationLocalId),
|
||||
])
|
||||
}, [])
|
||||
|
||||
const updateStatus = useCallback((ids: string[], status: AnnotationStatus) => {
|
||||
if (!ids.length) return
|
||||
const idSet = new Set(ids)
|
||||
setSaved(prev => prev.map(x => idSet.has(x.id) ? { ...x, status } : x))
|
||||
}, [])
|
||||
|
||||
const removeSaved = useCallback((id: string) => {
|
||||
setSaved(prev => prev.filter(x => x.id !== id))
|
||||
}, [])
|
||||
|
||||
const clear = useCallback(() => setSaved([]), [])
|
||||
|
||||
return (
|
||||
<SavedAnnotationsContext.Provider value={{ saved, addMany, replaceGroup, updateStatus, removeSaved, clear }}>
|
||||
{children}
|
||||
</SavedAnnotationsContext.Provider>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user