fix: add axes to sentinel memory chart
This commit is contained in:
@@ -977,13 +977,12 @@ select {
|
||||
.memory-chart {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 154px;
|
||||
height: 192px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.memory-axis,
|
||||
.memory-legend {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
@@ -993,6 +992,44 @@ select {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.memory-grid-line {
|
||||
stroke: #e5ecea;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.memory-axis-line {
|
||||
stroke: #71817c;
|
||||
stroke-width: 1.2;
|
||||
}
|
||||
|
||||
.memory-tick-line {
|
||||
stroke: #71817c;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.memory-axis-label {
|
||||
fill: var(--muted);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.memory-axis-label-y {
|
||||
text-anchor: end;
|
||||
}
|
||||
|
||||
.memory-axis-label-x {
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
.memory-axis-title {
|
||||
fill: #4f625d;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.memory-axis-title-x {
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
.detail-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
|
||||
@@ -4,6 +4,15 @@ import { createApp, computed, onMounted, ref, watch } from "./vendor/vue.esm-bro
|
||||
|
||||
const bootstrap = readBootstrap();
|
||||
const internalTextPattern = /水合|投影|Trace|trace|Shell|API|DOM|Console|console|Runner|runner|JSONL|steer|facts|分页|HTTP|http|requestfailed|pageerror|Final Response|Code Agent|web-probe|observe|analyzer|终态/u;
|
||||
const memoryChartFrame = Object.freeze({
|
||||
left: 64,
|
||||
right: 696,
|
||||
top: 20,
|
||||
bottom: 132,
|
||||
yLabelX: 56,
|
||||
xLabelY: 154,
|
||||
xTitleY: 172,
|
||||
});
|
||||
|
||||
createApp({
|
||||
setup() {
|
||||
@@ -113,6 +122,18 @@ createApp({
|
||||
});
|
||||
const detailMemoryMax = computed(() => Math.max(1, ...detailMemorySeries.value.flatMap((series) => series.points.map((point) => number(point.memoryMb)))));
|
||||
const detailMemoryDurationMax = computed(() => Math.max(1, ...detailMemorySeries.value.flatMap((series) => series.points.map((point) => number(point.elapsedMinutes)))));
|
||||
const detailMemoryYAxisTicks = computed(() => memoryTickValues(detailMemoryMax.value).map((value) => ({
|
||||
key: `memory-y-${value}`,
|
||||
value,
|
||||
y: memoryYValue(value),
|
||||
label: formatMb(value),
|
||||
})));
|
||||
const detailMemoryXAxisTicks = computed(() => memoryTickValues(detailMemoryDurationMax.value).map((value) => ({
|
||||
key: `memory-x-${value}`,
|
||||
value,
|
||||
x: memoryXValue(value),
|
||||
label: formatMinuteTick(value),
|
||||
})));
|
||||
const scopedCheckFindings = computed(() => {
|
||||
if (checkScope.value === "history") return historicalCheckFindings.value;
|
||||
return runDetailCheckFindings.value;
|
||||
@@ -318,12 +339,22 @@ createApp({
|
||||
|
||||
function memoryX(point) {
|
||||
const elapsed = number(point?.elapsedMinutes);
|
||||
return Math.round(24 + (elapsed / detailMemoryDurationMax.value) * 672);
|
||||
return memoryXValue(elapsed);
|
||||
}
|
||||
|
||||
function memoryY(point) {
|
||||
const memory = number(point?.memoryMb);
|
||||
return Math.round(126 - (memory / detailMemoryMax.value) * 102);
|
||||
return memoryYValue(memory);
|
||||
}
|
||||
|
||||
function memoryXValue(elapsedMinutes) {
|
||||
const ratio = clamp(number(elapsedMinutes) / detailMemoryDurationMax.value, 0, 1);
|
||||
return Math.round(memoryChartFrame.left + ratio * (memoryChartFrame.right - memoryChartFrame.left));
|
||||
}
|
||||
|
||||
function memoryYValue(memoryMb) {
|
||||
const ratio = clamp(number(memoryMb) / detailMemoryMax.value, 0, 1);
|
||||
return Math.round(memoryChartFrame.bottom - ratio * (memoryChartFrame.bottom - memoryChartFrame.top));
|
||||
}
|
||||
|
||||
function memoryLineClass(index) {
|
||||
@@ -402,6 +433,9 @@ createApp({
|
||||
detailMemorySeries,
|
||||
detailMemoryMax,
|
||||
detailMemoryDurationMax,
|
||||
detailMemoryYAxisTicks,
|
||||
detailMemoryXAxisTicks,
|
||||
memoryFrame: memoryChartFrame,
|
||||
scopedCheckFindings,
|
||||
scopedCheckSummary,
|
||||
visibleCheckFindings,
|
||||
@@ -724,10 +758,23 @@ createApp({
|
||||
<span class="tag">每个页面一条线 · 峰值 {{ formatMb(detailMemory.maxMemoryMb || detailMemoryMax) }}</span>
|
||||
</div>
|
||||
<div v-if="detailMemorySeries.length > 0" class="memory-chart-wrap">
|
||||
<svg class="memory-chart" viewBox="0 0 720 142" role="img" aria-label="运行详情页面内存曲线">
|
||||
<line class="trend-grid-line" x1="24" x2="696" y1="24" y2="24"></line>
|
||||
<line class="trend-grid-line" x1="24" x2="696" y1="75" y2="75"></line>
|
||||
<line class="trend-grid-line" x1="24" x2="696" y1="126" y2="126"></line>
|
||||
<svg class="memory-chart" viewBox="0 0 720 178" role="img" aria-label="运行详情页面内存曲线,纵轴为 MB,横轴为运行分钟">
|
||||
<g data-memory-axis-y="true">
|
||||
<g v-for="tick in detailMemoryYAxisTicks" :key="tick.key" data-memory-axis-y-tick="true">
|
||||
<line class="memory-grid-line" :x1="memoryFrame.left" :x2="memoryFrame.right" :y1="tick.y" :y2="tick.y"></line>
|
||||
<text class="memory-axis-label memory-axis-label-y" :x="memoryFrame.yLabelX" :y="tick.y + 4">{{ tick.label }}</text>
|
||||
</g>
|
||||
<line class="memory-axis-line" :x1="memoryFrame.left" :x2="memoryFrame.left" :y1="memoryFrame.top" :y2="memoryFrame.bottom"></line>
|
||||
<text class="memory-axis-title memory-axis-title-y" x="18" y="78" transform="rotate(-90 18 78)">内存 MB</text>
|
||||
</g>
|
||||
<g data-memory-axis-x="true">
|
||||
<line class="memory-axis-line" :x1="memoryFrame.left" :x2="memoryFrame.right" :y1="memoryFrame.bottom" :y2="memoryFrame.bottom"></line>
|
||||
<g v-for="tick in detailMemoryXAxisTicks" :key="tick.key" data-memory-axis-x-tick="true">
|
||||
<line class="memory-tick-line" :x1="tick.x" :x2="tick.x" :y1="memoryFrame.bottom" :y2="memoryFrame.bottom + 6"></line>
|
||||
<text class="memory-axis-label memory-axis-label-x" :x="tick.x" :y="memoryFrame.xLabelY">{{ tick.label }}</text>
|
||||
</g>
|
||||
<text class="memory-axis-title memory-axis-title-x" :x="(memoryFrame.left + memoryFrame.right) / 2" :y="memoryFrame.xTitleY">运行分钟</text>
|
||||
</g>
|
||||
<polyline
|
||||
v-for="(series, index) in detailMemorySeries"
|
||||
:key="series.key || series.label || index"
|
||||
@@ -736,11 +783,6 @@ createApp({
|
||||
:points="memoryPolyline(series)"
|
||||
></polyline>
|
||||
</svg>
|
||||
<div class="memory-axis">
|
||||
<span>0m</span>
|
||||
<span>{{ formatMinutes(detailMemoryDurationMax) }}</span>
|
||||
<span>峰值 {{ formatMb(detailMemory.maxMemoryMb || detailMemoryMax) }}</span>
|
||||
</div>
|
||||
<div class="memory-legend">
|
||||
<span
|
||||
v-for="(series, index) in detailMemorySeries"
|
||||
@@ -1065,6 +1107,14 @@ function formatMinutes(value) {
|
||||
return `${Number.isInteger(rounded) ? String(rounded) : String(rounded).replace(/0+$/u, "").replace(/\.$/u, "")} 分钟`;
|
||||
}
|
||||
|
||||
function formatMinuteTick(value) {
|
||||
const numberValue = optionalNumber(value);
|
||||
if (numberValue === null) return "-";
|
||||
const rounded = Math.round(numberValue * 100) / 100;
|
||||
const text = Number.isInteger(rounded) ? String(rounded) : String(rounded).replace(/0+$/u, "").replace(/\.$/u, "");
|
||||
return `${text}m`;
|
||||
}
|
||||
|
||||
function formatMb(value) {
|
||||
const numberValue = optionalNumber(value);
|
||||
if (numberValue === null) return "-";
|
||||
@@ -1073,6 +1123,11 @@ function formatMb(value) {
|
||||
return `${text} MB`;
|
||||
}
|
||||
|
||||
function memoryTickValues(maxValue) {
|
||||
const max = Math.max(1, number(maxValue));
|
||||
return [0, max / 2, max];
|
||||
}
|
||||
|
||||
function runDurationText(run) {
|
||||
const timing = run?.timing || {};
|
||||
return formatMinutes(optionalNumber(run?.runDurationMinutes, run?.durationMinutes, timing.runDurationMinutes, timing.durationMinutes));
|
||||
|
||||
Reference in New Issue
Block a user