niceeval 0.9.1 → 0.10.2
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 +31 -33
- package/dist/agents/types.d.ts +20 -17
- package/dist/context/types.d.ts +21 -21
- package/dist/i18n/en.d.ts +10 -2
- package/dist/i18n/zh-CN.d.ts +14 -6
- package/dist/o11y/execution-tree.d.ts +103 -0
- package/dist/o11y/otlp/select.d.ts +22 -0
- package/dist/report/{react → assets}/colors.d.ts +8 -0
- package/dist/report/{react → assets}/colors.js +23 -0
- package/dist/report/built-in/index.d.ts +2 -2
- package/dist/report/built-in/index.js +2 -2
- package/dist/report/built-in/standard.d.ts +8 -1
- package/dist/report/built-in/standard.js +17 -7
- package/dist/report/components/attempt-detail/AttemptAssertions.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptAssertions.js +17 -0
- package/dist/report/components/attempt-detail/AttemptConversation.d.ts +10 -0
- package/dist/report/components/attempt-detail/AttemptConversation.js +74 -0
- package/dist/report/components/attempt-detail/AttemptDiagnostics.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptDiagnostics.js +7 -0
- package/dist/report/components/attempt-detail/AttemptDiff.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptDiff.js +11 -0
- package/dist/report/components/attempt-detail/AttemptError.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptError.js +16 -0
- package/dist/report/components/attempt-detail/AttemptFixPrompt.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptFixPrompt.js +7 -0
- package/dist/report/components/attempt-detail/AttemptSource.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptSource.js +97 -0
- package/dist/report/components/attempt-detail/AttemptSummary.d.ts +8 -0
- package/dist/report/components/attempt-detail/AttemptSummary.js +20 -0
- package/dist/report/components/attempt-detail/AttemptTimeline.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptTimeline.js +28 -0
- package/dist/report/components/attempt-detail/AttemptTrace.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptTrace.js +29 -0
- package/dist/report/components/attempt-detail/AttemptUsage.d.ts +6 -0
- package/dist/report/components/attempt-detail/AttemptUsage.js +20 -0
- package/dist/report/components/attempt-detail/compute.d.ts +24 -0
- package/dist/report/components/attempt-detail/compute.js +297 -0
- package/dist/report/components/attempt-detail/faces.d.ts +14 -0
- package/dist/report/components/attempt-detail/faces.js +239 -0
- package/dist/report/components/attempt-detail/index.d.ts +38 -0
- package/dist/report/components/attempt-detail/index.js +547 -0
- package/dist/report/{react → components}/cell.d.ts +5 -3
- package/dist/report/{react → components}/cell.js +3 -3
- package/dist/report/{react → components/entity-lists}/AttemptList.d.ts +8 -4
- package/dist/report/{react → components/entity-lists}/AttemptList.js +16 -10
- package/dist/report/{react → components/entity-lists}/EvalList.d.ts +3 -3
- package/dist/report/{react → components/entity-lists}/EvalList.js +0 -0
- package/dist/report/{react → components/entity-lists}/ExperimentList.d.ts +4 -5
- package/dist/report/{react → components/entity-lists}/ExperimentList.js +12 -11
- package/dist/report/components/entity-lists/compute.d.ts +23 -0
- package/dist/report/components/entity-lists/compute.js +171 -0
- package/dist/report/components/entity-lists/faces.d.ts +5 -0
- package/dist/report/components/entity-lists/faces.js +175 -0
- package/dist/report/components/entity-lists/index.d.ts +49 -0
- package/dist/report/components/entity-lists/index.js +169 -0
- package/dist/report/{react → components}/fixtures.d.ts +2 -2
- package/dist/report/{react → components}/fixtures.js +1 -1
- package/dist/report/{react → components/metric-views}/DeltaTable.d.ts +2 -2
- package/dist/report/{react → components/metric-views}/DeltaTable.js +4 -4
- package/dist/report/{react → components/metric-views}/MetricBars.d.ts +3 -3
- package/dist/report/{react → components/metric-views}/MetricBars.js +3 -3
- package/dist/report/{react → components/metric-views}/MetricLine.d.ts +2 -2
- package/dist/report/{react → components/metric-views}/MetricLine.js +8 -5
- package/dist/report/{react → components/metric-views}/MetricMatrix.d.ts +3 -3
- package/dist/report/{react → components/metric-views}/MetricMatrix.js +4 -4
- package/dist/report/components/metric-views/MetricScatter.d.ts +11 -0
- package/dist/report/{react → components/metric-views}/MetricScatter.js +27 -60
- package/dist/report/{react → components/metric-views}/MetricTable.d.ts +3 -3
- package/dist/report/{react → components/metric-views}/MetricTable.js +4 -4
- package/dist/report/{react → components/metric-views}/Scoreboard.d.ts +2 -2
- package/dist/report/{react → components/metric-views}/Scoreboard.js +3 -3
- package/dist/report/components/metric-views/compute.d.ts +89 -0
- package/dist/report/{compute.js → components/metric-views/compute.js} +32 -415
- package/dist/report/components/metric-views/faces.d.ts +13 -0
- package/dist/report/components/metric-views/faces.js +381 -0
- package/dist/report/components/metric-views/index.d.ts +50 -0
- package/dist/report/components/metric-views/index.js +273 -0
- package/dist/report/{text → components/metric-views}/plot.js +1 -1
- package/dist/report/components/shared-compute.d.ts +22 -0
- package/dist/report/components/shared-compute.js +47 -0
- package/dist/report/components/shared-faces.d.ts +9 -0
- package/dist/report/components/shared-faces.js +26 -0
- package/dist/report/components/shared.d.ts +68 -0
- package/dist/report/components/shared.js +125 -0
- package/dist/report/{react → components/site-components}/CopyFixPrompt.d.ts +2 -2
- package/dist/report/{react → components/site-components}/CopyFixPrompt.js +2 -2
- package/dist/report/{react → components/site-components}/HeroCard.d.ts +2 -2
- package/dist/report/{react → components/site-components}/HeroCard.js +2 -2
- package/dist/report/{react → components/site-components}/ScopeWarnings.d.ts +2 -2
- package/dist/report/{react → components/site-components}/ScopeWarnings.js +3 -3
- package/dist/report/{react → components/site-components}/TraceWaterfall.d.ts +3 -3
- package/dist/report/{react → components/site-components}/TraceWaterfall.js +5 -5
- package/dist/report/components/site-components/compute.d.ts +28 -0
- package/dist/report/components/site-components/compute.js +132 -0
- package/dist/report/components/site-components/faces.d.ts +21 -0
- package/dist/report/components/site-components/faces.js +75 -0
- package/dist/report/components/site-components/index.d.ts +74 -0
- package/dist/report/components/site-components/index.js +220 -0
- package/dist/report/{scope-warnings.d.ts → components/site-components/scope-warnings.d.ts} +2 -2
- package/dist/report/{scope-warnings.js → components/site-components/scope-warnings.js} +2 -2
- package/dist/report/{react → components/summaries}/ScopeSummary.d.ts +2 -2
- package/dist/report/{react → components/summaries}/ScopeSummary.js +17 -8
- package/dist/report/components/summaries/compute.d.ts +7 -0
- package/dist/report/components/summaries/compute.js +51 -0
- package/dist/report/components/summaries/faces.d.ts +7 -0
- package/dist/report/components/summaries/faces.js +38 -0
- package/dist/report/components/summaries/index.d.ts +27 -0
- package/dist/report/components/summaries/index.js +78 -0
- package/dist/report/definition/grid-layout.d.ts +50 -0
- package/dist/report/definition/grid-layout.js +89 -0
- package/dist/report/{primitives.d.ts → definition/primitives.d.ts} +34 -4
- package/dist/report/{primitives.js → definition/primitives.js} +101 -10
- package/dist/report/{report.d.ts → definition/report.d.ts} +36 -65
- package/dist/report/{report.js → definition/report.js} +58 -90
- package/dist/report/{text/table.d.ts → definition/table-text.d.ts} +2 -2
- package/dist/report/{text/table.js → definition/table-text.js} +2 -2
- package/dist/report/{tree.d.ts → definition/tree.d.ts} +43 -11
- package/dist/report/{tree.js → definition/tree.js} +9 -11
- package/dist/report/index.d.ts +33 -18
- package/dist/report/index.js +23 -14
- package/dist/report/{aggregate.d.ts → model/aggregate.d.ts} +12 -4
- package/dist/report/{aggregate.js → model/aggregate.js} +28 -8
- package/dist/report/{flag.d.ts → model/flag.d.ts} +14 -1
- package/dist/report/{flag.js → model/flag.js} +35 -0
- package/dist/report/{format.d.ts → model/format.d.ts} +13 -7
- package/dist/report/{format.js → model/format.js} +79 -9
- package/dist/report/{locale.d.ts → model/locale.d.ts} +17 -17
- package/dist/report/{locale.js → model/locale.js} +31 -33
- package/dist/report/{metrics.d.ts → model/metrics.d.ts} +2 -2
- package/dist/report/{metrics.js → model/metrics.js} +2 -2
- package/dist/report/{types.d.ts → model/types.d.ts} +154 -20
- package/dist/report/react/index.d.ts +32 -21
- package/dist/report/react/index.js +33 -21
- package/dist/report/{load.d.ts → runtime/load.d.ts} +1 -1
- package/dist/report/{load.js → runtime/load.js} +1 -1
- package/dist/report/runtime/text.d.ts +67 -0
- package/dist/report/runtime/text.js +114 -0
- package/dist/report/runtime/web.d.ts +35 -0
- package/dist/report/runtime/web.js +70 -0
- package/dist/results/annotated-source.d.ts +87 -0
- package/dist/results/attempt-evidence.d.ts +74 -0
- package/dist/results/attempt-source.d.ts +15 -0
- package/dist/results/select.d.ts +11 -1
- package/dist/results/select.js +27 -5
- package/dist/runner/eval-selection.d.ts +26 -0
- package/dist/runner/feedback/sink.d.ts +26 -1
- package/dist/runner/types.d.ts +151 -24
- package/dist/sandbox/docker.d.ts +6 -0
- package/dist/sandbox/e2b.d.ts +0 -1
- package/dist/sandbox/types.d.ts +23 -21
- package/dist/scoring/display.d.ts +7 -2
- package/dist/scoring/display.js +42 -4
- package/dist/scoring/types.d.ts +3 -3
- package/dist/shared/aggregate.d.ts +14 -0
- package/dist/shared/aggregate.js +31 -0
- package/dist/shared/types.d.ts +6 -1
- package/docs-site/images/logo-dark.svg +7 -0
- package/docs-site/images/logo.svg +6 -5
- package/docs-site/zh/README.md +8 -7
- package/docs-site/zh/examples/ai-agent-application.mdx +5 -5
- package/docs-site/zh/examples/coding-agent-extensions.mdx +4 -4
- package/docs-site/zh/examples/index.mdx +3 -3
- package/docs-site/zh/examples/integrations/ai-sdk-v7.mdx +6 -6
- package/docs-site/zh/examples/integrations/claude-sdk.mdx +3 -3
- package/docs-site/zh/examples/integrations/codex-sdk.mdx +3 -3
- package/docs-site/zh/examples/integrations/langgraph.mdx +3 -3
- package/docs-site/zh/examples/integrations/pi-sdk.mdx +2 -2
- package/docs-site/zh/explanation/adapter.mdx +19 -19
- package/docs-site/zh/explanation/assert.mdx +9 -9
- package/docs-site/zh/explanation/drive.mdx +4 -4
- package/docs-site/zh/explanation/evals.mdx +8 -8
- package/docs-site/zh/explanation/experiment.mdx +8 -8
- package/docs-site/zh/explanation/hitl.mdx +13 -13
- package/docs-site/zh/explanation/judge.mdx +3 -3
- package/docs-site/zh/explanation/overview.mdx +7 -7
- package/docs-site/zh/explanation/runner.mdx +17 -13
- package/docs-site/zh/explanation/tier.mdx +6 -6
- package/docs-site/zh/index.mdx +14 -14
- package/docs-site/zh/introduction.mdx +13 -16
- package/docs-site/zh/reference/builtin-agents.mdx +61 -28
- package/docs-site/zh/reference/capabilities.mdx +7 -27
- package/docs-site/zh/reference/cli.mdx +36 -33
- package/docs-site/zh/reference/define-agent.mdx +32 -31
- package/docs-site/zh/reference/define-config.mdx +6 -6
- package/docs-site/zh/reference/define-eval.mdx +33 -20
- package/docs-site/zh/reference/events.mdx +4 -4
- package/docs-site/zh/reference/expect.mdx +3 -3
- package/docs-site/zh/reference/official-adapters.mdx +17 -17
- package/docs-site/zh/reference/report-components.mdx +195 -121
- package/docs-site/zh/reference/results-data.mdx +13 -13
- package/docs-site/zh/troubleshooting/debug-sandbox.mdx +11 -11
- package/docs-site/zh/troubleshooting/debugging.mdx +40 -16
- package/docs-site/zh/{how-to → tutorials}/agent-feedback-loop.mdx +38 -38
- package/docs-site/zh/tutorials/agent-onboarding.mdx +100 -0
- package/docs-site/zh/tutorials/authoring.mdx +211 -0
- package/docs-site/zh/{how-to → tutorials}/ci-integration.mdx +8 -8
- package/docs-site/zh/{how-to → tutorials}/connect-otel.mdx +22 -22
- package/docs-site/zh/{how-to → tutorials}/connect-your-agent.mdx +58 -63
- package/docs-site/zh/tutorials/custom-reports.mdx +453 -0
- package/docs-site/zh/{how-to → tutorials}/dataset-fanout.mdx +4 -4
- package/docs-site/zh/tutorials/experiments.mdx +102 -0
- package/docs-site/zh/{how-to → tutorials}/fixtures.mdx +9 -9
- package/docs-site/zh/{how-to → tutorials}/publish-report.mdx +6 -6
- package/docs-site/zh/tutorials/quickstart.mdx +18 -18
- package/docs-site/zh/{how-to → tutorials}/reporters.mdx +6 -6
- package/docs-site/zh/{how-to → tutorials}/sandbox-agent.mdx +6 -6
- package/docs-site/zh/{how-to → tutorials}/sandbox-providers.mdx +41 -19
- package/docs-site/zh/{how-to → tutorials}/scoring-guide.mdx +4 -4
- package/docs-site/zh/{how-to → tutorials}/viewing-results.mdx +60 -57
- package/docs-site/zh/tutorials/write-experiment.mdx +353 -0
- package/docs-site/zh/{how-to → tutorials}/write-send.mdx +40 -40
- package/package.json +10 -7
- package/src/agents/bub.ts +21 -8
- package/src/agents/claude-code.ts +23 -10
- package/src/agents/codex.test.ts +22 -7
- package/src/agents/codex.ts +22 -9
- package/src/agents/index.ts +2 -2
- package/src/agents/openai-compat.ts +1 -1
- package/src/agents/post-setup.ts +45 -22
- package/src/agents/streaming.ts +1 -1
- package/src/agents/types.ts +20 -17
- package/src/agents/ui-message-stream.test.ts +10 -0
- package/src/agents/ui-message-stream.ts +12 -1
- package/src/cli.ts +75 -59
- package/src/context/types.ts +21 -21
- package/src/define.ts +13 -0
- package/src/i18n/en.ts +27 -12
- package/src/i18n/zh-CN.ts +27 -12
- package/src/index.ts +2 -0
- package/src/o11y/prices.json +176 -99
- package/src/report/{react → assets}/colors.ts +22 -0
- package/src/report/{react → assets}/enhance.js +1 -33
- package/src/report/assets/styles.css +1785 -0
- package/src/report/built-in/index.tsx +2 -2
- package/src/report/built-in/standard.tsx +18 -6
- package/src/report/components/attempt-detail/AttemptAssertions.tsx +67 -0
- package/src/report/components/attempt-detail/AttemptConversation.tsx +158 -0
- package/src/report/components/attempt-detail/AttemptDiagnostics.tsx +38 -0
- package/src/report/components/attempt-detail/AttemptDiff.tsx +35 -0
- package/src/report/components/attempt-detail/AttemptError.tsx +31 -0
- package/src/report/components/attempt-detail/AttemptFixPrompt.tsx +26 -0
- package/src/report/components/attempt-detail/AttemptSource.tsx +224 -0
- package/src/report/components/attempt-detail/AttemptSummary.tsx +74 -0
- package/src/report/components/attempt-detail/AttemptTimeline.tsx +108 -0
- package/src/report/components/attempt-detail/AttemptTrace.tsx +63 -0
- package/src/report/components/attempt-detail/AttemptUsage.tsx +29 -0
- package/src/report/components/attempt-detail/attempt-components.test.tsx +758 -0
- package/src/report/components/attempt-detail/compute.ts +336 -0
- package/src/report/components/attempt-detail/faces.ts +260 -0
- package/src/report/components/attempt-detail/index.tsx +600 -0
- package/src/report/components/attempt-detail/validate.test.ts +252 -0
- package/src/report/{react → components}/cell.tsx +6 -3
- package/src/report/{report.test.ts → components/compute.test.ts} +316 -46
- package/src/report/{react → components/entity-lists}/AttemptList.tsx +24 -16
- package/src/report/{react → components/entity-lists}/EvalList.tsx +0 -0
- package/src/report/{react → components/entity-lists}/ExperimentList.tsx +33 -27
- package/src/report/components/entity-lists/compute.ts +196 -0
- package/src/report/components/entity-lists/faces.ts +208 -0
- package/src/report/components/entity-lists/index.tsx +238 -0
- package/src/report/components/entity-lists/validate.test.ts +114 -0
- package/src/report/{react → components}/fixtures.ts +2 -2
- package/src/report/{react → components/metric-views}/DeltaTable.tsx +5 -5
- package/src/report/{react → components/metric-views}/MetricBars.tsx +5 -5
- package/src/report/{react → components/metric-views}/MetricLine.tsx +9 -6
- package/src/report/{react → components/metric-views}/MetricMatrix.tsx +6 -6
- package/src/report/{react → components/metric-views}/MetricScatter.tsx +42 -70
- package/src/report/{react → components/metric-views}/MetricTable.tsx +6 -6
- package/src/report/{react → components/metric-views}/Scoreboard.tsx +4 -4
- package/src/report/{compute.ts → components/metric-views/compute.ts} +51 -477
- package/src/report/components/metric-views/faces.ts +423 -0
- package/src/report/components/metric-views/index.tsx +352 -0
- package/src/report/{text → components/metric-views}/plot.ts +1 -1
- package/src/report/components/metric-views/validate.test.ts +211 -0
- package/src/report/{react → components}/render.test.tsx +66 -26
- package/src/report/components/shared-compute.ts +59 -0
- package/src/report/components/shared-faces.ts +30 -0
- package/src/report/components/shared.ts +192 -0
- package/src/report/{react → components/site-components}/CopyFixPrompt.tsx +3 -3
- package/src/report/{react → components/site-components}/HeroCard.tsx +3 -3
- package/src/report/{react → components/site-components}/ScopeWarnings.tsx +4 -4
- package/src/report/{react → components/site-components}/TraceWaterfall.tsx +13 -10
- package/src/report/components/site-components/compute.ts +144 -0
- package/src/report/components/site-components/faces.ts +80 -0
- package/src/report/components/site-components/index.tsx +265 -0
- package/src/report/{scope-warnings.ts → components/site-components/scope-warnings.ts} +3 -3
- package/src/report/{site-components.test.tsx → components/site-components/site-components.test.tsx} +23 -21
- package/src/report/components/site-components/validate.test.ts +89 -0
- package/src/report/{react → components/summaries}/ScopeSummary.tsx +26 -11
- package/src/report/components/summaries/compute.ts +56 -0
- package/src/report/components/summaries/faces.ts +48 -0
- package/src/report/components/summaries/index.tsx +127 -0
- package/src/report/components/summaries/validate.test.ts +49 -0
- package/src/report/definition/grid-layout.test.ts +124 -0
- package/src/report/definition/grid-layout.ts +146 -0
- package/src/report/{primitives.tsx → definition/primitives.tsx} +168 -18
- package/src/report/{report.ts → definition/report.ts} +98 -165
- package/src/report/{shell-head.test.ts → definition/shell-head.test.ts} +2 -2
- package/src/report/{text/table.ts → definition/table-text.ts} +4 -4
- package/src/report/{tree.ts → definition/tree.ts} +56 -20
- package/src/report/index.ts +128 -66
- package/src/report/{aggregate.ts → model/aggregate.ts} +31 -9
- package/src/report/{flag.ts → model/flag.ts} +39 -1
- package/src/report/{format.ts → model/format.ts} +89 -10
- package/src/report/{locale.ts → model/locale.ts} +34 -36
- package/src/report/{metrics.ts → model/metrics.ts} +3 -3
- package/src/report/{types.ts → model/types.ts} +159 -22
- package/src/report/react/index.tsx +54 -26
- package/src/report/{dual-render.test.tsx → runtime/dual-render.test.tsx} +601 -53
- package/src/report/runtime/host.test.ts +44 -0
- package/src/report/runtime/host.ts +138 -0
- package/src/report/{load.ts → runtime/load.ts} +1 -1
- package/src/report/runtime/text.ts +192 -0
- package/src/report/runtime/web.ts +106 -0
- package/src/results/attempt-evidence.ts +5 -1
- package/src/results/host-equivalence.test.ts +53 -2
- package/src/results/select.ts +29 -5
- package/src/runner/attempt.test.ts +48 -1
- package/src/runner/attempt.ts +62 -42
- package/src/runner/cleanup-timeout.test.ts +16 -0
- package/src/runner/cleanup-timeout.ts +23 -0
- package/src/runner/discover.ts +1 -2
- package/src/runner/eval-selection.test.ts +187 -0
- package/src/runner/eval-selection.ts +109 -0
- package/src/runner/experiment-cleanup-registry.test.ts +89 -0
- package/src/runner/experiment-cleanup-registry.ts +39 -0
- package/src/runner/experiment-labels.test.ts +71 -0
- package/src/runner/feedback/agent.test.ts +33 -1
- package/src/runner/feedback/agent.ts +12 -16
- package/src/runner/feedback/ci.test.ts +35 -1
- package/src/runner/feedback/ci.ts +16 -18
- package/src/runner/feedback/coordinator.ts +28 -0
- package/src/runner/feedback/human.test.ts +108 -1
- package/src/runner/feedback/human.ts +71 -21
- package/src/runner/feedback/reducer.test.ts +64 -0
- package/src/runner/feedback/reducer.ts +26 -0
- package/src/runner/feedback/sink.ts +40 -1
- package/src/runner/fingerprint.ts +2 -1
- package/src/runner/report.test.ts +14 -0
- package/src/runner/report.ts +3 -1
- package/src/runner/run.test.ts +390 -12
- package/src/runner/run.ts +259 -26
- package/src/runner/sandbox-selection.test.ts +13 -3
- package/src/runner/sandbox-selection.ts +4 -2
- package/src/runner/types.ts +160 -24
- package/src/sandbox/docker.ts +7 -0
- package/src/sandbox/e2b-reconcile.test.ts +125 -0
- package/src/sandbox/e2b.ts +47 -12
- package/src/sandbox/types.ts +23 -21
- package/src/scoring/display.test.ts +28 -2
- package/src/scoring/display.ts +38 -5
- package/src/scoring/types.ts +3 -3
- package/src/shared/aggregate.test.ts +52 -0
- package/src/shared/aggregate.ts +29 -0
- package/src/shared/types.ts +6 -1
- package/src/show/command.test.ts +34 -0
- package/src/show/command.ts +16 -0
- package/src/show/compose.ts +1 -1
- package/src/show/index.ts +56 -20
- package/src/show/render.ts +15 -239
- package/src/show/show.test.ts +127 -34
- package/src/view/app/App.test.tsx +1 -1
- package/src/view/app/App.tsx +119 -47
- package/src/view/app/i18n.ts +7 -147
- package/src/view/app/lib/attempt-dialog.test.ts +65 -0
- package/src/view/app/lib/attempt-dialog.ts +69 -0
- package/src/view/app/main.tsx +0 -1
- package/src/view/app/types.ts +3 -86
- package/src/view/artifact-serving.test.ts +22 -38
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +15 -22
- package/src/view/data.test.ts +48 -36
- package/src/view/data.ts +105 -83
- package/src/view/index.ts +1 -1
- package/src/view/server.ts +32 -2
- package/src/view/shared/types.ts +6 -31
- package/src/view/site-parity.test.ts +24 -1
- package/src/view/site.ts +144 -17
- package/src/view/styles.css +0 -805
- package/src/view/view-report.test.ts +143 -22
- package/dist/report/components.d.ts +0 -179
- package/dist/report/components.js +0 -544
- package/dist/report/compute.d.ts +0 -139
- package/dist/report/react/ExperimentComparison.d.ts +0 -10
- package/dist/report/react/ExperimentComparison.js +0 -12
- package/dist/report/react/MetricScatter.d.ts +0 -9
- package/dist/report/react/format.d.ts +0 -3
- package/dist/report/react/format.js +0 -7
- package/dist/report/text/faces.d.ts +0 -45
- package/dist/report/text/faces.js +0 -671
- package/dist/report/web.d.ts +0 -32
- package/dist/report/web.js +0 -48
- package/docs-site/zh/how-to/authoring.mdx +0 -162
- package/docs-site/zh/how-to/custom-reports.mdx +0 -414
- package/docs-site/zh/how-to/experiments.mdx +0 -86
- package/docs-site/zh/how-to/write-experiment.mdx +0 -164
- package/src/report/components.tsx +0 -925
- package/src/report/react/ExperimentComparison.tsx +0 -73
- package/src/report/react/format.ts +0 -9
- package/src/report/react/styles.css +0 -945
- package/src/report/text/faces.ts +0 -767
- package/src/report/web.ts +0 -77
- package/src/show/report-host.test.ts +0 -205
- package/src/show/report-host.ts +0 -389
- package/src/view/app/components/AttemptModal.tsx +0 -496
- package/src/view/app/components/CodeView.test.tsx +0 -142
- package/src/view/app/components/CodeView.tsx +0 -310
- package/src/view/app/components/CopyControls.tsx +0 -106
- package/src/view/app/components/Trace.tsx +0 -100
- package/src/view/app/components/Transcript.tsx +0 -157
- package/src/view/app/components/ui/badge.tsx +0 -21
- package/src/view/app/lib/artifact-url.ts +0 -17
- package/src/view/app/lib/attempt-route.test.ts +0 -80
- package/src/view/app/lib/attempt-route.ts +0 -52
- package/src/view/app/lib/format.ts +0 -70
- package/src/view/app/lib/guards.test.ts +0 -108
- package/src/view/app/lib/guards.ts +0 -71
- package/src/view/app/lib/rows.ts +0 -22
- package/src/view/app/lib/transcript-data.tsx +0 -151
- package/src/view/app/lib/verdict.ts +0 -23
- package/src/view/app/shared.ts +0 -8
- /package/dist/report/{react → components/metric-views}/chart-math.d.ts +0 -0
- /package/dist/report/{react → components/metric-views}/chart-math.js +0 -0
- /package/dist/report/{text → components/metric-views}/plot.d.ts +0 -0
- /package/dist/report/{react → components/site-components}/PoweredBy.d.ts +0 -0
- /package/dist/report/{react → components/site-components}/PoweredBy.js +0 -0
- /package/dist/report/{text/layout.d.ts → model/text-layout.d.ts} +0 -0
- /package/dist/report/{text/layout.js → model/text-layout.js} +0 -0
- /package/dist/report/{types.js → model/types.js} +0 -0
- /package/src/report/{react → components/metric-views}/chart-math.test.ts +0 -0
- /package/src/report/{react → components/metric-views}/chart-math.ts +0 -0
- /package/src/report/{react → components/site-components}/PoweredBy.tsx +0 -0
- /package/src/report/{text/layout.ts → model/text-layout.ts} +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// Grid 的语义层与面内布局(docs/feature/reports/architecture.md「排版原语的语义层与面内布局」、
|
|
2
|
+
// docs/feature/reports/library/layout.md「Grid 与 Stat」)。只放同步纯函数与中间类型:
|
|
3
|
+
// normalizeGrid 把 resolved ReportNode children 校验并展平成有序 cell 列表;planTextGrid
|
|
4
|
+
// 只依赖 availableWidth / cell 数 / 规范化 Grid props,规划 text 面的列数与每列宽度。
|
|
5
|
+
// 不 import show / view、Results IO 或 stylesheet;primitives.tsx 消费本文件产出两面适配。
|
|
6
|
+
|
|
7
|
+
import type { ReportNode } from "./tree.ts";
|
|
8
|
+
|
|
9
|
+
export type GridVariant = "plain" | "boxed";
|
|
10
|
+
export type GridDensity = "regular" | "compact";
|
|
11
|
+
|
|
12
|
+
// react/jsx-runtime 的 Fragment 注册符号,跨 react 版本稳定(tree.ts 同一常量的独立取用,
|
|
13
|
+
// Symbol.for 全局注册表保证同一符号,不产生耦合)。
|
|
14
|
+
const REACT_FRAGMENT = Symbol.for("react.fragment");
|
|
15
|
+
|
|
16
|
+
function isElementNode(node: unknown): node is { type: unknown; props: Record<string, unknown>; key?: unknown } {
|
|
17
|
+
return typeof node === "object" && node !== null && !Array.isArray(node) && "type" in node && "props" in node;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function keyOf(node: unknown, fallback: string): string {
|
|
21
|
+
if (isElementNode(node)) {
|
|
22
|
+
const key = node.key;
|
|
23
|
+
if (typeof key === "string" || typeof key === "number") return String(key);
|
|
24
|
+
}
|
|
25
|
+
return fallback;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** 校验 `columns`:必须是有限正整数——TypeScript 的 `number` 排除不了 0/负数/小数/NaN/Infinity。 */
|
|
29
|
+
export function validateGridColumns(columns: number): number {
|
|
30
|
+
if (!(Number.isFinite(columns) && Number.isInteger(columns) && columns > 0)) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Grid columns must be a finite positive integer, received ${JSON.stringify(columns)}. ` +
|
|
33
|
+
"Pass columns={N} with a whole number greater than 0 (e.g. columns={3}).",
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return columns;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface NormalizedGridCell {
|
|
40
|
+
readonly node: ReportNode;
|
|
41
|
+
/** React key:复用元素自带 key,缺失时按展平后的声明序生成稳定回退。 */
|
|
42
|
+
readonly key: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* `normalizeGrid` 的产物:有序、不可拆的 cell 列表 + columns / variant / density。
|
|
47
|
+
* 不是公开 data shape,也不进结果或 artifact——只是两个渲染面共享的同步排版中间值。
|
|
48
|
+
*/
|
|
49
|
+
export interface NormalizedGrid {
|
|
50
|
+
readonly cells: readonly NormalizedGridCell[];
|
|
51
|
+
readonly columns: number;
|
|
52
|
+
readonly variant: GridVariant;
|
|
53
|
+
readonly density: GridDensity;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 递归展开数组与 Fragment、跳过空分支(null/undefined/boolean),其余节点各占一格
|
|
58
|
+
* ——`Col` 归拢的多个子节点、任意自定义组件的渲染结果都是不透明的一格,不下钻其内部结构。
|
|
59
|
+
*/
|
|
60
|
+
function flattenGridChildren(children: ReportNode): NormalizedGridCell[] {
|
|
61
|
+
const cells: NormalizedGridCell[] = [];
|
|
62
|
+
const visit = (node: ReportNode): void => {
|
|
63
|
+
if (node === null || node === undefined || typeof node === "boolean") return;
|
|
64
|
+
if (Array.isArray(node)) {
|
|
65
|
+
for (const child of node) visit(child);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (isElementNode(node) && node.type === REACT_FRAGMENT) {
|
|
69
|
+
visit(node.props.children as ReportNode);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
cells.push({ node, key: keyOf(node, `nre-grid-cell-${cells.length}`) });
|
|
73
|
+
};
|
|
74
|
+
visit(children);
|
|
75
|
+
return cells;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** `Grid` 组件创建时的一次性规范化:校验 props、展平 children 成有序 cell 列表。 */
|
|
79
|
+
export function normalizeGrid(input: {
|
|
80
|
+
children: ReportNode;
|
|
81
|
+
columns: number;
|
|
82
|
+
variant?: GridVariant;
|
|
83
|
+
density?: GridDensity;
|
|
84
|
+
}): NormalizedGrid {
|
|
85
|
+
return {
|
|
86
|
+
cells: flattenGridChildren(input.children),
|
|
87
|
+
columns: validateGridColumns(input.columns),
|
|
88
|
+
variant: input.variant ?? "plain",
|
|
89
|
+
density: input.density ?? "regular",
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** text 面规划的输入:只有可用宽度、cell 数与规范化 Grid props 里跟宽度有关的两项。 */
|
|
94
|
+
export interface TextGridPlanInput {
|
|
95
|
+
readonly availableWidth: number;
|
|
96
|
+
readonly cellCount: number;
|
|
97
|
+
readonly columns: number;
|
|
98
|
+
readonly density: GridDensity;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* text 面的一次性排版计划:实际列数、每列内容显示宽度、格间 gutter。
|
|
103
|
+
* `boxed` 与 `plain` 复用同一份计划(规划总是先扣 boxed 的四边框与内 padding),
|
|
104
|
+
* `plain` 渲染时只是不打印这部分字符——两个 variant 因此列数一致,不会各挑各的列数。
|
|
105
|
+
*/
|
|
106
|
+
export interface TextGridPlan {
|
|
107
|
+
readonly columns: number;
|
|
108
|
+
readonly contentWidths: readonly number[];
|
|
109
|
+
readonly gutter: number;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** text 面每 cell 的最小可读内容宽度;density 不以挤坏字段换取更多列。 */
|
|
113
|
+
const MIN_CONTENT_WIDTH = 24;
|
|
114
|
+
/** boxed 单 cell 的固定开销:左右各一根边框 + 左右各一格 padding。 */
|
|
115
|
+
const BOXED_OVERHEAD_PER_CELL = 4;
|
|
116
|
+
|
|
117
|
+
function gridGutter(density: GridDensity): number {
|
|
118
|
+
return density === "compact" ? 1 : 2;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 从 `min(columns, cellCount)` 向一列尝试,选出满足每格最小可读内容宽度的最大列数;
|
|
123
|
+
* 一列是无条件 fallback(即使内容宽度因此小于 24)。选定列数后,余下的显示列从左向右
|
|
124
|
+
* 逐列多补一列,因此任意一行的显示宽度都不会超过 `availableWidth`(见调用方组装)。
|
|
125
|
+
*/
|
|
126
|
+
export function planTextGrid(input: TextGridPlanInput): TextGridPlan {
|
|
127
|
+
const { availableWidth, cellCount, columns, density } = input;
|
|
128
|
+
const gutter = gridGutter(density);
|
|
129
|
+
const maxColumns = Math.max(1, Math.min(columns, Math.max(cellCount, 1)));
|
|
130
|
+
|
|
131
|
+
let chosen = 1;
|
|
132
|
+
for (let n = maxColumns; n >= 2; n--) {
|
|
133
|
+
const budget = availableWidth - BOXED_OVERHEAD_PER_CELL * n - gutter * (n - 1);
|
|
134
|
+
if (budget >= 0 && Math.floor(budget / n) >= MIN_CONTENT_WIDTH) {
|
|
135
|
+
chosen = n;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const budget = Math.max(0, availableWidth - BOXED_OVERHEAD_PER_CELL * chosen - gutter * (chosen - 1));
|
|
141
|
+
const base = Math.floor(budget / chosen);
|
|
142
|
+
const remainder = budget - base * chosen;
|
|
143
|
+
const contentWidths = Array.from({ length: chosen }, (_, i) => Math.max(1, base + (i < remainder ? 1 : 0)));
|
|
144
|
+
|
|
145
|
+
return { columns: chosen, contentWidths, gutter };
|
|
146
|
+
}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
// 排版原语 Row / Col / Section / Text / Style / Tabs / Tab / Table
|
|
2
|
-
//
|
|
1
|
+
// 排版原语 Row / Col / Grid / Section / Stat / Text / Style / Tabs / Tab / Table:十个内置
|
|
2
|
+
// 双面组件,没有特殊机制(docs/feature/reports/library/layout.md)。web 面是普通 React 渲染;
|
|
3
3
|
// text 面用 ctx.render(child, 子宽) 显式传宽。Style 注入页级全局 CSS(树位置只决定声明
|
|
4
4
|
// 顺序),text 面渲染为空。Table 是自定义表的标准件,官方表状组件的 text 面也建在它上面。
|
|
5
|
+
// Grid / Stat 的语义层(normalizeGrid 展平校验、text 面的 TextGridPlan 排版)在
|
|
6
|
+
// ./grid-layout.ts(docs/feature/reports/architecture.md「排版原语的语义层与面内布局」);
|
|
7
|
+
// 本文件只声明两面适配,不重复那份算术。
|
|
5
8
|
|
|
6
|
-
import type { ReactNode } from "react";
|
|
7
|
-
import type { AttemptLocator } from "
|
|
9
|
+
import type { CSSProperties, ReactNode } from "react";
|
|
10
|
+
import type { AttemptLocator } from "../../results/locator.ts";
|
|
8
11
|
import { COMPONENT_RAW_CHILDREN, COMPONENT_ROLE, defineComponent, type ReportNode } from "./tree.ts";
|
|
9
|
-
import { localeText, resolveLocalizedText, type LocalizedText, type ReportLocale } from "
|
|
10
|
-
import { indentBlock, joinColumns, stringWidth, wrapDisplay } from "
|
|
11
|
-
import type { ColumnAlign } from "
|
|
12
|
-
import { renderTableText } from "./text
|
|
12
|
+
import { localeText, resolveLocalizedText, type LocalizedText, type ReportLocale } from "../model/locale.ts";
|
|
13
|
+
import { indentBlock, joinColumns, padDisplay, stringWidth, wrapDisplay } from "../model/text-layout.ts";
|
|
14
|
+
import type { ColumnAlign } from "../model/text-layout.ts";
|
|
15
|
+
import { renderTableText } from "./table-text.ts";
|
|
16
|
+
import { normalizeGrid, planTextGrid, type GridDensity, type GridVariant } from "./grid-layout.ts";
|
|
13
17
|
|
|
14
18
|
function childArray(children: ReportNode): ReportNode[] {
|
|
15
19
|
if (children === null || children === undefined || typeof children === "boolean") return [];
|
|
@@ -20,6 +24,9 @@ function cx(...parts: (string | undefined)[]): string {
|
|
|
20
24
|
return parts.filter(Boolean).join(" ");
|
|
21
25
|
}
|
|
22
26
|
|
|
27
|
+
/** `null`/缺数据的统一显示符:Table 与 Stat 共用,不补成 0。 */
|
|
28
|
+
const MISSING_MARK = "—";
|
|
29
|
+
|
|
23
30
|
export interface LayoutProps {
|
|
24
31
|
children?: ReportNode;
|
|
25
32
|
className?: string;
|
|
@@ -76,27 +83,168 @@ export const Row = defineComponent<RowProps>({
|
|
|
76
83
|
});
|
|
77
84
|
Row.displayName = "Row";
|
|
78
85
|
|
|
86
|
+
// ───────────────────────── Grid / Stat ─────────────────────────
|
|
87
|
+
|
|
88
|
+
export interface GridProps extends LayoutProps {
|
|
89
|
+
/** 宽面最多摆几列;必须是有限正整数,运行时校验(docs/feature/reports/library/layout.md「Grid 与 Stat」)。 */
|
|
90
|
+
columns: number;
|
|
91
|
+
/** plain 无框;boxed 给每个 cell 完整四边框。默认 plain。 */
|
|
92
|
+
variant?: GridVariant;
|
|
93
|
+
/** 改变格内留白,并调整内置 Stat 的主值字号;不改变内容和分组。默认 regular。 */
|
|
94
|
+
density?: GridDensity;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** boxed 单个 cell 的完整边框:同一份 TextGridPlan 决定内容宽度,四边不因换行残缺。 */
|
|
98
|
+
function boxCellBlock(content: string, contentWidth: number): string {
|
|
99
|
+
const lines = content.length > 0 ? content.split("\n") : [""];
|
|
100
|
+
const top = `┌${"─".repeat(contentWidth + 2)}┐`;
|
|
101
|
+
const bottom = `└${"─".repeat(contentWidth + 2)}┘`;
|
|
102
|
+
const body = lines.map((line) => `│ ${padDisplay(line, contentWidth)} │`);
|
|
103
|
+
return [top, ...body, bottom].join("\n");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** 一个物理行内的 cell 并排:顶对齐、短 block 补空行到同高(joinColumns 已有语义)。 */
|
|
107
|
+
function renderGridRow(blocks: string[], contentWidths: number[], gutter: number, variant: GridVariant): string {
|
|
108
|
+
const separator = " ".repeat(gutter);
|
|
109
|
+
if (variant === "boxed") {
|
|
110
|
+
const boxed = blocks.map((block, i) => boxCellBlock(block, contentWidths[i]));
|
|
111
|
+
const boxWidths = contentWidths.map((w) => w + 4);
|
|
112
|
+
return joinColumns(boxed, boxWidths, separator);
|
|
113
|
+
}
|
|
114
|
+
return joinColumns(blocks, contentWidths, separator);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 自由摘要面板的格子容器:只负责呈现,不读取 Scope、不聚合 Metric。每个直接子节点
|
|
119
|
+
* (数组 / Fragment 先按 ReportNode 规则展平,空分支不占格)是一格;`Col` 把多个区块
|
|
120
|
+
* 归成一格。展平与 text 面排版的算术在 ./grid-layout.ts,这里只做两面结构适配。
|
|
121
|
+
*/
|
|
122
|
+
export const Grid = defineComponent<GridProps>({
|
|
123
|
+
web({ children, columns, variant, density, className }) {
|
|
124
|
+
const normalized = normalizeGrid({ children, columns, variant, density });
|
|
125
|
+
const style: CSSProperties = { "--nre-grid-max-columns": normalized.columns } as CSSProperties;
|
|
126
|
+
return (
|
|
127
|
+
<div
|
|
128
|
+
className={cx("nre", "nre-grid", `nre-grid--${normalized.variant}`, `nre-grid--${normalized.density}`, className)}
|
|
129
|
+
style={style}
|
|
130
|
+
>
|
|
131
|
+
{normalized.cells.map((cell) => (
|
|
132
|
+
<div className="nre-grid-cell" key={cell.key}>
|
|
133
|
+
{cell.node as ReactNode}
|
|
134
|
+
</div>
|
|
135
|
+
))}
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
text({ children, columns, variant, density }, ctx) {
|
|
140
|
+
const normalized = normalizeGrid({ children, columns, variant, density });
|
|
141
|
+
if (normalized.cells.length === 0) return "";
|
|
142
|
+
const plan = planTextGrid({
|
|
143
|
+
availableWidth: ctx.width,
|
|
144
|
+
cellCount: normalized.cells.length,
|
|
145
|
+
columns: normalized.columns,
|
|
146
|
+
density: normalized.density,
|
|
147
|
+
});
|
|
148
|
+
// 确定计划后才对每个 cell 调用一次 ctx.render——不为试探列数重复渲染。
|
|
149
|
+
const blocks = normalized.cells.map((cell, i) => ctx.render(cell.node, plan.contentWidths[i % plan.columns]));
|
|
150
|
+
const rows: string[] = [];
|
|
151
|
+
for (let start = 0; start < blocks.length; start += plan.columns) {
|
|
152
|
+
const rowBlocks = blocks.slice(start, start + plan.columns);
|
|
153
|
+
const rowWidths = plan.contentWidths.slice(0, rowBlocks.length);
|
|
154
|
+
rows.push(renderGridRow(rowBlocks, rowWidths, plan.gutter, normalized.variant));
|
|
155
|
+
}
|
|
156
|
+
return rows.join("\n\n");
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
Grid.displayName = "Grid";
|
|
160
|
+
|
|
161
|
+
export type StatTone = "neutral" | "positive" | "negative" | "warning";
|
|
162
|
+
|
|
163
|
+
export interface StatProps {
|
|
164
|
+
label: LocalizedText;
|
|
165
|
+
/** 已格式化的主值;null 明确渲染为 —,不补成 0。 */
|
|
166
|
+
value: LocalizedText | number | null;
|
|
167
|
+
/** 主值下面的短解释;省略时不留空行。 */
|
|
168
|
+
detail?: LocalizedText;
|
|
169
|
+
/** 主值的语义色;不从正负号、单位或 Metric.better 猜。默认 neutral。 */
|
|
170
|
+
tone?: StatTone;
|
|
171
|
+
className?: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Grid / Stat 共享的显示值规范化:LocalizedText 走 resolveLocalizedText,number 走当前
|
|
176
|
+
* locale 的 Intl.NumberFormat,null 变 —;两个面调同一份,不各写一套。
|
|
177
|
+
*/
|
|
178
|
+
function resolveStatDisplay(value: LocalizedText | number | null, locale: ReportLocale): string {
|
|
179
|
+
if (value === null) return MISSING_MARK;
|
|
180
|
+
if (typeof value === "number") return new Intl.NumberFormat(locale).format(value);
|
|
181
|
+
return resolveLocalizedText(value, locale);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** label / 主值 / 辅助信息的最小内容单元;可以脱离 Grid 单独使用。 */
|
|
185
|
+
export const Stat = defineComponent<StatProps>({
|
|
186
|
+
web({ label, value, detail, tone = "neutral", className }, ctx) {
|
|
187
|
+
return (
|
|
188
|
+
<div className={cx("nre", "nre-stat", `nre-stat--${tone}`, className)}>
|
|
189
|
+
<div className="nre-stat-label">{resolveLocalizedText(label, ctx.locale)}</div>
|
|
190
|
+
<div className="nre-stat-value">{resolveStatDisplay(value, ctx.locale)}</div>
|
|
191
|
+
{detail !== undefined ? <div className="nre-stat-detail">{resolveLocalizedText(detail, ctx.locale)}</div> : null}
|
|
192
|
+
</div>
|
|
193
|
+
);
|
|
194
|
+
},
|
|
195
|
+
text({ label, value, detail }, ctx) {
|
|
196
|
+
const lines = [resolveLocalizedText(label, ctx.locale), resolveStatDisplay(value, ctx.locale)];
|
|
197
|
+
if (detail !== undefined) lines.push(resolveLocalizedText(detail, ctx.locale));
|
|
198
|
+
return lines.flatMap((line) => wrapDisplay(line, ctx.width)).join("\n");
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
Stat.displayName = "Stat";
|
|
202
|
+
|
|
203
|
+
// ───────────────────────── Section ─────────────────────────
|
|
204
|
+
|
|
79
205
|
export interface SectionProps extends LayoutProps {
|
|
80
206
|
title: LocalizedText;
|
|
207
|
+
/** 标题行右侧的短元信息;text 面与标题同一行,空间不足时换到下一行。 */
|
|
208
|
+
meta?: LocalizedText;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** 标题行右侧同一行放不下 meta 时,退化成标题后两格缩进折行。 */
|
|
212
|
+
function sectionHeadingLine(heading: string, metaText: string | undefined, width: number): string {
|
|
213
|
+
if (metaText === undefined) return heading;
|
|
214
|
+
const gap = width - stringWidth(heading) - stringWidth(metaText);
|
|
215
|
+
if (gap >= 1) return heading + " ".repeat(gap) + metaText;
|
|
216
|
+
const wrapped = wrapDisplay(metaText, Math.max(1, width - 2)).join("\n");
|
|
217
|
+
return `${heading}\n${indentBlock(wrapped, " ")}`;
|
|
81
218
|
}
|
|
82
219
|
|
|
83
|
-
/**
|
|
220
|
+
/** 带标题的块:网页是标题层级(可选 meta 同行右对齐),终端是标题行加缩进。 */
|
|
84
221
|
export const Section = defineComponent<SectionProps>({
|
|
85
|
-
web({ title, children, className }, ctx) {
|
|
222
|
+
web({ title, meta, children, className }, ctx) {
|
|
223
|
+
const titleText = resolveLocalizedText(title, ctx.locale);
|
|
224
|
+
const metaText = meta !== undefined ? resolveLocalizedText(meta, ctx.locale) : undefined;
|
|
86
225
|
return (
|
|
87
226
|
<section className={cx("nre", "nre-section", className)}>
|
|
88
|
-
|
|
227
|
+
{metaText !== undefined ? (
|
|
228
|
+
<header className="nre-section-header">
|
|
229
|
+
<h2 className="nre-section-title">{titleText}</h2>
|
|
230
|
+
<p className="nre-section-meta">{metaText}</p>
|
|
231
|
+
</header>
|
|
232
|
+
) : (
|
|
233
|
+
<h2 className="nre-section-title">{titleText}</h2>
|
|
234
|
+
)}
|
|
89
235
|
{children as ReactNode}
|
|
90
236
|
</section>
|
|
91
237
|
);
|
|
92
238
|
},
|
|
93
|
-
text({ title, children }, ctx) {
|
|
239
|
+
text({ title, meta, children }, ctx) {
|
|
94
240
|
const heading = resolveLocalizedText(title, ctx.locale);
|
|
241
|
+
const metaText = meta !== undefined ? resolveLocalizedText(meta, ctx.locale) : undefined;
|
|
242
|
+
const headingLine = sectionHeadingLine(heading, metaText, ctx.width);
|
|
95
243
|
const body = childArray(children)
|
|
96
244
|
.map((child) => ctx.render(child, ctx.width - 2))
|
|
97
245
|
.filter((block) => block.length > 0)
|
|
98
246
|
.join("\n\n");
|
|
99
|
-
return body.length > 0 ? `${
|
|
247
|
+
return body.length > 0 ? `${headingLine}\n${indentBlock(body, " ")}` : headingLine;
|
|
100
248
|
},
|
|
101
249
|
});
|
|
102
250
|
Section.displayName = "Section";
|
|
@@ -269,8 +417,6 @@ export interface TableProps {
|
|
|
269
417
|
className?: string;
|
|
270
418
|
}
|
|
271
419
|
|
|
272
|
-
const MISSING_MARK = "—";
|
|
273
|
-
|
|
274
420
|
/** 列 key 唯一、行 cells 不携带未声明 key、空列拒绝——无类型 JS 输入在渲染前同样校验。 */
|
|
275
421
|
function validateTableProps(props: TableProps): void {
|
|
276
422
|
if (!Array.isArray(props.columns) || props.columns.length === 0) {
|
|
@@ -344,9 +490,13 @@ export const Table = defineComponent<TableProps>({
|
|
|
344
490
|
{hasLocator ? (
|
|
345
491
|
<td>
|
|
346
492
|
{row.locator ? (
|
|
347
|
-
|
|
348
|
-
{row.locator}
|
|
349
|
-
|
|
493
|
+
ctx.attemptHref ? (
|
|
494
|
+
<a className="nre-locator" href={ctx.attemptHref(row.locator)}>
|
|
495
|
+
{row.locator}
|
|
496
|
+
</a>
|
|
497
|
+
) : (
|
|
498
|
+
<span className="nre-locator">{row.locator}</span>
|
|
499
|
+
)
|
|
350
500
|
) : (
|
|
351
501
|
<span className="nre-missing">{MISSING_MARK}</span>
|
|
352
502
|
)}
|