diff --git a/client/src/components/GraphModal.vue b/client/src/components/GraphModal.vue index a986f37..4b95428 100644 --- a/client/src/components/GraphModal.vue +++ b/client/src/components/GraphModal.vue @@ -15,11 +15,11 @@ watch([() => props.metricKey, mode], async ([key]) => { if(mode.value === 'hourly') { past.setHours(past.getHours() - 24, 0, 0, 0); future.setHours(future.getHours() + 24, 0, 0, 0); - rows.value = await api.hourly(past, future, props.metricKey || undefined); + rows.value = await api.hourly(past, future, `time,${props.metricKey}`); } else { past.setDate(past.getDate() - 3); future.setDate(future.getDate() + 3); - rows.value = await api.daily(past, future); + rows.value = await api.daily(past, future, `time,${props.metricKey}`); } }, {immediate: true}); @@ -54,6 +54,7 @@ const chart = computed(() => { // stitch current point into both paths so lines meet const nearest = pts.reduce((a, b) => Math.abs(a.t - nowT) < Math.abs(b.t - nowT) ? a : b); const dot = {x: xOf(nearest.t), y: yOf(nearest.v as number), v: nearest.v}; + hist.push({t: nearest.t, v: nearest.v}); const toPath = (arr: typeof pts) => arr.map((p, i) => `${i===0?'M':'L'} ${xOf(p.t).toFixed(1)} ${yOf(p.v as number).toFixed(1)}`).join(' '); diff --git a/server/src/influx.mjs b/server/src/influx.mjs index 012cb51..cdf5f43 100644 --- a/server/src/influx.mjs +++ b/server/src/influx.mjs @@ -92,6 +92,7 @@ export async function queryDaily(start, end) { from(bucket: "${c.INFLUX_BUCKET}") |> range(start: ${start.toISOString()}, stop: ${end.toISOString()}) |> filter(fn: (r) => r._measurement == "${m}") + |> group(columns: ["_field"]) |> aggregateWindow(every: 1d, fn: mean, createEmpty: false) |> pivot(rowKey: ["_time"], columnKey: ["_field"], valueColumn: "_value") `), @@ -99,6 +100,7 @@ export async function queryDaily(start, end) { from(bucket: "${c.INFLUX_BUCKET}") |> range(start: ${start.toISOString()}, stop: ${end.toISOString()}) |> filter(fn: (r) => r._measurement == "${m}") + |> group(columns: ["_field"]) |> aggregateWindow(every: 1d, fn: min, createEmpty: false) |> pivot(rowKey: ["_time"], columnKey: ["_field"], valueColumn: "_value") `), @@ -106,19 +108,18 @@ export async function queryDaily(start, end) { from(bucket: "${c.INFLUX_BUCKET}") |> range(start: ${start.toISOString()}, stop: ${end.toISOString()}) |> filter(fn: (r) => r._measurement == "${m}") + |> group(columns: ["_field"]) |> aggregateWindow(every: 1d, fn: max, createEmpty: false) |> pivot(rowKey: ["_time"], columnKey: ["_field"], valueColumn: "_value") `), ]); - // Mean values are the base — flat field names, no suffix for(const row of means) { const time = truncateToDay(row._time); if(!results[time]) results[time] = {time}; Object.assign(results[time], extractRow(row)); } - // Only promote temp min/max to named fields, ignore the rest for(const row of mins) { const time = truncateToDay(row._time); if(!results[time]) results[time] = {time};