mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 13:10:37 -04:00
feat(ui): let users choose local or UTC chart tooltip times
This commit is contained in:
@@ -208,6 +208,44 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-header">
|
||||
<div>
|
||||
<h2>Chart times</h2>
|
||||
<p>Choose which times chart tooltips show.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="application-settings-section-body grid gap-3 sm:grid-cols-2">
|
||||
@foreach ([
|
||||
['value' => 'local', 'label' => 'Your time', 'description' => 'Show the time in the time zone of this browser.', 'lines' => ['Oct 24, 12:30:33']],
|
||||
['value' => 'utc', 'label' => 'Your time and UTC', 'description' => 'Also show the UTC time. Use it to compare with server logs.', 'lines' => ['Your time: Oct 24, 12:30:33 GMT+2', 'UTC: Oct 24, 10:30:33 UTC']],
|
||||
] as $option)
|
||||
<button type="button" @click="setChartTimes('{{ $option['value'] }}')"
|
||||
class="group overflow-hidden rounded-[10px] border border-neutral-200 bg-white text-left transition-[border-color,box-shadow] hover:border-neutral-300 hover:shadow-sm dark:border-white/[0.07] dark:bg-white/[0.05] dark:hover:border-white/[0.12]"
|
||||
:class="chartTimes === '{{ $option['value'] }}'
|
||||
? 'border-coollabs! bg-coollabs/[0.06]! ring-2 ring-coollabs/25 dark:border-brand-light! dark:bg-brand-light/[0.08]! dark:ring-brand-light/25'
|
||||
: ''">
|
||||
<div class="flex h-20 items-center justify-center border-b border-neutral-200 bg-neutral-50 px-4 dark:border-white/[0.07] dark:bg-black/15">
|
||||
<div class="rounded-md border border-neutral-300 bg-white px-2.5 py-1.5 text-[11px] leading-4 dark:border-white/15 dark:bg-[#181818]">
|
||||
<div class="text-black dark:text-fg">CPU: <span class="font-semibold">4.3%</span></div>
|
||||
@foreach ($option['lines'] as $line)
|
||||
<div class="text-neutral-500 dark:text-fg-dim">{{ $line }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-sm font-semibold text-black dark:text-fg">{{ $option['label'] }}</span>
|
||||
<x-reicon name="check-circle" class="size-4 text-coollabs dark:text-brand-light"
|
||||
x-show="chartTimes === '{{ $option['value'] }}'" x-cloak />
|
||||
</div>
|
||||
<p class="mt-1 text-xs leading-5 text-neutral-500 dark:text-fg-dim">{{ $option['description'] }}</p>
|
||||
</div>
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{-- Custom theme dialog: presets, a preview, four colors, and a share code. Save applies the draft. --}}
|
||||
<template x-teleport="body">
|
||||
<div x-show="dialogOpen" x-cloak @keydown.escape.window="dialogOpen = false"
|
||||
|
||||
@@ -138,6 +138,25 @@
|
||||
root.style.setProperty('--theme-accent-foreground', window.themeAccentForeground(localStorage.themeColor));
|
||||
document.querySelector('meta[name=theme-color]')?.setAttribute('content', isDark ? '#101010' : '#ffffff');
|
||||
};
|
||||
// Time lines for chart tooltips. By default only the browser time zone is shown;
|
||||
// the "Chart times" option on the Appearance page adds the UTC time.
|
||||
window.chartTooltipTime = (timestamp, { seconds = true } = {}) => {
|
||||
const format = (timeZone) => new Date(timestamp).toLocaleString(undefined, {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
...(seconds ? { second: '2-digit' } : {}),
|
||||
hourCycle: 'h23',
|
||||
...(timeZone ? { timeZone, timeZoneName: 'short' } : {}),
|
||||
});
|
||||
if (localStorage.getItem('chartTimes') !== 'utc') {
|
||||
return `<div class="apexcharts-tooltip-custom-title">${format()}</div>`;
|
||||
}
|
||||
const localTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
return `<div class="apexcharts-tooltip-custom-title">Your time: ${format(localTimeZone)}</div>
|
||||
<div class="apexcharts-tooltip-custom-title">UTC: ${format('UTC')}</div>`;
|
||||
};
|
||||
// Shows the tooltip at the same time on every chart of a group while one of them is hovered.
|
||||
// ApexCharts' own chart.group needs equal widths and equal x ranges, so it does not
|
||||
// fit side-by-side cards. Instead, replay the hover as a mouse event at the matching x.
|
||||
@@ -187,6 +206,7 @@
|
||||
pageWidth: localStorage.getItem('pageWidth') || 'centered',
|
||||
navStyle: localStorage.getItem('navStyle') === 'floating' ? 'floating' : 'default',
|
||||
navItems: localStorage.getItem('navItems') === 'flat' ? 'flat' : '3d',
|
||||
chartTimes: localStorage.getItem('chartTimes') === 'utc' ? 'utc' : 'local',
|
||||
presets: window.customThemePresets,
|
||||
// The custom theme dialog edits a draft; Save applies it. A null draft is the built-in Dark theme.
|
||||
dialogOpen: false,
|
||||
@@ -272,6 +292,10 @@
|
||||
localStorage.setItem('navItems', style);
|
||||
document.documentElement.dataset.navItems = style;
|
||||
},
|
||||
setChartTimes(value) {
|
||||
this.chartTimes = value;
|
||||
localStorage.setItem('chartTimes', value);
|
||||
},
|
||||
});
|
||||
|
||||
document.addEventListener('livewire:navigated', window.applyStoredTheme);
|
||||
|
||||
@@ -92,23 +92,13 @@
|
||||
const memory = series[1][dataPointIndex];
|
||||
const timestamp = w.globals.seriesX[seriesIndex][dataPointIndex];
|
||||
const formatPercent = value => Number.isFinite(value) ? `${Number(value.toFixed(1))}%` : '—';
|
||||
const formatLocalTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, {
|
||||
hour12: false,
|
||||
timeZoneName: 'short',
|
||||
});
|
||||
const formatUtcTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, {
|
||||
hour12: false,
|
||||
timeZone: 'UTC',
|
||||
timeZoneName: 'short',
|
||||
});
|
||||
|
||||
const dot = color => `<span style="display:inline-block;width:8px;height:8px;border-radius:9999px;margin-right:6px;flex:none;background:${color}"></span>`;
|
||||
|
||||
return `<div class="apexcharts-tooltip-custom">
|
||||
<div class="apexcharts-tooltip-custom-value" style="display:flex;align-items:center">${dot('rgb(30, 144, 255)')}CPU: <span class="apexcharts-tooltip-value-bold" style="margin-left:4px">${formatPercent(cpu)}</span></div>
|
||||
<div class="apexcharts-tooltip-custom-value" style="display:flex;align-items:center">${dot('rgb(168, 85, 247)')}Memory: <span class="apexcharts-tooltip-value-bold" style="margin-left:4px">${formatPercent(memory)}</span></div>
|
||||
<div class="apexcharts-tooltip-custom-title">Your time: ${formatLocalTimestamp(timestamp)}</div>
|
||||
<div class="apexcharts-tooltip-custom-title">UTC: ${formatUtcTimestamp(timestamp)}</div>
|
||||
${window.chartTooltipTime(timestamp)}
|
||||
</div>`;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -380,9 +380,6 @@ $serverListboxOptions = array_merge(
|
||||
};
|
||||
const fmtRate = v => `${fmtBytes(v)}/s`;
|
||||
|
||||
const fmtLocalTime = ts => new Date(ts).toLocaleString(undefined, { hour12: false, timeZoneName: 'short' });
|
||||
const fmtUtcTime = ts => new Date(ts).toLocaleString(undefined, { hour12: false, timeZone: 'UTC', timeZoneName: 'short' });
|
||||
|
||||
// The app strips the default ApexCharts tooltip background (utilities.css), so
|
||||
// every chart must render its own `apexcharts-tooltip-custom` markup.
|
||||
const customTooltip = formatter => ({ series, dataPointIndex, w }) => {
|
||||
@@ -394,8 +391,7 @@ $serverListboxOptions = array_merge(
|
||||
rows += `<div class="apexcharts-tooltip-custom-value">${w.globals.seriesNames[i]}: <span class="apexcharts-tooltip-value-bold">${formatter(value)}</span></div>`;
|
||||
});
|
||||
return `<div class="apexcharts-tooltip-custom">${rows}
|
||||
<div class="apexcharts-tooltip-custom-title">Your time: ${fmtLocalTime(timestamp)}</div>
|
||||
<div class="apexcharts-tooltip-custom-title">UTC: ${fmtUtcTime(timestamp)}</div>
|
||||
${window.chartTooltipTime(timestamp)}
|
||||
</div>`;
|
||||
};
|
||||
|
||||
|
||||
@@ -125,15 +125,6 @@
|
||||
};
|
||||
const formatRate = value => `${formatBytes(value)}/s`;
|
||||
|
||||
const formatLocalTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, {
|
||||
hour12: false,
|
||||
timeZoneName: 'short',
|
||||
});
|
||||
const formatUtcTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, {
|
||||
hour12: false,
|
||||
timeZone: 'UTC',
|
||||
timeZoneName: 'short',
|
||||
});
|
||||
|
||||
const chartOptions = (name, color, loadingText, formatter = formatPercent) => ({
|
||||
chart: {
|
||||
@@ -226,8 +217,7 @@
|
||||
|
||||
return `<div class="apexcharts-tooltip-custom">
|
||||
${values.join('')}
|
||||
<div class="apexcharts-tooltip-custom-title">Your time: ${formatLocalTimestamp(timestamp)}</div>
|
||||
<div class="apexcharts-tooltip-custom-title">UTC: ${formatUtcTimestamp(timestamp)}</div>
|
||||
${window.chartTooltipTime(timestamp)}
|
||||
</div>`;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -47,15 +47,6 @@
|
||||
|
||||
// `24h` buckets are hourly, `7d`/`30d` daily — pick a matching axis/tooltip format.
|
||||
const timeFormat = range => (range === '24h' ? 'HH:mm' : 'dd MMM');
|
||||
const formatLocalTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, {
|
||||
hour12: false,
|
||||
timeZoneName: 'short',
|
||||
});
|
||||
const formatUtcTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, {
|
||||
hour12: false,
|
||||
timeZone: 'UTC',
|
||||
timeZoneName: 'short',
|
||||
});
|
||||
|
||||
const chart = new ApexCharts(el, {
|
||||
chart: {
|
||||
@@ -108,8 +99,7 @@
|
||||
|
||||
return `<div class="apexcharts-tooltip-custom">
|
||||
<div class="apexcharts-tooltip-custom-value">Requests: <span class="apexcharts-tooltip-value-bold">${requests.toLocaleString()}</span></div>
|
||||
<div class="apexcharts-tooltip-custom-title">Your time: ${formatLocalTimestamp(timestamp)}</div>
|
||||
<div class="apexcharts-tooltip-custom-title">UTC: ${formatUtcTimestamp(timestamp)}</div>
|
||||
${window.chartTooltipTime(timestamp, { seconds: false })}
|
||||
</div>`;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -65,15 +65,6 @@
|
||||
init() {
|
||||
if (typeof ApexCharts === 'undefined') { return; }
|
||||
const o = this.opts(@js($initial), @js($initialCategories));
|
||||
const formatLocalTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, {
|
||||
hour12: false,
|
||||
timeZoneName: 'short',
|
||||
});
|
||||
const formatUtcTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, {
|
||||
hour12: false,
|
||||
timeZone: 'UTC',
|
||||
timeZoneName: 'short',
|
||||
});
|
||||
const formatValue = value => {
|
||||
if (value === null || value === undefined) { return '—'; }
|
||||
const fmt = @js($format);
|
||||
@@ -110,8 +101,7 @@
|
||||
const timestamp = w.globals.seriesX[0][dataPointIndex];
|
||||
return `<div class='apexcharts-tooltip-custom'>
|
||||
<div class='apexcharts-tooltip-custom-value'>${@js($label)}: <span class='apexcharts-tooltip-value-bold'>${formatValue(value)}</span></div>
|
||||
<div class='apexcharts-tooltip-custom-title'>Your time: ${formatLocalTimestamp(timestamp)}</div>
|
||||
<div class='apexcharts-tooltip-custom-title'>UTC: ${formatUtcTimestamp(timestamp)}</div>
|
||||
${window.chartTooltipTime(timestamp, { seconds: false })}
|
||||
</div>`;
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user