feat: implement Section 5 - Span Tool State & Integration
- Add SpanAnnotation and SpanLabelType interfaces to page.tsx - Add span-related state: spanAnnotations, selectedSpanId, spanLabelTypes - Add fetchSpanAnnotations() and fetchSpanLabelTypes() data fetching functions - Load span annotations and label types when chart changes - Add "Span" tool button to Toolbox component with RectangleHorizontal icon - Mark Section 5 tasks (5.1-5.5) as complete in tasks.md Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
5ea63a613e
commit
c9d2cbfc4b
3 changed files with 79 additions and 10 deletions
|
|
@ -21,8 +21,33 @@ interface Annotation {
|
|||
created_at: number;
|
||||
}
|
||||
|
||||
interface SpanAnnotation {
|
||||
id: number;
|
||||
chart_id: number;
|
||||
start_time: number;
|
||||
end_time: number;
|
||||
label: string;
|
||||
confidence: number | null;
|
||||
outcome: string | null;
|
||||
notes: string | null;
|
||||
sub_spans: any;
|
||||
color: string;
|
||||
created_at: number;
|
||||
}
|
||||
|
||||
interface SpanLabelType {
|
||||
id: number;
|
||||
name: string;
|
||||
display_name: string;
|
||||
color: string;
|
||||
hotkey: string | null;
|
||||
is_active: number;
|
||||
sort_order: number;
|
||||
created_at: number;
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const [activeTool, setActiveTool] = useState<Tool>(null);
|
||||
const [activeTool, setActiveTool] = useState<Tool | 'span'>(null);
|
||||
const [selectedColor, setSelectedColor] = useState('#3b82f6');
|
||||
const [selectedLabelId, setSelectedLabelId] = useState<number | null>(null);
|
||||
const [annotations, setAnnotations] = useState<Annotation[]>([]);
|
||||
|
|
@ -30,6 +55,11 @@ export default function Home() {
|
|||
const [activeChartId, setActiveChartId] = useState<number | null>(null);
|
||||
const chartRef = useRef<CandleChartHandle>(null);
|
||||
|
||||
// Span annotation state
|
||||
const [spanAnnotations, setSpanAnnotations] = useState<SpanAnnotation[]>([]);
|
||||
const [selectedSpanId, setSelectedSpanId] = useState<number | null>(null);
|
||||
const [spanLabelTypes, setSpanLabelTypes] = useState<SpanLabelType[]>([]);
|
||||
|
||||
// Fetch charts list
|
||||
const fetchCharts = useCallback(async () => {
|
||||
try {
|
||||
|
|
@ -58,25 +88,54 @@ export default function Home() {
|
|||
}
|
||||
}, []);
|
||||
|
||||
// Fetch charts on mount, auto-select the most recent
|
||||
// Fetch span annotations for active chart
|
||||
const fetchSpanAnnotations = useCallback(async (chartId: number | null) => {
|
||||
if (!chartId) {
|
||||
setSpanAnnotations([]);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(`/api/span-annotations?chartId=${chartId}`);
|
||||
const data = await response.json();
|
||||
setSpanAnnotations(data);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch span annotations:', error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Fetch span label types
|
||||
const fetchSpanLabelTypes = useCallback(async () => {
|
||||
try {
|
||||
const response = await fetch('/api/span-label-types');
|
||||
const data = await response.json();
|
||||
setSpanLabelTypes(data);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch span label types:', error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Fetch charts and span label types on mount, auto-select the most recent chart
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
const chartList = await fetchCharts();
|
||||
await fetchSpanLabelTypes();
|
||||
if (chartList.length > 0) {
|
||||
setActiveChartId(chartList[0].id); // sorted by created_at desc
|
||||
}
|
||||
};
|
||||
init();
|
||||
}, [fetchCharts]);
|
||||
}, [fetchCharts, fetchSpanLabelTypes]);
|
||||
|
||||
// When activeChartId changes, refetch data
|
||||
useEffect(() => {
|
||||
if (activeChartId !== null) {
|
||||
chartRef.current?.refreshData();
|
||||
fetchAnnotations(activeChartId);
|
||||
fetchSpanAnnotations(activeChartId);
|
||||
setSelectedLabelId(null);
|
||||
setSelectedSpanId(null);
|
||||
}
|
||||
}, [activeChartId, fetchAnnotations]);
|
||||
}, [activeChartId, fetchAnnotations, fetchSpanAnnotations]);
|
||||
|
||||
const handleExport = () => {
|
||||
if (activeChartId) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { ArrowUpCircle, ArrowDownCircle, TrendingUp, Trash2, Download, ChevronDown, ChevronUp } from 'lucide-react';
|
||||
import { ArrowUpCircle, ArrowDownCircle, TrendingUp, Trash2, Download, ChevronDown, ChevronUp, RectangleHorizontal } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { ThemeToggle } from '@/components/ThemeToggle';
|
||||
|
|
@ -168,6 +168,16 @@ export default function Toolbox({
|
|||
</Button>
|
||||
))}
|
||||
|
||||
{/* Span tool button */}
|
||||
<Button
|
||||
variant={activeTool === 'span' ? 'default' : 'outline'}
|
||||
className="justify-start gap-2"
|
||||
onClick={() => handleToolClick('span')}
|
||||
>
|
||||
<RectangleHorizontal className="w-5 h-5" />
|
||||
Span
|
||||
</Button>
|
||||
|
||||
{/* Color picker */}
|
||||
<div className="flex gap-1 px-1">
|
||||
{[
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue