"use client"; import { useEffect, useMemo, useState, type FormEvent } from "react"; import { Download, RefreshCw } from "lucide-react"; import { api, type Dataset, type ExportRow } from "@/lib/api"; import { useAsync, useInterval } from "@/lib/hooks"; import { useToast } from "@/lib/toast"; import { daysAgo, fmtBytes, fmtInt, fmtRelative, fmtTs, splitList, today } from "@/lib/format"; import { Banner, Card, ErrorState, Field, PageHeader, StatusBadge } from "@/components/ui"; import { DataTable } from "@/components/DataTable"; import { JsonView } from "@/components/JsonView"; export default function ExportsPage() { const toast = useToast(); const datasets = useAsync((s) => api.get<{ data: Dataset[] }>("/catalog/datasets", undefined, s), []); const list = useAsync((s) => api.get<{ data: ExportRow[] }>("/exports", undefined, s), []); const live = useMemo(() => (list.data?.data ?? []).some((e) => e.status === "queued" || e.status === "running"), [list.data]); useInterval(list.reload, live ? 3000 : null); const [datasetId, setDatasetId] = useState("market_bars.stock.1m.raw"); const [symbols, setSymbols] = useState(""); const [start, setStart] = useState(daysAgo(365)); const [end, setEnd] = useState(today()); const [adjustment, setAdjustment] = useState<"raw" | "split" | "split_div">("raw"); const [format, setFormat] = useState<"parquet" | "csv">("parquet"); const [busy, setBusy] = useState(false); // Prefill from the Bars explorer (range too large) useEffect(() => { const p = new URLSearchParams(window.location.search); if (p.get("symbols")) setSymbols(p.get("symbols")!.replace(/,/g, "\n")); if (p.get("start")) setStart(p.get("start")!); if (p.get("end")) setEnd(p.get("end")!); const a = p.get("adjustment"); if (a === "raw" || a === "split" || a === "split_div") setAdjustment(a); }, []); const syms = splitList(symbols); async function submit(e: FormEvent) { e.preventDefault(); setBusy(true); try { const out = await api.post<{ id: string; status: string; poll: string }>("/exports", { dataset_id: datasetId, symbols: syms, start, end, adjustment, format }); toast.success("Export queued", out.id); list.reload(); } catch (err) { toast.error(err); } finally { setBusy(false); } } return ( <> Refresh{live ? " (auto 3 s)" : ""} } />