diff --git a/web/hwlab-cloud-web/src/components/agent/TraceTimeline.vue b/web/hwlab-cloud-web/src/components/agent/TraceTimeline.vue index 4ab551e7..fa5ff760 100644 --- a/web/hwlab-cloud-web/src/components/agent/TraceTimeline.vue +++ b/web/hwlab-cloud-web/src/components/agent/TraceTimeline.vue @@ -9,14 +9,22 @@ import { traceDisplayRows, type TraceEventRow } from "../../../../../tools/src/h const props = defineProps<{ trace?: RunnerTrace | null; defaultExpanded?: boolean; storageKey?: string; autoExpanded?: boolean | null }>(); +const TRACE_RENDER_ROW_WINDOW = 120; const listRef = ref(null); const expanded = ref(false); const { following, keepBottomAfterUpdate, onScroll, scrollToBottom } = useBottomFollowScroll(listRef, { threshold: 24 }); const events = computed(() => Array.isArray(props.trace?.events) ? props.trace.events : []); const eventCount = computed(() => props.trace?.eventCount ?? events.value.length); -const rawReadableRows = computed(() => traceDisplayRows(traceRecord(props.trace), events.value as Record[], { formatClock: formatDisplayClock })); +const rawReadableRows = computed(() => expanded.value ? traceDisplayRows(traceRecord(props.trace), events.value as Record[], { formatClock: formatDisplayClock }) : []); const readableRows = computed(() => rawReadableRows.value); +const hiddenRowCount = computed(() => Math.max(0, readableRows.value.length - TRACE_RENDER_ROW_WINDOW)); +const renderedRows = computed(() => hiddenRowCount.value > 0 ? readableRows.value.slice(-TRACE_RENDER_ROW_WINDOW) : readableRows.value); +const traceSummaryLabel = computed(() => { + const count = eventCount.value; + if (count <= 0) return String(props.trace?.status ?? "").trim() || "pending"; + return `${count} events`; +}); const projectionDiagnosticLabel = computed(() => { const projection = props.trace?.projection ?? null; const health = projection?.projectionHealth ?? props.trace?.projectionHealth; @@ -128,14 +136,16 @@ function firstNonEmptyString(...values: unknown[]): string | null {