diff --git a/dashboard/src/components/GraphItem.vue b/dashboard/src/components/GraphItem.vue index dc23e3f2b..fb5927b43 100644 --- a/dashboard/src/components/GraphItem.vue +++ b/dashboard/src/components/GraphItem.vue @@ -4,7 +4,7 @@ import moment from 'moment-timezone'; import { onMounted, onUnmounted, useTemplateRef, watch } from 'vue'; import Chart from 'chart.js/auto'; -import { prettyDecimalSize } from '@cloudron/pankow/utils'; +import { prettyDecimalSize, prettyLongDate, prettyShortDate } from '@cloudron/pankow/utils'; import annotationPlugin from 'chartjs-plugin-annotation'; Chart.register(annotationPlugin); @@ -12,6 +12,7 @@ Chart.register(annotationPlugin); const LIVE_REFRESH_INTERVAL_MSECS = 1000; // for realtime graphs, the time (x axis) advances at this pace const graphNode = useTemplateRef('graphNode'); +const tooltipElem = useTemplateRef('tooltipElem'); let graph = null; let liveRefreshIntervalId = null; @@ -50,11 +51,40 @@ function createGraphOptions({ yscale, period, highMark }) { position: 'bottom' // not used, hidden since color code is shown in tooltip }, tooltip: { + enabled: false, + external: function(context) { + const tooltipModel = context.tooltip; + if (tooltipModel.opacity === 0) { + tooltipElem.value.style.opacity = 0; + return; + } + + // Set Text + if (tooltipModel.body) { + const titleLines = tooltipModel.title || []; + const bodyLines = tooltipModel.body.map(item => item.lines); + + let innerHtml = `
${titleLines[0]}
`; + + bodyLines.forEach(function(body, i) { + const colors = tooltipModel.labelColors[i]; + innerHtml += `
${body}
`; + }); + + tooltipElem.value.innerHTML = innerHtml; + } + + tooltipElem.value.style.opacity = 1; + tooltipElem.value.style.position = 'absolute'; + tooltipElem.value.style.left = tooltipModel.caretX + 'px'; + tooltipElem.value.style.top = 0 + 'px'; + tooltipElem.value.style.height = '100%'; + }, callbacks: { - title: (tooltipItem) => moment(tooltipItem[0].raw.x).format(period.tooltipFormat), + title: (tooltipItem) => period.tooltipFormat === 'long' ? prettyLongDate(tooltipItem[0].raw.x) : prettyShortDate(tooltipItem[0].raw.x), label: (tooltipItem) => { const datasetLabel = tooltipItem.chart.data.datasets[tooltipItem.datasetIndex].label; - return `${datasetLabel}: ${yscale.ticks.callback(tooltipItem.raw.y)}`; + return `${yscale.ticks.callback(tooltipItem.raw.y)}: ${datasetLabel}`; } } }, @@ -260,6 +290,7 @@ defineExpose({
+
@@ -277,3 +308,23 @@ defineExpose({ } + + diff --git a/dashboard/src/components/SystemMetrics.vue b/dashboard/src/components/SystemMetrics.vue index 11fa03139..aeb3a7e12 100644 --- a/dashboard/src/components/SystemMetrics.vue +++ b/dashboard/src/components/SystemMetrics.vue @@ -16,13 +16,13 @@ const systemModel = SystemModel.create(); const appsModel = AppsModel.create(); const periods = [ - { hours: 0, label: t('app.graphs.period.live'), tickFormat: 'hh:mm A', tooltipFormat: 'hh:mm:ss A' }, - { hours: 1, intervalSecs: 20, label: t('app.graphs.period.1h'), tickFormat: 'hh:mm A', tooltipFormat: 'hh:mm:ss A' }, // 180 points - { hours: 6, intervalSecs: 60, label: t('app.graphs.period.6h'), tickFormat: 'hh:mm A', tooltipFormat: 'hh:mm A' }, - { hours: 12, intervalSecs: 240, label: t('app.graphs.period.12h'), tickFormat: 'hh:mm A', tooltipFormat: 'hh:mm A' }, - { hours: 24, intervalSecs: 480, label: t('app.graphs.period.24h'), tickFormat: 'hh:mm A', tooltipFormat: 'hh:mm A' }, - { hours: 24*7, intervalSecs: 960, label: t('app.graphs.period.7d'), tickFormat: 'DD MMM', tooltipFormat: 'DD MMM hh:mm A' }, - { hours: 24*30, intervalSecs: 960, label: t('app.graphs.period.30d'), tickFormat: 'DD MMM', tooltipFormat: 'DD MMM hh:mm A' }, // 2700 points + { hours: 0, label: t('app.graphs.period.live'), tickFormat: 'hh:mm A', tooltipFormat: 'short' }, + { hours: 1, intervalSecs: 20, label: t('app.graphs.period.1h'), tickFormat: 'hh:mm A', tooltipFormat: 'short' }, // 180 points + { hours: 6, intervalSecs: 60, label: t('app.graphs.period.6h'), tickFormat: 'hh:mm A', tooltipFormat: 'short' }, + { hours: 12, intervalSecs: 240, label: t('app.graphs.period.12h'), tickFormat: 'hh:mm A', tooltipFormat: 'short' }, + { hours: 24, intervalSecs: 480, label: t('app.graphs.period.24h'), tickFormat: 'hh:mm A', tooltipFormat: 'short' }, + { hours: 24*7, intervalSecs: 960, label: t('app.graphs.period.7d'), tickFormat: 'DD MMM', tooltipFormat: 'long' }, + { hours: 24*30, intervalSecs: 960, label: t('app.graphs.period.30d'), tickFormat: 'DD MMM', tooltipFormat: 'long' }, // 2700 points ]; const busy = ref(true);