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
|
|
@ -30,11 +30,11 @@
|
||||||
|
|
||||||
## 5. Span Tool State & Integration
|
## 5. Span Tool State & Integration
|
||||||
|
|
||||||
- [ ] 5.1 Extend `activeTool` type in `page.tsx` to include `'span'` tool mode
|
- [x] 5.1 Extend `activeTool` type in `page.tsx` to include `'span'` tool mode
|
||||||
- [ ] 5.2 Add span-related state to `page.tsx`: `spanAnnotations[]`, `selectedSpanId`, `spanLabelTypes[]`
|
- [x] 5.2 Add span-related state to `page.tsx`: `spanAnnotations[]`, `selectedSpanId`, `spanLabelTypes[]`
|
||||||
- [ ] 5.3 Add `fetchSpanAnnotations(chartId)` and `fetchSpanLabelTypes()` data fetching functions
|
- [x] 5.3 Add `fetchSpanAnnotations(chartId)` and `fetchSpanLabelTypes()` data fetching functions
|
||||||
- [ ] 5.4 Load span annotations and label types when chart changes (alongside existing annotation loading)
|
- [x] 5.4 Load span annotations and label types when chart changes (alongside existing annotation loading)
|
||||||
- [ ] 5.5 Add "Span" tool button to Toolbox component alongside existing tools
|
- [x] 5.5 Add "Span" tool button to Toolbox component alongside existing tools
|
||||||
|
|
||||||
## 6. Two-Click Span Selection & Preview
|
## 6. Two-Click Span Selection & Preview
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,33 @@ interface Annotation {
|
||||||
created_at: number;
|
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() {
|
export default function Home() {
|
||||||
const [activeTool, setActiveTool] = useState<Tool>(null);
|
const [activeTool, setActiveTool] = useState<Tool | 'span'>(null);
|
||||||
const [selectedColor, setSelectedColor] = useState('#3b82f6');
|
const [selectedColor, setSelectedColor] = useState('#3b82f6');
|
||||||
const [selectedLabelId, setSelectedLabelId] = useState<number | null>(null);
|
const [selectedLabelId, setSelectedLabelId] = useState<number | null>(null);
|
||||||
const [annotations, setAnnotations] = useState<Annotation[]>([]);
|
const [annotations, setAnnotations] = useState<Annotation[]>([]);
|
||||||
|
|
@ -30,6 +55,11 @@ export default function Home() {
|
||||||
const [activeChartId, setActiveChartId] = useState<number | null>(null);
|
const [activeChartId, setActiveChartId] = useState<number | null>(null);
|
||||||
const chartRef = useRef<CandleChartHandle>(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
|
// Fetch charts list
|
||||||
const fetchCharts = useCallback(async () => {
|
const fetchCharts = useCallback(async () => {
|
||||||
try {
|
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(() => {
|
useEffect(() => {
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
const chartList = await fetchCharts();
|
const chartList = await fetchCharts();
|
||||||
|
await fetchSpanLabelTypes();
|
||||||
if (chartList.length > 0) {
|
if (chartList.length > 0) {
|
||||||
setActiveChartId(chartList[0].id); // sorted by created_at desc
|
setActiveChartId(chartList[0].id); // sorted by created_at desc
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
init();
|
init();
|
||||||
}, [fetchCharts]);
|
}, [fetchCharts, fetchSpanLabelTypes]);
|
||||||
|
|
||||||
// When activeChartId changes, refetch data
|
// When activeChartId changes, refetch data
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeChartId !== null) {
|
if (activeChartId !== null) {
|
||||||
chartRef.current?.refreshData();
|
chartRef.current?.refreshData();
|
||||||
fetchAnnotations(activeChartId);
|
fetchAnnotations(activeChartId);
|
||||||
|
fetchSpanAnnotations(activeChartId);
|
||||||
setSelectedLabelId(null);
|
setSelectedLabelId(null);
|
||||||
|
setSelectedSpanId(null);
|
||||||
}
|
}
|
||||||
}, [activeChartId, fetchAnnotations]);
|
}, [activeChartId, fetchAnnotations, fetchSpanAnnotations]);
|
||||||
|
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
if (activeChartId) {
|
if (activeChartId) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState, useEffect } from 'react';
|
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 { Button } from '@/components/ui/button';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { ThemeToggle } from '@/components/ThemeToggle';
|
import { ThemeToggle } from '@/components/ThemeToggle';
|
||||||
|
|
@ -168,6 +168,16 @@ export default function Toolbox({
|
||||||
</Button>
|
</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 */}
|
{/* Color picker */}
|
||||||
<div className="flex gap-1 px-1">
|
<div className="flex gap-1 px-1">
|
||||||
{[
|
{[
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue