diff --git a/scripts/assets/web-probe-sentinel-monitor-web/monitor-web.css b/scripts/assets/web-probe-sentinel-monitor-web/monitor-web.css index c21d9160..09e5a0fd 100644 --- a/scripts/assets/web-probe-sentinel-monitor-web/monitor-web.css +++ b/scripts/assets/web-probe-sentinel-monitor-web/monitor-web.css @@ -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)); diff --git a/scripts/assets/web-probe-sentinel-monitor-web/monitor-web.js b/scripts/assets/web-probe-sentinel-monitor-web/monitor-web.js index 49a3f017..a6d3e8e5 100644 --- a/scripts/assets/web-probe-sentinel-monitor-web/monitor-web.js +++ b/scripts/assets/web-probe-sentinel-monitor-web/monitor-web.js @@ -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({ 每个页面一条线 · 峰值 {{ formatMb(detailMemory.maxMemoryMb || detailMemoryMax) }}
- - - - + + + + + {{ tick.label }} + + + 内存 MB + + + + + + {{ tick.label }} + + 运行分钟 + -
- 0m - {{ formatMinutes(detailMemoryDurationMax) }} - 峰值 {{ formatMb(detailMemory.maxMemoryMb || detailMemoryMax) }} -
= 3 + && memorySummary.axisYTickCount >= 3 + && memorySummary.axisHasUnits === true; const datasetSentinelId = String(dataset.sentinelId || ""); const finalPath = new URL(window.location.href).pathname.replace(/\/+$/u, "") || "/"; const expectedPath = expectedRoutePrefix.replace(/\/+$/u, "") || "/"; @@ -770,6 +782,7 @@ const dom = await page.evaluate(async ({ expectedRoutePrefix, expectedSentinelId latestFindingTypeCount: latestRunCounts.typeCount, trendCurves: chartTiming.ok, memoryPerPageLines: memorySummary.perPageLines, + memoryAxes: memorySummary.axesOk, }, sentinelBoundary, title: document.title, @@ -822,6 +835,7 @@ const ok = !navigationError && dom.requestedRunSelection?.ok === true && dom.chartTiming?.ok === true && dom.memorySummary?.perPageLines === true + && dom.memorySummary?.axesOk === true && dom.layout?.horizontalOverflow !== true && pageErrors.length === 0; @@ -1326,7 +1340,7 @@ function renderDashboardResult(result: Record): string { chartTiming.hasWarningCurve ?? "-", ]]), "", - table(["MEMORY_CHART", "MEMORY_RUN", "MEMORY_MATCH", "MEMORY_PAGES", "MEMORY_CURVES", "MEMORY_SAMPLES", "API_PAGES", "MEMORY_PAGE_LINES", "MEMORY_SOURCE"], [[ + table(["MEMORY_CHART", "MEMORY_RUN", "MEMORY_MATCH", "MEMORY_PAGES", "MEMORY_CURVES", "MEMORY_SAMPLES", "API_PAGES", "MEMORY_PAGE_LINES", "MEMORY_AXES", "X_TICKS", "Y_TICKS", "MEMORY_SOURCE"], [[ memorySummary.present ?? "-", memorySummary.runId ?? "-", memorySummary.matchesTargetRun ?? "-", @@ -1335,6 +1349,9 @@ function renderDashboardResult(result: Record): string { memorySummary.sampleCount ?? "-", memorySummary.apiPageCount ?? "-", memorySummary.perPageLines ?? "-", + memorySummary.axesOk ?? "-", + memorySummary.axisXTickCount ?? "-", + memorySummary.axisYTickCount ?? "-", memorySummary.source ?? memorySummary.apiSource ?? "-", ]]), "", diff --git a/scripts/verify-web-probe-sentinel-monitor-web.ts b/scripts/verify-web-probe-sentinel-monitor-web.ts index 611a1cc4..46abe861 100644 --- a/scripts/verify-web-probe-sentinel-monitor-web.ts +++ b/scripts/verify-web-probe-sentinel-monitor-web.ts @@ -12,13 +12,19 @@ const checks: Array<{ readonly path: string; readonly contains: readonly string[ "data-monitor-independent-scroll", "data-check-row", "data-check-dialog", + "data-memory-axis-x", + "data-memory-axis-y", "rootCause", ], }, { path: "scripts/assets/web-probe-sentinel-monitor-web/monitor-web.css", minBytes: 8_000, - contains: [], + contains: [ + ".memory-axis-line", + ".memory-axis-label", + ".memory-axis-title", + ], }, { path: "scripts/assets/web-probe-sentinel-monitor-web/vendor/vue.esm-browser.prod.js",