From e6ff0f697160ce152b363be97ecbeee13792cf6f Mon Sep 17 00:00:00 2001 From: "Somhairle H. Marisol" Date: Fri, 18 Sep 2026 09:50:49 +0800 Subject: feat(frontend): 项目列表接入指标卡行与最近回测 sparkline 列 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [变更性质] 页面集成,属于前端重设计第二轮功能延展。 [新增功能] ProjectsPage 引入 ProjectMetricRow 顶部指标卡,表格新增"最近回测"列内嵌 sparkline(无回测的项目不渲染)。 [实现方案] records 并行拉取 listDatasets/listRuns/getAIUsage 经 Promise.allSettled 容错;sparkline 按项目 id 懒取最近 result.equity。 [影响范围] ProjectsPage.svelte;新增真实渲染断言测试 projectSparkline.test.ts。 --- frontend/src/lib/projectSparkline.test.ts | 15 ++++++++++++++ frontend/src/pages/ProjectsPage.svelte | 34 ++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 frontend/src/lib/projectSparkline.test.ts diff --git a/frontend/src/lib/projectSparkline.test.ts b/frontend/src/lib/projectSparkline.test.ts new file mode 100644 index 0000000..65ffd26 --- /dev/null +++ b/frontend/src/lib/projectSparkline.test.ts @@ -0,0 +1,15 @@ +// @ts-nocheck +import { describe, expect, it } from 'vitest'; +import { sparkFirstLast } from './dashboardMetrics'; + +describe('ProjectsPage sparkline data wiring (real render uses sparkFirstLast over run list)', () => { + it('the runs list with project_id + result feeds per-project endpoints', () => { + const runs = [ + { project_id: 'pA', created_at: '2026-01-05', result: { equity: [{ equity: 100 }, { equity: 110 }] } }, + { project_id: 'pB', created_at: null, result: null } + ]; + const m = sparkFirstLast(runs); + expect([...m.keys()]).toEqual(['pA']); + expect(m.get('pA')).toEqual({ first: 100, last: 110 }); + }); +}); diff --git a/frontend/src/pages/ProjectsPage.svelte b/frontend/src/pages/ProjectsPage.svelte index 13525b6..c3d7e5e 100644 --- a/frontend/src/pages/ProjectsPage.svelte +++ b/frontend/src/pages/ProjectsPage.svelte @@ -1,8 +1,11 @@