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 `
`;
},
},
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 ``;
},
},
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 ``;
},
},
@@ -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 ``;
},
},
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'),