niceeval 0.5.4 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INDEX.md +55 -0
- package/dist/agents/types.d.ts +321 -0
- package/dist/context/types.d.ts +335 -0
- package/dist/i18n/core.d.ts +11 -0
- package/dist/i18n/en.d.ts +181 -0
- package/dist/i18n/index.d.ts +5 -0
- package/dist/i18n/zh-CN.d.ts +183 -0
- package/dist/o11y/otlp/parse.d.ts +3 -0
- package/dist/o11y/otlp/receiver.d.ts +21 -0
- package/dist/o11y/otlp/turn-otel.d.ts +43 -0
- package/dist/o11y/types.d.ts +190 -0
- package/dist/report/aggregate.d.ts +57 -0
- package/dist/report/aggregate.js +212 -0
- package/dist/report/built-ins/experiment-comparison.d.ts +1 -0
- package/dist/report/built-ins/experiment-comparison.js +13 -0
- package/dist/report/built-ins/index.d.ts +1 -0
- package/dist/report/built-ins/index.js +2 -0
- package/dist/report/components.d.ts +180 -0
- package/dist/report/components.js +132 -0
- package/dist/report/compute.d.ts +106 -0
- package/dist/report/compute.js +600 -0
- package/dist/report/flag.d.ts +6 -0
- package/dist/report/flag.js +8 -0
- package/dist/report/format.d.ts +26 -0
- package/dist/report/format.js +109 -0
- package/dist/report/index.d.ts +19 -0
- package/dist/report/index.js +30 -0
- package/dist/report/load.d.ts +12 -0
- package/dist/report/load.js +56 -0
- package/dist/report/locale.d.ts +94 -0
- package/dist/report/locale.js +183 -0
- package/dist/report/metrics.d.ts +21 -0
- package/dist/report/metrics.js +115 -0
- package/dist/report/primitives.d.ts +64 -0
- package/dist/report/primitives.js +113 -0
- package/dist/report/react/AttemptList.d.ts +23 -0
- package/dist/report/react/AttemptList.js +19 -0
- package/dist/report/react/DeltaTable.d.ts +8 -0
- package/dist/report/react/DeltaTable.js +24 -0
- package/dist/report/react/EvalList.d.ts +10 -0
- package/dist/report/react/EvalList.js +0 -0
- package/dist/report/react/ExperimentList.d.ts +11 -0
- package/dist/report/react/ExperimentList.js +67 -0
- package/dist/report/react/GroupSummary.d.ts +8 -0
- package/dist/report/react/GroupSummary.js +8 -0
- package/dist/report/react/MetricBars.d.ts +10 -0
- package/dist/report/react/MetricBars.js +48 -0
- package/dist/report/react/MetricLine.d.ts +9 -0
- package/dist/report/react/MetricLine.js +68 -0
- package/dist/report/react/MetricMatrix.d.ts +10 -0
- package/dist/report/react/MetricMatrix.js +23 -0
- package/dist/report/react/MetricScatter.d.ts +9 -0
- package/dist/report/react/MetricScatter.js +96 -0
- package/dist/report/react/MetricTable.d.ts +11 -0
- package/dist/report/react/MetricTable.js +26 -0
- package/dist/report/react/RunOverview.d.ts +8 -0
- package/dist/report/react/RunOverview.js +12 -0
- package/dist/report/react/Scoreboard.d.ts +8 -0
- package/dist/report/react/Scoreboard.js +26 -0
- package/dist/report/react/cell.d.ts +9 -0
- package/dist/report/react/cell.js +9 -0
- package/dist/report/react/chart-math.d.ts +14 -0
- package/dist/report/react/chart-math.js +68 -0
- package/dist/report/react/colors.d.ts +14 -0
- package/dist/report/react/colors.js +45 -0
- package/dist/report/react/fixtures.d.ts +19 -0
- package/dist/report/react/fixtures.js +398 -0
- package/dist/report/react/format.d.ts +3 -0
- package/dist/report/react/format.js +7 -0
- package/dist/report/react/index.d.ts +6 -0
- package/dist/report/react/index.js +14 -0
- package/dist/report/report.d.ts +24 -0
- package/dist/report/report.js +49 -0
- package/dist/report/text/faces.d.ts +29 -0
- package/dist/report/text/faces.js +541 -0
- package/dist/report/text/layout.d.ts +75 -0
- package/dist/report/text/layout.js +173 -0
- package/dist/report/text/plot.d.ts +37 -0
- package/dist/report/text/plot.js +81 -0
- package/dist/report/text/table.d.ts +8 -0
- package/dist/report/text/table.js +86 -0
- package/dist/report/tree.d.ts +99 -0
- package/dist/report/tree.js +228 -0
- package/dist/report/types.d.ts +408 -0
- package/dist/report/types.js +4 -0
- package/dist/report/web.d.ts +15 -0
- package/dist/report/web.js +37 -0
- package/dist/results/locator.d.ts +75 -0
- package/dist/results/locator.js +0 -0
- package/dist/results/select.d.ts +45 -0
- package/dist/results/select.js +230 -0
- package/dist/results/source-hash.d.ts +9 -0
- package/dist/results/types.d.ts +204 -0
- package/dist/runner/eval-source.d.ts +22 -0
- package/dist/runner/fingerprint.d.ts +23 -0
- package/dist/runner/types.d.ts +332 -0
- package/dist/sandbox/docker-stream.d.ts +24 -0
- package/dist/sandbox/docker.d.ts +84 -0
- package/dist/sandbox/e2b.d.ts +31 -0
- package/dist/sandbox/errors.d.ts +4 -0
- package/dist/sandbox/local-files.d.ts +6 -0
- package/dist/sandbox/paths.d.ts +4 -0
- package/dist/sandbox/registry.d.ts +13 -0
- package/dist/sandbox/resolve.d.ts +40 -0
- package/dist/sandbox/retry.d.ts +10 -0
- package/dist/sandbox/shell.d.ts +11 -0
- package/dist/sandbox/source-files.d.ts +13 -0
- package/dist/sandbox/types.d.ts +203 -0
- package/dist/sandbox/vercel.d.ts +37 -0
- package/dist/scoring/types.d.ts +70 -0
- package/dist/shared/aggregate.d.ts +29 -0
- package/dist/shared/aggregate.js +55 -0
- package/dist/shared/types.d.ts +27 -0
- package/dist/shared/verdict.d.ts +27 -0
- package/dist/shared/verdict.js +34 -0
- package/dist/tty-line.d.ts +6 -0
- package/dist/types.d.ts +7 -0
- package/dist/util.d.ts +22 -0
- package/docs-site/zh/concepts/adapter.mdx +7 -7
- package/docs-site/zh/concepts/assert.mdx +19 -18
- package/docs-site/zh/concepts/evals.mdx +12 -11
- package/docs-site/zh/concepts/experiment.mdx +2 -2
- package/docs-site/zh/concepts/judge.mdx +9 -9
- package/docs-site/zh/concepts/overview.mdx +3 -3
- package/docs-site/zh/concepts/tier.mdx +6 -6
- package/docs-site/zh/example/claude-code-codex-plugin.mdx +9 -5
- package/docs-site/zh/example/claude-code-codex-skill.mdx +12 -7
- package/docs-site/zh/guides/agent-feedback-loop.mdx +237 -78
- package/docs-site/zh/guides/connect-otel.mdx +3 -3
- package/docs-site/zh/guides/connect-your-agent.mdx +2 -2
- package/docs-site/zh/guides/custom-reports.mdx +196 -36
- package/docs-site/zh/guides/experiments.mdx +7 -1
- package/docs-site/zh/guides/fixtures.mdx +4 -2
- package/docs-site/zh/guides/official-adapters.mdx +31 -9
- package/docs-site/zh/guides/publish-report.mdx +4 -4
- package/docs-site/zh/guides/report-components.mdx +194 -55
- package/docs-site/zh/guides/reporters.mdx +2 -2
- package/docs-site/zh/guides/results-data.mdx +61 -34
- package/docs-site/zh/guides/runner.mdx +2 -2
- package/docs-site/zh/guides/sandbox-agent.mdx +3 -2
- package/docs-site/zh/guides/{sandbox-backends.mdx → sandbox-providers.mdx} +12 -12
- package/docs-site/zh/guides/viewing-results.mdx +200 -79
- package/docs-site/zh/guides/write-experiment.mdx +9 -1
- package/docs-site/zh/guides/write-send.mdx +4 -3
- package/docs-site/zh/index.mdx +4 -3
- package/docs-site/zh/introduction.mdx +2 -1
- package/docs-site/zh/quickstart.mdx +5 -3
- package/docs-site/zh/reference/builtin-agents.mdx +38 -13
- package/docs-site/zh/reference/capabilities.mdx +1 -1
- package/docs-site/zh/reference/cli.mdx +36 -13
- package/docs-site/zh/reference/define-agent.mdx +15 -13
- package/docs-site/zh/reference/define-config.mdx +1 -1
- package/docs-site/zh/reference/define-eval.mdx +3 -3
- package/docs-site/zh/reference/events.mdx +9 -3
- package/docs-site/zh/reference/expect.mdx +13 -8
- package/package.json +10 -6
- package/src/agents/bub.ts +129 -42
- package/src/agents/claude-code.test.ts +152 -0
- package/src/agents/claude-code.ts +127 -13
- package/src/agents/codex.test.ts +192 -0
- package/src/agents/codex.ts +151 -12
- package/src/agents/index.ts +9 -3
- package/src/agents/manifest.ts +41 -0
- package/src/agents/plugin-config.test.ts +94 -0
- package/src/agents/shared.ts +33 -2
- package/src/agents/skills.test.ts +214 -0
- package/src/agents/skills.ts +304 -0
- package/src/agents/streaming.ts +5 -5
- package/src/agents/types.ts +59 -3
- package/src/cli.ts +74 -47
- package/src/context/context.test.ts +20 -2
- package/src/context/control-flow.ts +1 -1
- package/src/context/session.test.ts +92 -1
- package/src/context/session.ts +23 -1
- package/src/context/types.ts +4 -4
- package/src/define.test.ts +8 -8
- package/src/define.ts +11 -11
- package/src/expect/index.ts +5 -5
- package/src/i18n/en.ts +33 -15
- package/src/i18n/zh-CN.ts +37 -21
- package/src/index.ts +1 -1
- package/src/o11y/execution-tree.test.ts +452 -0
- package/src/o11y/execution-tree.ts +367 -0
- package/src/o11y/otlp/receiver.ts +1 -1
- package/src/o11y/otlp/select.ts +7 -3
- package/src/o11y/parsers/claude-code.test.ts +175 -0
- package/src/o11y/parsers/claude-code.ts +32 -0
- package/src/o11y/types.ts +6 -1
- package/src/report/aggregate.ts +26 -20
- package/src/report/built-in-user-parity.test.tsx +640 -0
- package/src/report/built-ins/experiment-comparison.tsx +19 -0
- package/src/report/built-ins/index.ts +2 -0
- package/src/report/components.tsx +225 -50
- package/src/report/compute.ts +335 -54
- package/src/report/dual-render.test.tsx +1129 -0
- package/src/report/flag.ts +1 -1
- package/src/report/format.ts +35 -2
- package/src/report/index.ts +47 -14
- package/src/report/load.ts +1 -1
- package/src/report/locale.ts +229 -0
- package/src/report/metrics.ts +39 -15
- package/src/report/primitives.tsx +100 -2
- package/src/report/react/AttemptList.tsx +113 -0
- package/src/report/react/DeltaTable.tsx +9 -6
- package/src/report/react/EvalList.tsx +0 -0
- package/src/report/react/ExperimentList.tsx +220 -0
- package/src/report/react/GroupSummary.tsx +66 -0
- package/src/report/react/MetricBars.tsx +24 -13
- package/src/report/react/MetricLine.tsx +21 -21
- package/src/report/react/MetricMatrix.tsx +8 -4
- package/src/report/react/MetricScatter.tsx +126 -96
- package/src/report/react/MetricTable.tsx +115 -15
- package/src/report/react/RunOverview.tsx +48 -26
- package/src/report/react/Scoreboard.tsx +15 -7
- package/src/report/react/cell.tsx +18 -9
- package/src/{view/app/lib/chart.ts → report/react/chart-math.ts} +2 -6
- package/src/report/react/colors.ts +24 -15
- package/src/report/react/enhance.js +168 -0
- package/src/report/react/fixtures.ts +169 -34
- package/src/report/react/format.ts +1 -1
- package/src/report/react/index.tsx +21 -6
- package/src/report/react/render.test.tsx +180 -31
- package/src/report/react/styles.css +432 -213
- package/src/report/report.test.ts +398 -94
- package/src/report/report.ts +29 -11
- package/src/report/text/faces.ts +344 -96
- package/src/report/text/layout.ts +76 -11
- package/src/report/text/table.ts +98 -0
- package/src/report/tree.ts +103 -20
- package/src/report/types.ts +184 -25
- package/src/report/web.ts +46 -19
- package/src/results/annotated-source.test.ts +146 -0
- package/src/results/annotated-source.ts +128 -0
- package/src/results/attempt-evidence.test.ts +158 -0
- package/src/results/attempt-evidence.ts +158 -0
- package/src/results/attempt-source.ts +48 -0
- package/src/results/copy.ts +154 -139
- package/src/results/format.ts +54 -47
- package/src/results/host-equivalence.test.ts +527 -0
- package/src/results/index.ts +56 -14
- package/src/results/locator.test.ts +198 -0
- package/src/results/locator.ts +0 -0
- package/src/results/open.ts +392 -175
- package/src/results/results.test.ts +943 -494
- package/src/results/select.ts +129 -23
- package/src/results/skipped-notice.ts +0 -0
- package/src/results/source-hash.ts +28 -0
- package/src/results/types.ts +98 -62
- package/src/results/writer.ts +304 -176
- package/src/runner/attempt.test.ts +170 -0
- package/src/runner/attempt.ts +48 -13
- package/src/runner/discover.test.ts +65 -0
- package/src/runner/discover.ts +6 -2
- package/src/runner/eval-source.test.ts +121 -0
- package/src/runner/eval-source.ts +45 -0
- package/src/runner/fingerprint.ts +54 -1
- package/src/runner/remote-sandbox.ts +1 -1
- package/src/runner/report.test.ts +6 -8
- package/src/runner/report.ts +5 -4
- package/src/runner/reporters/artifacts.ts +27 -41
- package/src/runner/reporters/braintrust.test.ts +3 -3
- package/src/runner/reporters/braintrust.ts +1 -1
- package/src/runner/reporters/console.ts +6 -6
- package/src/runner/reporters/json.ts +4 -4
- package/src/runner/reporters/live.test.ts +56 -0
- package/src/runner/reporters/live.ts +36 -10
- package/src/runner/reporters/quiet.test.ts +66 -0
- package/src/runner/reporters/quiet.ts +49 -0
- package/src/runner/reporters/shared.ts +5 -5
- package/src/runner/reporters/table.ts +17 -17
- package/src/runner/run.ts +61 -102
- package/src/runner/types.ts +43 -32
- package/src/sandbox/checkpoint.ts +1 -1
- package/src/sandbox/docker.ts +15 -2
- package/src/sandbox/e2b.ts +11 -5
- package/src/sandbox/errors.ts +13 -0
- package/src/sandbox/index.ts +3 -3
- package/src/sandbox/local-files.ts +1 -1
- package/src/sandbox/registry.ts +6 -5
- package/src/sandbox/resolve.ts +38 -23
- package/src/sandbox/retry.test.ts +68 -0
- package/src/sandbox/retry.ts +44 -0
- package/src/sandbox/types.ts +24 -24
- package/src/sandbox/vercel.ts +17 -3
- package/src/scoring/collector.ts +3 -3
- package/src/scoring/judge.ts +2 -2
- package/src/scoring/scoped.ts +13 -1
- package/src/scoring/types.ts +7 -7
- package/src/scoring/verdict.ts +4 -4
- package/src/shared/aggregate.ts +23 -3
- package/src/shared/types.ts +2 -2
- package/src/shared/{outcome.ts → verdict.ts} +15 -15
- package/src/show/compose.ts +12 -132
- package/src/show/index.ts +119 -95
- package/src/show/render.ts +462 -159
- package/src/show/show.test.ts +471 -253
- package/src/source-loc.ts +1 -1
- package/src/tty-line.ts +32 -0
- package/src/types.ts +2 -2
- package/src/util.test.ts +21 -1
- package/src/util.ts +5 -1
- package/src/view/app/App.tsx +33 -198
- package/src/view/app/components/AttemptModal.tsx +6 -6
- package/src/view/app/components/CodeView.tsx +2 -2
- package/src/view/app/components/CopyControls.tsx +32 -36
- package/src/view/app/components/SkippedRunsBanner.tsx +140 -0
- package/src/view/app/components/ui/badge.tsx +1 -1
- package/src/view/app/components/ui/dialog.tsx +2 -2
- package/src/view/app/i18n.ts +40 -31
- package/src/view/app/lib/artifact-url.ts +1 -1
- package/src/view/app/lib/attempt-route.test.ts +37 -47
- package/src/view/app/lib/attempt-route.ts +26 -26
- package/src/view/app/lib/rows.ts +9 -112
- package/src/view/app/lib/verdict.ts +25 -0
- package/src/view/app/main.tsx +9 -12
- package/src/view/app/pages/RunsPage.tsx +4 -4
- package/src/view/app/pages/TracesPage.tsx +3 -3
- package/src/view/app/shared.ts +0 -1
- package/src/view/app/types.ts +6 -51
- package/src/view/artifact-serving.test.ts +136 -0
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +21 -21
- package/src/view/data.test.ts +214 -143
- package/src/view/data.ts +166 -120
- package/src/view/index.ts +23 -11
- package/src/view/server.ts +52 -17
- package/src/view/shared/types.ts +22 -31
- package/src/view/styles.css +117 -327
- package/src/view/view-report.test.ts +146 -98
- package/src/report/default-report.tsx +0 -222
- package/src/report/dual-face.test.tsx +0 -527
- package/src/report/react/CaseList.tsx +0 -70
- package/src/view/app/components/CostScoreChart.tsx +0 -147
- package/src/view/app/components/ExperimentTable.tsx +0 -284
- package/src/view/app/components/GroupSelector.tsx +0 -61
- package/src/view/app/components/primitives.tsx +0 -43
- package/src/view/app/lib/outcome.ts +0 -82
|
@@ -1,71 +1,171 @@
|
|
|
1
|
-
// MetricTable:行维度 ×
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// MetricTable:行维度 × 指标列。没有实体下钻——要展开到 experiment 的 Eval 或 Eval 的
|
|
2
|
+
// Attempt,用 ExperimentList / EvalList,这个组件只表达任意维度 × 任意指标。
|
|
3
|
+
// 行按传入顺序渲染——排序发生在计算侧(tableData 的 sort 参数),组件不重排;
|
|
4
|
+
// 静态 HTML 以数据侧预排的顺序呈现即完整。web 面额外输出渐进增强的 data 属性:
|
|
5
|
+
// 所有表头带 data-nre-sort、格子带 data-sort-value,enhance.js 在场时点表头
|
|
6
|
+
// 可就地重排(纯展示态交互,不改口径);filter 开时在表格前渲染过滤输入框。
|
|
7
|
+
// meta 在场(rows: "experiment")时补 Model / Agent / Verdicts 列,列序对齐 view
|
|
8
|
+
// 原生榜单:experiment、model、agent、指标列…、verdicts。
|
|
4
9
|
// 列头以箭头标注 better 方向;samples < total 的格子带覆盖率角标;
|
|
5
10
|
// 一组全 null 渲染成「缺数据」,绝不画 0(逻辑在 MetricCellView)。
|
|
6
11
|
|
|
7
12
|
import type { ReactElement } from "react";
|
|
8
|
-
import type {
|
|
13
|
+
import type { TableData, TableRowMeta } from "../types.ts";
|
|
14
|
+
import type { AttemptLocator } from "../../results/locator.ts";
|
|
15
|
+
import { DEFAULT_REPORT_LOCALE, localeText, resolveMetricLabel, type ReportLocale } from "../locale.ts";
|
|
9
16
|
import { MetricCellView } from "./cell.tsx";
|
|
10
17
|
import { colorClassForKey } from "./colors.ts";
|
|
11
18
|
import { cx } from "./format.ts";
|
|
12
19
|
|
|
20
|
+
/** verdict 计票 pill(「3 passed / 1 failed」):非零判定各一枚,全零如实空。 */
|
|
21
|
+
function VerdictTally({
|
|
22
|
+
verdicts,
|
|
23
|
+
locale,
|
|
24
|
+
}: {
|
|
25
|
+
verdicts: NonNullable<TableRowMeta["verdicts"]>;
|
|
26
|
+
locale: ReportLocale;
|
|
27
|
+
}): ReactElement {
|
|
28
|
+
const kinds = (["passed", "failed", "errored", "skipped"] as const).filter((k) => verdicts[k] > 0);
|
|
29
|
+
return (
|
|
30
|
+
<span className="nre-verdict-tally">
|
|
31
|
+
{kinds.map((kind) => (
|
|
32
|
+
<span key={kind} className={cx("nre-verdict-pill", `nre-verdict-${kind}`)}>
|
|
33
|
+
{verdicts[kind]} {localeText(locale, `verdict.${kind}`)}
|
|
34
|
+
</span>
|
|
35
|
+
))}
|
|
36
|
+
{kinds.length === 0 && <span className="nre-missing">—</span>}
|
|
37
|
+
</span>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
13
41
|
export function MetricTable({
|
|
14
42
|
data,
|
|
15
43
|
attemptHref,
|
|
44
|
+
filter,
|
|
16
45
|
className,
|
|
46
|
+
locale = DEFAULT_REPORT_LOCALE,
|
|
17
47
|
}: {
|
|
18
48
|
data: TableData;
|
|
19
|
-
attemptHref?: (
|
|
49
|
+
attemptHref?: (locator: AttemptLocator) => string;
|
|
50
|
+
filter?: boolean;
|
|
20
51
|
className?: string;
|
|
52
|
+
locale?: ReportLocale;
|
|
21
53
|
}): ReactElement {
|
|
22
|
-
|
|
23
|
-
|
|
54
|
+
const hasMeta = data.rows.some((row) => row.meta !== undefined);
|
|
55
|
+
const hasModel = data.rows.some((row) => row.meta?.model !== undefined);
|
|
56
|
+
const hasVerdicts = data.rows.some((row) => row.meta?.verdicts !== undefined);
|
|
57
|
+
|
|
58
|
+
const table = (
|
|
59
|
+
<table className={cx("nre", "nre-metric-table", !filter && className)}>
|
|
24
60
|
<thead>
|
|
25
61
|
<tr>
|
|
26
|
-
<th scope="col" className="nre-dimension">
|
|
62
|
+
<th scope="col" className="nre-dimension" data-nre-sort="">
|
|
27
63
|
{data.dimension}
|
|
28
64
|
</th>
|
|
65
|
+
{hasMeta && hasModel && (
|
|
66
|
+
<th scope="col" className="nre-meta-col" data-nre-sort="">
|
|
67
|
+
{localeText(locale, "table.model")}
|
|
68
|
+
</th>
|
|
69
|
+
)}
|
|
70
|
+
{hasMeta && (
|
|
71
|
+
<th scope="col" className="nre-meta-col" data-nre-sort="">
|
|
72
|
+
{localeText(locale, "table.agent")}
|
|
73
|
+
</th>
|
|
74
|
+
)}
|
|
29
75
|
{data.columns.map((col) => (
|
|
30
|
-
<th scope="col" key={col.key} className="nre-metric-col">
|
|
31
|
-
{col.label}
|
|
76
|
+
<th scope="col" key={col.key} className="nre-metric-col" data-nre-sort="">
|
|
77
|
+
{resolveMetricLabel(col.label, locale, col.key)}
|
|
32
78
|
{col.unit && <span className="nre-unit">({col.unit})</span>}
|
|
33
79
|
{/* better 方向提示:↑ 越高越好 / ↓ 越低越好 */}
|
|
34
80
|
{col.better && (
|
|
35
81
|
<span
|
|
36
82
|
className="nre-better"
|
|
37
|
-
title={col.better === "higher" ? "
|
|
83
|
+
title={localeText(locale, col.better === "higher" ? "table.higherBetter" : "table.lowerBetter")}
|
|
38
84
|
>
|
|
39
85
|
{col.better === "higher" ? "↑" : "↓"}
|
|
40
86
|
</span>
|
|
41
87
|
)}
|
|
42
88
|
</th>
|
|
43
89
|
))}
|
|
90
|
+
{hasVerdicts && (
|
|
91
|
+
<th scope="col" className="nre-verdicts-col" data-nre-sort="">
|
|
92
|
+
{localeText(locale, "table.verdicts")}
|
|
93
|
+
</th>
|
|
94
|
+
)}
|
|
44
95
|
</tr>
|
|
45
96
|
</thead>
|
|
46
97
|
<tbody>
|
|
47
98
|
{data.rows.map((row) => (
|
|
48
99
|
<tr key={row.key}>
|
|
49
100
|
{/* 行键 = 维度键(如 agent):稳定散列上色,跨块同键同色 */}
|
|
50
|
-
<th
|
|
101
|
+
<th
|
|
102
|
+
scope="row"
|
|
103
|
+
className={cx("nre-row-key", "nre-key", colorClassForKey(row.key))}
|
|
104
|
+
data-sort-value={row.key}
|
|
105
|
+
>
|
|
51
106
|
{row.key}
|
|
107
|
+
{/* rows: "experiment" 专属:eval/attempt 数 + 最后运行时间,行键下的一行紧凑摘要
|
|
108
|
+
(旧 ExperimentRow 的 "N eval results · N runs · 最后运行时间") */}
|
|
109
|
+
{row.meta?.evals !== undefined && (
|
|
110
|
+
<div className="nre-row-meta-sub">
|
|
111
|
+
{localeText(locale, "overview.evalsCount", { n: row.meta.evals })}
|
|
112
|
+
{row.meta.attempts !== undefined && row.meta.attempts > row.meta.evals
|
|
113
|
+
? ` · ${localeText(locale, "overview.attemptsCount", { n: row.meta.attempts })}`
|
|
114
|
+
: ""}
|
|
115
|
+
{row.meta.lastRunAt ? ` · ${localeText(locale, "latestRun", { run: row.meta.lastRunAt })}` : ""}
|
|
116
|
+
</div>
|
|
117
|
+
)}
|
|
52
118
|
</th>
|
|
119
|
+
{hasMeta && hasModel && (
|
|
120
|
+
<td className="nre-td nre-meta-cell" data-sort-value={row.meta?.model ?? ""}>
|
|
121
|
+
{row.meta?.model ?? <span className="nre-missing">—</span>}
|
|
122
|
+
</td>
|
|
123
|
+
)}
|
|
124
|
+
{hasMeta && (
|
|
125
|
+
<td className="nre-td nre-meta-cell" data-sort-value={row.meta?.agent ?? ""}>
|
|
126
|
+
{row.meta?.agent ?? <span className="nre-missing">—</span>}
|
|
127
|
+
</td>
|
|
128
|
+
)}
|
|
53
129
|
{data.columns.map((col) => {
|
|
54
130
|
const cell = row.cells[col.key];
|
|
55
131
|
return (
|
|
56
|
-
<td key={col.key} className="nre-td">
|
|
132
|
+
<td key={col.key} className="nre-td" data-sort-value={cell?.value ?? ""}>
|
|
57
133
|
{cell ? (
|
|
58
|
-
<MetricCellView cell={cell} attemptHref={attemptHref} />
|
|
134
|
+
<MetricCellView cell={cell} attemptHref={attemptHref} locale={locale} />
|
|
59
135
|
) : (
|
|
60
|
-
// 数据侧没给这个格子(理论上
|
|
136
|
+
// 数据侧没给这个格子(理论上 tableData 不会缺列)——按空处理,不编数
|
|
61
137
|
<span className="nre-empty" />
|
|
62
138
|
)}
|
|
63
139
|
</td>
|
|
64
140
|
);
|
|
65
141
|
})}
|
|
142
|
+
{hasVerdicts && (
|
|
143
|
+
<td className="nre-td nre-verdicts-cell" data-sort-value={row.meta?.verdicts?.passed ?? ""}>
|
|
144
|
+
{row.meta?.verdicts ? (
|
|
145
|
+
<VerdictTally verdicts={row.meta.verdicts} locale={locale} />
|
|
146
|
+
) : (
|
|
147
|
+
<span className="nre-missing">—</span>
|
|
148
|
+
)}
|
|
149
|
+
</td>
|
|
150
|
+
)}
|
|
66
151
|
</tr>
|
|
67
152
|
))}
|
|
68
153
|
</tbody>
|
|
69
154
|
</table>
|
|
70
155
|
);
|
|
156
|
+
|
|
157
|
+
if (!filter) return table;
|
|
158
|
+
// 过滤输入框渲染在表格前(同一个 wrap 里),enhance.js 经 data-nre-filter 接管;
|
|
159
|
+
// 无 JS 时静默无功能,表格内容依旧完整。
|
|
160
|
+
return (
|
|
161
|
+
<div className={cx("nre", "nre-metric-table-wrap", className)}>
|
|
162
|
+
<input
|
|
163
|
+
className="nre-filter"
|
|
164
|
+
data-nre-filter=""
|
|
165
|
+
type="search"
|
|
166
|
+
placeholder={localeText(locale, "table.filterPlaceholder")}
|
|
167
|
+
/>
|
|
168
|
+
{table}
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
71
171
|
}
|
|
@@ -1,69 +1,91 @@
|
|
|
1
1
|
// RunOverview:页头 KPI 条——「这批数据是什么」。
|
|
2
2
|
// 数字下面标注数据来源(几个快照、何时跑的);warnings 有内容时直接显示在条内,
|
|
3
|
-
// 诚实不靠使用者记得渲染(docs/reports.md
|
|
3
|
+
// 诚实不靠使用者记得渲染(docs/feature/reports/library.md「RunOverview」行为清单)。
|
|
4
4
|
|
|
5
5
|
import type { ReactElement } from "react";
|
|
6
6
|
import type { OverviewData } from "../types.ts";
|
|
7
|
-
import {
|
|
7
|
+
import { DEFAULT_REPORT_LOCALE, localeText, type ReportLocale } from "../locale.ts";
|
|
8
|
+
import { cx, formatDurationMs, formatUSD } from "./format.ts";
|
|
8
9
|
|
|
9
10
|
export function RunOverview({
|
|
10
11
|
data,
|
|
11
12
|
className,
|
|
13
|
+
locale = DEFAULT_REPORT_LOCALE,
|
|
12
14
|
}: {
|
|
13
15
|
data: OverviewData;
|
|
14
16
|
className?: string;
|
|
17
|
+
locale?: ReportLocale;
|
|
15
18
|
}): ReactElement {
|
|
16
19
|
const { totals } = data;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
const missing = <span className="nre-missing">{localeText(locale, "cell.missing")}</span>;
|
|
21
|
+
// 通过率只渲染 computeCell 算好的 MetricCell,不现场重算——覆盖率角标复用
|
|
22
|
+
// MetricCellView 的缺数据/coverage 语义(缺数据 = 显式文案,绝不画 0%)
|
|
23
|
+
const { passRate } = totals;
|
|
24
|
+
const passRateNode =
|
|
25
|
+
passRate.value === null ? (
|
|
26
|
+
missing
|
|
27
|
+
) : (
|
|
28
|
+
<>
|
|
29
|
+
{passRate.display}
|
|
30
|
+
{passRate.samples < passRate.total && (
|
|
31
|
+
<sup
|
|
32
|
+
className="nre-coverage"
|
|
33
|
+
title={localeText(locale, "cell.coverageTitle", { samples: passRate.samples, total: passRate.total })}
|
|
34
|
+
>
|
|
35
|
+
{passRate.samples}/{passRate.total}
|
|
36
|
+
</sup>
|
|
37
|
+
)}
|
|
38
|
+
</>
|
|
39
|
+
);
|
|
20
40
|
|
|
21
41
|
return (
|
|
22
42
|
<header className={cx("nre", "nre-overview", className)}>
|
|
23
43
|
<dl className="nre-kpis">
|
|
24
44
|
<div className="nre-kpi">
|
|
25
|
-
<dt>
|
|
45
|
+
<dt>{localeText(locale, "overview.snapshots")}</dt>
|
|
26
46
|
<dd>{data.snapshots.length}</dd>
|
|
27
47
|
</div>
|
|
28
48
|
<div className="nre-kpi">
|
|
29
|
-
<dt>
|
|
49
|
+
<dt>{localeText(locale, "overview.evals")}</dt>
|
|
30
50
|
<dd>{totals.evals}</dd>
|
|
31
51
|
</div>
|
|
32
52
|
<div className="nre-kpi">
|
|
33
|
-
<dt>attempts</dt>
|
|
53
|
+
<dt>{localeText(locale, "overview.attempts")}</dt>
|
|
34
54
|
<dd>{totals.attempts}</dd>
|
|
35
55
|
</div>
|
|
36
56
|
<div className="nre-kpi">
|
|
37
|
-
<dt>
|
|
38
|
-
<dd>{
|
|
57
|
+
<dt>{localeText(locale, "overview.passRate")}</dt>
|
|
58
|
+
<dd>{passRateNode}</dd>
|
|
39
59
|
</div>
|
|
40
60
|
<div className="nre-kpi">
|
|
41
|
-
<dt>
|
|
61
|
+
<dt>{localeText(locale, "overview.totalCost")}</dt>
|
|
42
62
|
{/* costUSD 全缺 = null:显示缺数据,不编 $0 */}
|
|
43
|
-
<dd>
|
|
44
|
-
{totals.costUSD === null ? (
|
|
45
|
-
<span className="nre-missing">{MISSING_TEXT}</span>
|
|
46
|
-
) : (
|
|
47
|
-
formatUSD(totals.costUSD)
|
|
48
|
-
)}
|
|
49
|
-
</dd>
|
|
63
|
+
<dd>{totals.costUSD === null ? missing : formatUSD(totals.costUSD)}</dd>
|
|
50
64
|
</div>
|
|
51
65
|
<div className="nre-kpi">
|
|
52
|
-
<dt>
|
|
66
|
+
<dt>{localeText(locale, "overview.totalDuration")}</dt>
|
|
53
67
|
<dd>{formatDurationMs(totals.durationMs)}</dd>
|
|
54
68
|
</div>
|
|
55
69
|
</dl>
|
|
56
70
|
|
|
57
|
-
<p className="nre-
|
|
58
|
-
<span className="nre-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
<span className="nre-
|
|
71
|
+
<p className="nre-verdicts">
|
|
72
|
+
<span className="nre-verdict nre-verdict-passed">
|
|
73
|
+
{localeText(locale, "verdict.passed")} {totals.passed}
|
|
74
|
+
</span>
|
|
75
|
+
<span className="nre-verdict nre-verdict-failed">
|
|
76
|
+
{localeText(locale, "verdict.failed")} {totals.failed}
|
|
77
|
+
</span>
|
|
78
|
+
<span className="nre-verdict nre-verdict-errored">
|
|
79
|
+
{localeText(locale, "verdict.errored")} {totals.errored}
|
|
80
|
+
</span>
|
|
81
|
+
<span className="nre-verdict nre-verdict-skipped">
|
|
82
|
+
{localeText(locale, "verdict.skipped")} {totals.skipped}
|
|
83
|
+
</span>
|
|
62
84
|
</p>
|
|
63
85
|
|
|
64
86
|
{/* 数据来源:哪些快照、何时跑的——报告的数字都从这里来 */}
|
|
65
87
|
<p className="nre-source">
|
|
66
|
-
|
|
88
|
+
{localeText(locale, "overview.source", { n: data.snapshots.length })}
|
|
67
89
|
{data.snapshots.map((s) => (
|
|
68
90
|
<span key={`${s.experimentId}@${s.startedAt}`} className="nre-source-snapshot">
|
|
69
91
|
{s.experimentId}({s.agent}
|
|
@@ -72,7 +94,7 @@ export function RunOverview({
|
|
|
72
94
|
))}
|
|
73
95
|
</p>
|
|
74
96
|
|
|
75
|
-
{/*
|
|
97
|
+
{/* Selection 的警告(残缺快照等)直接渲染在条内,不静默;结构化字段供程序判断,这里打 message */}
|
|
76
98
|
{data.warnings.length > 0 && (
|
|
77
99
|
<ul className="nre-warnings">
|
|
78
100
|
{data.warnings.map((w, i) => (
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
// Scoreboard:考试成绩单——总分 + 分科小计。
|
|
2
2
|
// 固定分母的口径不藏:没跑的题挣 0 分但留在分母里,科目行如实报 missing;
|
|
3
|
-
// weights 是「实际生效的权重表」,渲染出来让成绩单可审计(docs/reports.md
|
|
3
|
+
// weights 是「实际生效的权重表」,渲染出来让成绩单可审计(docs/feature/reports/library.md「Scoreboard」)。
|
|
4
4
|
|
|
5
5
|
import type { ReactElement } from "react";
|
|
6
6
|
import type { ScoreboardData } from "../types.ts";
|
|
7
|
+
import { DEFAULT_REPORT_LOCALE, countText, localeText, type ReportLocale } from "../locale.ts";
|
|
7
8
|
import { colorClassForKey } from "./colors.ts";
|
|
8
9
|
import { cx } from "./format.ts";
|
|
9
10
|
|
|
10
11
|
export function Scoreboard({
|
|
11
12
|
data,
|
|
12
13
|
className,
|
|
14
|
+
locale = DEFAULT_REPORT_LOCALE,
|
|
13
15
|
}: {
|
|
14
16
|
data: ScoreboardData;
|
|
15
17
|
className?: string;
|
|
18
|
+
locale?: ReportLocale;
|
|
16
19
|
}): ReactElement {
|
|
17
20
|
// 科目列 = 各行 subjects 的并集,按首次出现顺序;固定分母下各行本应一致,这里防御性合并
|
|
18
21
|
const subjectKeys: string[] = [];
|
|
@@ -31,7 +34,8 @@ export function Scoreboard({
|
|
|
31
34
|
{data.dimension}
|
|
32
35
|
</th>
|
|
33
36
|
<th scope="col" className="nre-total-col">
|
|
34
|
-
|
|
37
|
+
{localeText(locale, "scoreboard.total")}
|
|
38
|
+
<span className="nre-full-marks">/ {data.fullMarks}</span>
|
|
35
39
|
</th>
|
|
36
40
|
{subjectKeys.map((key) => (
|
|
37
41
|
<th scope="col" key={key} className="nre-subject-col">
|
|
@@ -55,13 +59,17 @@ export function Scoreboard({
|
|
|
55
59
|
<td key={key} className="nre-subject">
|
|
56
60
|
<span
|
|
57
61
|
className="nre-subject-score"
|
|
58
|
-
title={
|
|
62
|
+
title={localeText(locale, "scoreboard.subjectTitle", {
|
|
63
|
+
evals: subject.evals,
|
|
64
|
+
earned: subject.earned,
|
|
65
|
+
possible: subject.possible,
|
|
66
|
+
})}
|
|
59
67
|
>
|
|
60
68
|
{subject.earned}/{subject.possible}
|
|
61
69
|
</span>
|
|
62
70
|
{/* 固定分母的如实注脚:没跑、按 0 计的题数 */}
|
|
63
71
|
{subject.missing > 0 && (
|
|
64
|
-
<span className="nre-subject-missing">{
|
|
72
|
+
<span className="nre-subject-missing">{countText(locale, "scoreboard.missing", subject.missing)}</span>
|
|
65
73
|
)}
|
|
66
74
|
</td>
|
|
67
75
|
);
|
|
@@ -72,15 +80,15 @@ export function Scoreboard({
|
|
|
72
80
|
</table>
|
|
73
81
|
{/* 实际生效的权重表:成绩单可审计 */}
|
|
74
82
|
<p className="nre-weights">
|
|
75
|
-
weights
|
|
83
|
+
{localeText(locale, "scoreboard.weights")}{" "}
|
|
76
84
|
{data.weights.length === 0
|
|
77
|
-
?
|
|
85
|
+
? localeText(locale, "scoreboard.allWeights")
|
|
78
86
|
: data.weights.map((w) => (
|
|
79
87
|
<span key={w.prefix} className="nre-weight">
|
|
80
88
|
{w.prefix} ×{w.weight}
|
|
81
89
|
</span>
|
|
82
90
|
))}
|
|
83
|
-
{data.weights.length > 0 && <span className="nre-weight-rest">
|
|
91
|
+
{data.weights.length > 0 && <span className="nre-weight-rest">{localeText(locale, "scoreboard.othersWeight")}</span>}
|
|
84
92
|
</p>
|
|
85
93
|
</section>
|
|
86
94
|
);
|
|
@@ -3,42 +3,51 @@
|
|
|
3
3
|
// 纯渲染、零 hooks;交互只有普通 <a>(下钻由使用者的 attemptHref 决定去处)。
|
|
4
4
|
|
|
5
5
|
import type { ReactElement } from "react";
|
|
6
|
-
import type {
|
|
7
|
-
import {
|
|
6
|
+
import type { MetricCell } from "../types.ts";
|
|
7
|
+
import type { AttemptLocator } from "../../results/locator.ts";
|
|
8
|
+
import { DEFAULT_REPORT_LOCALE, localeText, type ReportLocale } from "../locale.ts";
|
|
8
9
|
|
|
9
10
|
export function MetricCellView({
|
|
10
11
|
cell,
|
|
11
12
|
attemptHref,
|
|
13
|
+
locale = DEFAULT_REPORT_LOCALE,
|
|
12
14
|
}: {
|
|
13
15
|
cell: MetricCell;
|
|
14
|
-
attemptHref?: (
|
|
16
|
+
attemptHref?: (locator: AttemptLocator) => string;
|
|
17
|
+
locale?: ReportLocale;
|
|
15
18
|
}): ReactElement {
|
|
16
19
|
// 全 null(没有任何有效样本)→ 缺数据文案,绝不画 0;total 仍如实入 title
|
|
17
20
|
if (cell.value === null) {
|
|
18
21
|
return (
|
|
19
22
|
<span className="nre-cell nre-cell-missing">
|
|
20
|
-
<span className="nre-missing" title={
|
|
21
|
-
{
|
|
23
|
+
<span className="nre-missing" title={localeText(locale, "cell.noneMeasurableTitle", { total: cell.total })}>
|
|
24
|
+
{localeText(locale, "cell.missing")}
|
|
22
25
|
</span>
|
|
23
26
|
</span>
|
|
24
27
|
);
|
|
25
28
|
}
|
|
26
29
|
return (
|
|
27
30
|
<span className="nre-cell">
|
|
28
|
-
<span
|
|
31
|
+
<span
|
|
32
|
+
className="nre-value"
|
|
33
|
+
title={localeText(locale, "cell.measuredTitle", { samples: cell.samples, total: cell.total })}
|
|
34
|
+
>
|
|
29
35
|
{cell.display}
|
|
30
36
|
</span>
|
|
31
37
|
{/* samples < total:有 attempt 测不了这个指标,覆盖率角标如实标出 */}
|
|
32
38
|
{cell.samples < cell.total && (
|
|
33
|
-
<sup
|
|
39
|
+
<sup
|
|
40
|
+
className="nre-coverage"
|
|
41
|
+
title={localeText(locale, "cell.coverageTitle", { samples: cell.samples, total: cell.total })}
|
|
42
|
+
>
|
|
34
43
|
{cell.samples}/{cell.total}
|
|
35
44
|
</sup>
|
|
36
45
|
)}
|
|
37
46
|
{/* refs + attemptHref:格子可点,「给我看那次 attempt」就在手边 */}
|
|
38
47
|
{attemptHref && cell.refs && cell.refs.length > 0 && (
|
|
39
48
|
<span className="nre-refs">
|
|
40
|
-
{cell.refs.map((
|
|
41
|
-
<a key={
|
|
49
|
+
{cell.refs.map((locator, i) => (
|
|
50
|
+
<a key={locator} className="nre-ref" href={attemptHref(locator)}>
|
|
42
51
|
#{i + 1}
|
|
43
52
|
</a>
|
|
44
53
|
))}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// 通用图表数值工具:round-number
|
|
1
|
+
// 通用图表数值工具:round-number 刻度生成与标签防撞布局,零依赖纯函数。
|
|
2
|
+
// 从 src/view/app/lib/chart.ts 迁来(view 侧从这里 re-export),报告组件与 view 共用同一份。
|
|
2
3
|
|
|
3
4
|
function niceNumber(range: number, round: boolean): number {
|
|
4
5
|
if (range <= 0) return 1;
|
|
@@ -34,11 +35,6 @@ export function niceTicks(min: number, max: number, count = 5): number[] {
|
|
|
34
35
|
return ticks;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
/** 六色分类色板之外的第 7+ 个系列一律回退到中性色,避免同色误导身份(见 dataviz 分类色板规则)。 */
|
|
38
|
-
export function seriesColor(index: number): string {
|
|
39
|
-
return index < 6 ? `var(--series-${index + 1})` : "var(--muted)";
|
|
40
|
-
}
|
|
41
|
-
|
|
42
38
|
export interface LabelInput {
|
|
43
39
|
cx: number;
|
|
44
40
|
cy: number;
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
// 跨块配色一致(docs/reports.md
|
|
1
|
+
// 跨块配色一致(docs/feature/reports/architecture.md「静态网页」):
|
|
2
2
|
// 系列/维度键 → 固定调色板下标,用稳定散列而不是「按出现顺序分配」。
|
|
3
3
|
// 这样同一个 agent 在 scatter 的线、DeltaTable 的行、matrix 的列头永远同色,
|
|
4
4
|
// 不需要 Provider、不需要手工配置,甚至不需要两个组件见过同一份数据。
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
5
|
+
//
|
|
6
|
+
// 色板与 view 统一:六色 CVD 校验色板(src/view/styles.css 的 --series-1..6),
|
|
7
|
+
// 顺序不要重排。深浅两套值都住在 styles.css 的 --nre-c0..c5(light-dark()),
|
|
8
|
+
// 「CSS 与 colors.ts 逐个对应」契约:NRE_PALETTE 是浅色主题那套值的拷贝,
|
|
9
|
+
// 渲染面优先挂类名(nre-cN 上文字色、nre-series-cN 上图形系列色)由 CSS 上色,
|
|
10
|
+
// 深色主题才能跟随;colorHexForKey 只留给「不经 CSS」的消费方。改色时两边一起改。
|
|
8
11
|
|
|
9
|
-
/**
|
|
12
|
+
/** 固定调色板(浅色主题值);下标即 nre-cN / nre-series-cN 的 N,与 styles.css 的 --nre-cN 逐个对应。 */
|
|
10
13
|
export const NRE_PALETTE = [
|
|
11
|
-
"#
|
|
12
|
-
"#
|
|
13
|
-
"#
|
|
14
|
-
"#
|
|
15
|
-
"#
|
|
16
|
-
"#
|
|
17
|
-
"#dc2626", // c6 红
|
|
18
|
-
"#65a30d", // c7 橄榄
|
|
14
|
+
"#2a78d6", // c0 蓝(dark: #3987e5)
|
|
15
|
+
"#1baf7a", // c1 绿(dark: #199e70)
|
|
16
|
+
"#eda100", // c2 琥珀(dark: #c98500)
|
|
17
|
+
"#008300", // c3 深绿(dark: #008300)
|
|
18
|
+
"#e34948", // c4 红(dark: #e66767)
|
|
19
|
+
"#eb6834", // c5 橙(dark: #d95926)
|
|
19
20
|
] as const;
|
|
20
21
|
|
|
21
22
|
export const NRE_PALETTE_SIZE = NRE_PALETTE.length;
|
|
@@ -31,12 +32,20 @@ export function colorIndexForKey(key: string): number {
|
|
|
31
32
|
return hash % NRE_PALETTE_SIZE;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
/** 键对应的稳定 class 名("nre-c3"),配 styles.css 的 .nre-cN
|
|
35
|
+
/** 键对应的稳定 class 名("nre-c3"),配 styles.css 的 .nre-cN 上文字色。 */
|
|
35
36
|
export function colorClassForKey(key: string): string {
|
|
36
37
|
return `nre-c${colorIndexForKey(key)}`;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* 键对应的系列 class 名("nre-series-c3"):挂在 SVG 图形元素(线/点/柱/系列名)上,
|
|
42
|
+
* styles.css 用它设置 --nre-series,fill/stroke 走 var —— 深色主题下图表随之切换。
|
|
43
|
+
*/
|
|
44
|
+
export function seriesClassForKey(key: string): string {
|
|
45
|
+
return `nre-series-c${colorIndexForKey(key)}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** 键对应的十六进制颜色(浅色主题值);渲染面优先类名,这里只留给不经 CSS 的消费方。 */
|
|
40
49
|
export function colorHexForKey(key: string): string {
|
|
41
50
|
return NRE_PALETTE[colorIndexForKey(key)];
|
|
42
51
|
}
|