feat: integrate chatbox research with datasets and backtests
This commit is contained in:
@@ -28,6 +28,7 @@ import type {
|
||||
Source,
|
||||
} from "./types";
|
||||
import "./style.css";
|
||||
import { SourceDetails, sourceLabel } from "../research/SourceDetails";
|
||||
|
||||
export function BacktestPage({
|
||||
active,
|
||||
@@ -47,6 +48,8 @@ export function BacktestPage({
|
||||
onContext: (context: PageContext) => void;
|
||||
}) {
|
||||
const [view, setView] = useState("runs");
|
||||
const [sourceFilter, setSourceFilter] = useState("");
|
||||
const [sourceKinds, setSourceKinds] = useState<string[]>([]);
|
||||
const [page, setPage] = useState(1);
|
||||
const [runs, setRuns] = useState<Page<Run>>({
|
||||
items: [],
|
||||
@@ -97,15 +100,19 @@ export function BacktestPage({
|
||||
const [itemDetail, setItemDetail] = useState<Item | null>(null);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
const [r, d, c] = await Promise.all([
|
||||
api<Page<Run>>(`/backtests/runs?offset=${(page - 1) * 25}`),
|
||||
const [r, d, c, kinds] = await Promise.all([
|
||||
api<Page<Run>>(
|
||||
`/backtests/runs?offset=${(page - 1) * 25}&source=${encodeURIComponent(sourceFilter)}`,
|
||||
),
|
||||
api<Page<DraftSummary>>(`/backtests/drafts?offset=${(page - 1) * 25}`),
|
||||
api<Scheduler>("/backtests/config"),
|
||||
api<string[]>("/backtests/sources"),
|
||||
]);
|
||||
setRuns(r);
|
||||
setDrafts(d);
|
||||
setConfig(c);
|
||||
}, [page]);
|
||||
setSourceKinds(kinds);
|
||||
}, [page, sourceFilter]);
|
||||
useEffect(() => {
|
||||
if (!active) return;
|
||||
let alive = true;
|
||||
@@ -293,6 +300,22 @@ export function BacktestPage({
|
||||
]}
|
||||
/>
|
||||
<span className="muted">REGULAR · FASTEXPR</span>
|
||||
{view === "runs" && (
|
||||
<Select
|
||||
aria-label="回测研究来源筛选"
|
||||
value={sourceFilter || undefined}
|
||||
placeholder="全部研究来源"
|
||||
showClear
|
||||
optionList={sourceKinds.map((kind) => ({
|
||||
value: kind,
|
||||
label: sourceLabel(kind),
|
||||
}))}
|
||||
onChange={(value) => {
|
||||
setSourceFilter(String(value ?? ""));
|
||||
setPage(1);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="backtest-spacer" />
|
||||
<Button
|
||||
type="tertiary"
|
||||
@@ -337,7 +360,11 @@ export function BacktestPage({
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
{ title: "来源", width: 120, render: (_, r) => r!.source.kind },
|
||||
{
|
||||
title: "来源",
|
||||
width: 120,
|
||||
render: (_, r) => sourceLabel(r!.source.kind),
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
width: 160,
|
||||
@@ -438,8 +465,9 @@ export function BacktestPage({
|
||||
</div>
|
||||
<p>
|
||||
{preview.name} · {preview.total} 条候选 · {preview.batch_count}{" "}
|
||||
个平台批次 · 来源 {preview.source.kind}
|
||||
个平台批次 · 来源 {sourceLabel(preview.source.kind)}
|
||||
</p>
|
||||
<SourceDetails source={preview.source} onAction={onAction} />
|
||||
{preview.duplicate_count > 0 && (
|
||||
<Banner
|
||||
type="warning"
|
||||
@@ -763,10 +791,11 @@ export function BacktestPage({
|
||||
/>
|
||||
)}
|
||||
<p className="muted">
|
||||
来源 {run.source.kind}{" "}
|
||||
来源 {sourceLabel(run.source.kind)}{" "}
|
||||
{run.source.batch_id ? `· 批次 ${run.source.batch_id}` : ""} ·{" "}
|
||||
{formatTime(run.created_at, timezone)}
|
||||
</p>
|
||||
<SourceDetails source={run.source} onAction={onAction} />
|
||||
{run.scheduler.blocked_reason && (
|
||||
<Banner
|
||||
type="warning"
|
||||
|
||||
Reference in New Issue
Block a user