diff --git a/resources/views/livewire/dashboard/server-metrics-chart.blade.php b/resources/views/livewire/dashboard/server-metrics-chart.blade.php index aae36747ae..7d6924d46c 100644 --- a/resources/views/livewire/dashboard/server-metrics-chart.blade.php +++ b/resources/views/livewire/dashboard/server-metrics-chart.blade.php @@ -92,15 +92,21 @@ const memory = series[1][dataPointIndex]; const timestamp = w.globals.seriesX[seriesIndex][dataPointIndex]; const formatPercent = value => Number.isFinite(value) ? `${Number(value.toFixed(1))}%` : '—'; - const formatTimestamp = timestamp => `${new Date(timestamp).toLocaleString(undefined, { - timeZone: 'UTC', + const formatLocalTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, { hour12: false, - })} UTC`; + timeZoneName: 'short', + }); + const formatUtcTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, { + hour12: false, + timeZone: 'UTC', + timeZoneName: 'short', + }); return `
CPU: ${formatPercent(cpu)}
Memory: ${formatPercent(memory)}
-
${formatTimestamp(timestamp)}
+
Your time: ${formatLocalTimestamp(timestamp)}
+
UTC: ${formatUtcTimestamp(timestamp)}
`; }, }, diff --git a/resources/views/livewire/server/charts.blade.php b/resources/views/livewire/server/charts.blade.php index da992ded2d..05d8b6f4b7 100644 --- a/resources/views/livewire/server/charts.blade.php +++ b/resources/views/livewire/server/charts.blade.php @@ -64,14 +64,15 @@ return `${Number(number.toFixed(precision))}%`; }; - const formatTimestamp = timestamp => { - const date = new Date(timestamp); - - return `${date.toLocaleString(undefined, { - timeZone: 'UTC', - hour12: false - })} UTC`; - }; + 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) => ({ chart: { @@ -163,7 +164,8 @@ return `
${name}: ${formatPercent(value)}
-
${formatTimestamp(timestamp)}
+
Your time: ${formatLocalTimestamp(timestamp)}
+
UTC: ${formatUtcTimestamp(timestamp)}
`; }, }, diff --git a/resources/views/livewire/traffic/_requests-chart.blade.php b/resources/views/livewire/traffic/_requests-chart.blade.php index d8ded84f5b..07c5870888 100644 --- a/resources/views/livewire/traffic/_requests-chart.blade.php +++ b/resources/views/livewire/traffic/_requests-chart.blade.php @@ -46,10 +46,15 @@ // `24h` buckets are hourly, `7d`/`30d` daily — pick a matching axis/tooltip format. const timeFormat = range => (range === '24h' ? 'HH:mm' : 'dd MMM'); - const formatTimestamp = timestamp => `${new Date(timestamp).toLocaleString(undefined, { - timeZone: 'UTC', + const formatLocalTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, { hour12: false, - })} UTC`; + timeZoneName: 'short', + }); + const formatUtcTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, { + hour12: false, + timeZone: 'UTC', + timeZoneName: 'short', + }); const chart = new ApexCharts(el, { chart: { @@ -84,7 +89,7 @@ }, grid: { borderColor: gridColor(), - padding: { left: 0, right: 12, top: 12, bottom: 0 }, + padding: { left: 6, right: 12, top: 12, bottom: 0 }, }, legend: { show: false }, noData: { @@ -101,7 +106,8 @@ return `
Requests: ${requests.toLocaleString()}
-
${formatTimestamp(timestamp)}
+
Your time: ${formatLocalTimestamp(timestamp)}
+
UTC: ${formatUtcTimestamp(timestamp)}
`; }, }, @@ -124,7 +130,7 @@ colors: [accent()], grid: { borderColor: gridColor(), - padding: { left: 0, right: 12, top: 12, bottom: 0 }, + padding: { left: 6, right: 12, top: 12, bottom: 0 }, }, xaxis: { type: 'datetime', diff --git a/resources/views/livewire/traffic/_sparkline.blade.php b/resources/views/livewire/traffic/_sparkline.blade.php index 1e13f48214..4fb3ce8cc2 100644 --- a/resources/views/livewire/traffic/_sparkline.blade.php +++ b/resources/views/livewire/traffic/_sparkline.blade.php @@ -58,10 +58,15 @@ init() { if (typeof ApexCharts === 'undefined') { return; } const o = this.opts(@js($initial), @js($initialCategories)); - const formatTimestamp = timestamp => `${new Date(timestamp).toLocaleString(undefined, { - timeZone: 'UTC', + const formatLocalTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, { hour12: false, - })} UTC`; + timeZoneName: 'short', + }); + const formatUtcTimestamp = timestamp => new Date(timestamp).toLocaleString(undefined, { + hour12: false, + timeZone: 'UTC', + timeZoneName: 'short', + }); const formatValue = value => { if (@js($key) === 'bandwidthSpark') { const units = ['B', 'KB', 'MB', 'GB', 'TB']; @@ -95,7 +100,8 @@ const timestamp = w.globals.seriesX[0][dataPointIndex]; return `
${@js($label)}: ${formatValue(value)}
-
${formatTimestamp(timestamp)}
+
Your time: ${formatLocalTimestamp(timestamp)}
+
UTC: ${formatUtcTimestamp(timestamp)}
`; }, }, diff --git a/tests/Feature/DashboardServerMetricsChartTest.php b/tests/Feature/DashboardServerMetricsChartTest.php index 4d7c64d0fd..c1208106b7 100644 --- a/tests/Feature/DashboardServerMetricsChartTest.php +++ b/tests/Feature/DashboardServerMetricsChartTest.php @@ -79,7 +79,8 @@ it('configures the dashboard chart as a ten minute cpu and memory sparkline with ->not->toContain('w-full overflow-hidden rounded-b-xl') ->toContain('CPU:') ->toContain('Memory:') - ->toContain('formatTimestamp(timestamp)') + ->toContain('formatLocalTimestamp(timestamp)') + ->toContain('formatUtcTimestamp(timestamp)') ->toContain("min: 0,\n max: 100,") ->toContain('labels: { show: false }'); }); diff --git a/tests/Feature/MetricsTooltipStylingTest.php b/tests/Feature/MetricsTooltipStylingTest.php index f748487e59..37d3764669 100644 --- a/tests/Feature/MetricsTooltipStylingTest.php +++ b/tests/Feature/MetricsTooltipStylingTest.php @@ -29,3 +29,14 @@ test('metrics charts render custom tooltip content', function (string $view) { 'server metrics' => 'views/livewire/server/charts.blade.php', 'resource metrics' => 'views/livewire/project/shared/metrics.blade.php', ]); + +test('server metric tooltips show local and UTC timestamps', function (string $view) { + expect(file_get_contents(resource_path($view))) + ->toContain('formatLocalTimestamp(timestamp)') + ->toContain('formatUtcTimestamp(timestamp)') + ->toContain('Your time:') + ->toContain('UTC:'); +})->with([ + 'dashboard server metrics' => 'views/livewire/dashboard/server-metrics-chart.blade.php', + 'server metrics' => 'views/livewire/server/charts.blade.php', +]); diff --git a/tests/Feature/TrafficAnalytics/ChartTokensTest.php b/tests/Feature/TrafficAnalytics/ChartTokensTest.php index c9e2467930..c9cc84b764 100644 --- a/tests/Feature/TrafficAnalytics/ChartTokensTest.php +++ b/tests/Feature/TrafficAnalytics/ChartTokensTest.php @@ -55,7 +55,7 @@ it('keeps request values in a compact y-axis outside the plot', function () { expect($partial) ->toContain('minWidth: 28') ->toContain('maxWidth: 28') - ->toContain('padding: { left: 0, right: 12, top: 12, bottom: 0 }') + ->toContain('padding: { left: 6, right: 12, top: 12, bottom: 0 }') ->not->toContain('floating: true') ->not->toContain('offsetX: 32'); }); @@ -110,18 +110,28 @@ it('keeps KPI sparklines axisless after live updates', function () { ->toContain('grid: { padding: { left: 4, right: 4, top: 0, bottom: 0 } }'); }); -it('shows values and UTC timestamps in analytics chart tooltips', function () { +it('shows values with local and UTC timestamps in analytics chart tooltips', function () { $sparkline = file_get_contents(base_path('resources/views/livewire/traffic/_sparkline.blade.php')); $requestsChart = file_get_contents(base_path('resources/views/livewire/traffic/_requests-chart.blade.php')); expect($sparkline) ->toContain('sparkCategories') ->toContain('apexcharts-tooltip-custom-value') - ->toContain('formatTimestamp(timestamp)'); + ->toContain('formatLocalTimestamp(timestamp)') + ->toContain('formatUtcTimestamp(timestamp)') + ->toContain('Your time:') + ->toContain('UTC:') + ->toContain("timeZoneName: 'short'") + ->toContain("timeZone: 'UTC'"); expect($requestsChart) ->toContain('apexcharts-tooltip-custom-value') - ->toContain('formatTimestamp(timestamp)'); + ->toContain('formatLocalTimestamp(timestamp)') + ->toContain('formatUtcTimestamp(timestamp)') + ->toContain('Your time:') + ->toContain('UTC:') + ->toContain("timeZoneName: 'short'") + ->toContain("timeZone: 'UTC'"); foreach ([ app_path('Livewire/Analytics.php'),