diff --git a/core/ui/static/modules/actions.js b/core/ui/static/modules/actions.js
index 6edb7286..4ad3e55a 100644
--- a/core/ui/static/modules/actions.js
+++ b/core/ui/static/modules/actions.js
@@ -548,7 +548,7 @@ function renderReviewItem(item) {
if (item.commit_sha) parts.push(`commit ${escapeHtml(item.commit_sha.substring(0, 8))}`);
if (item.review_requested_at) {
const d = new Date(item.review_requested_at);
- const label = isNaN(d) ? item.review_requested_at : d.toLocaleString();
+ const label = isNaN(d) ? item.review_requested_at : formatFriendlyDate(item.review_requested_at);
parts.push(`${escapeHtml(label)}`);
}
return parts.length ? `
${parts.join('')}
` : '';
diff --git a/core/ui/static/modules/aether.js b/core/ui/static/modules/aether.js
index 9e811bc0..76829614 100644
--- a/core/ui/static/modules/aether.js
+++ b/core/ui/static/modules/aether.js
@@ -836,7 +836,8 @@ const Aether = (function() {
if (errorEl) errorEl.textContent = _stats.errors;
if (lastEventEl && _lastEvent) {
- const timeStr = _lastEvent.time.toLocaleTimeString();
+ const _t = _lastEvent.time;
+ const timeStr = `${_t.getHours().toString().padStart(2,'0')}:${_t.getMinutes().toString().padStart(2,'0')}:${_t.getSeconds().toString().padStart(2,'0')}`;
const colorVar = _lastEvent.type === 'START' ? '--color-success' :
_lastEvent.type === 'COMPLETE' ? '--color-secondary' : '--color-primary';
lastEventEl.innerHTML = `${_lastEvent.type}${timeStr}`;
diff --git a/core/ui/static/modules/decisions.js b/core/ui/static/modules/decisions.js
index 5cc9ff02..41203595 100644
--- a/core/ui/static/modules/decisions.js
+++ b/core/ui/static/modules/decisions.js
@@ -190,7 +190,10 @@ function _renderList() {
function _friendlyDate(iso) {
if (!iso) return '';
try {
- return new Date(iso).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
+ const d = new Date(iso);
+ if (isNaN(d.getTime())) return iso;
+ const months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
+ return `${months[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
} catch { return iso; }
}
diff --git a/core/ui/static/modules/processes.js b/core/ui/static/modules/processes.js
index 28d66079..6d2005aa 100644
--- a/core/ui/static/modules/processes.js
+++ b/core/ui/static/modules/processes.js
@@ -295,7 +295,7 @@ function toggleProcessExpand(processId) {
function renderOutputHtml(events) {
let html = '';
for (const evt of events) {
- const ts = evt.timestamp ? new Date(evt.timestamp).toLocaleTimeString() : '';
+ const ts = evt.timestamp ? formatCompactTime(evt.timestamp) : '';
const typeClass = evt.type === 'rate_limit' ? 'warning' : (evt.type === 'text' ? 'text' : 'tool');
const messageText = stripConsoleSequences(evt.message || '');
html += ``;
diff --git a/core/ui/static/modules/ui-updates.js b/core/ui/static/modules/ui-updates.js
index d95ab2cb..7c7ec94d 100644
--- a/core/ui/static/modules/ui-updates.js
+++ b/core/ui/static/modules/ui-updates.js
@@ -64,7 +64,8 @@ function updateUI(state) {
* Update timestamp display
*/
function updateTimestamp(instanceId) {
- setElementText('last-update', new Date().toLocaleTimeString());
+ const _now = new Date();
+ setElementText('last-update', `${_now.getHours().toString().padStart(2,'0')}:${_now.getMinutes().toString().padStart(2,'0')}:${_now.getSeconds().toString().padStart(2,'0')}`);
setElementText('instance-id', instanceId || '--');
// Update footer mission on each poll to ensure it's current
updateFooterMission();
@@ -143,7 +144,7 @@ function updateSessionInfo(session) {
if (session.started_at) {
const started = new Date(session.started_at);
- setElementText('session-started', started.toLocaleTimeString());
+ setElementText('session-started', `${started.getHours().toString().padStart(2,'0')}:${started.getMinutes().toString().padStart(2,'0')}:${started.getSeconds().toString().padStart(2,'0')}`);
sessionStartTime = started;
} else {
setElementText('session-started', '--');
diff --git a/core/ui/static/modules/utils.js b/core/ui/static/modules/utils.js
index 8eed31ee..bf7ae9a2 100644
--- a/core/ui/static/modules/utils.js
+++ b/core/ui/static/modules/utils.js
@@ -90,20 +90,22 @@ function formatCompactDate(isoString) {
/**
* Format ISO date string to human-friendly format with day of week
* @param {string} isoString - ISO date string
- * @returns {string} Formatted date like "Fri Dec 15 14:30"
+ * @returns {string} Formatted date like "Fri, Dec 15 2026 14:30"
*/
function formatFriendlyDate(isoString) {
if (!isoString) return '';
try {
const date = new Date(isoString);
+ if (isNaN(date.getTime())) return '';
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const dayOfWeek = days[date.getDay()];
const month = months[date.getMonth()];
const dayNum = date.getDate();
+ const year = date.getFullYear();
const hours = date.getHours().toString().padStart(2, '0');
const mins = date.getMinutes().toString().padStart(2, '0');
- return `${dayOfWeek} ${month} ${dayNum} ${hours}:${mins}`;
+ return `${dayOfWeek}, ${month} ${dayNum} ${year} ${hours}:${mins}`;
} catch (e) {
return '';
}
diff --git a/server/src/Dotbot.Server/wwwroot/css/dashboard.css b/server/src/Dotbot.Server/wwwroot/css/dashboard.css
index 9cdc0cb1..286be4ee 100644
--- a/server/src/Dotbot.Server/wwwroot/css/dashboard.css
+++ b/server/src/Dotbot.Server/wwwroot/css/dashboard.css
@@ -914,7 +914,7 @@ select.filter-input option {
background: var(--bg-panel);
border: 1px solid var(--bezel-edge);
border-radius: 6px;
- max-width: 900px;
+ max-width: 920px;
width: 95%;
max-height: 80vh;
overflow: hidden;
diff --git a/server/src/Dotbot.Server/wwwroot/js/dashboard.js b/server/src/Dotbot.Server/wwwroot/js/dashboard.js
index 374f205d..5948633d 100644
--- a/server/src/Dotbot.Server/wwwroot/js/dashboard.js
+++ b/server/src/Dotbot.Server/wwwroot/js/dashboard.js
@@ -5,6 +5,15 @@
(function () {
'use strict';
+ // --- Formatters ---
+ const _dtFormatter = new Intl.DateTimeFormat('en-US', {
+ weekday: 'short', month: 'short', day: 'numeric',
+ year: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false
+ });
+ const _timeFormatter = new Intl.DateTimeFormat('en-US', {
+ hour: '2-digit', minute: '2-digit', hour12: false
+ });
+
// --- State ---
let allInstances = [];
let byPerson = {}; // email -> [{ instance, recipient, response }]
@@ -16,6 +25,26 @@
let nudgeCooldowns = {}; // key -> timestamp
// --- Helpers ---
+ function formatDashboardDateTime(date) {
+ try {
+ const d = date instanceof Date ? date : new Date(date);
+ if (isNaN(d.getTime())) return String(date);
+ const parts = _dtFormatter.formatToParts(d);
+ const get = (t) => (parts.find(p => p.type === t) || {}).value || '';
+ return `${get('weekday')}, ${get('month')} ${get('day')} ${get('year')} ${get('hour')}:${get('minute')}`;
+ } catch (e) { return String(date); }
+ }
+
+ function formatDashboardTime(date) {
+ try {
+ const d = date instanceof Date ? date : new Date(date);
+ if (isNaN(d.getTime())) return '';
+ const parts = _timeFormatter.formatToParts(d);
+ const get = (t) => (parts.find(p => p.type === t) || {}).value || '';
+ return `${get('hour')}:${get('minute')}`;
+ } catch (e) { return ''; }
+ }
+
function buildRecipientPills(recipients, max) {
if (!recipients || recipients.length === 0) return '';
// Sort: non-responders first, then responders
@@ -286,7 +315,7 @@
Created
- ${inst.createdAt ? new Date(inst.createdAt).toLocaleString() : '-'}
+ ${inst.createdAt ? formatDashboardDateTime(inst.createdAt) : '-'}
Created By
@@ -814,6 +843,6 @@
function updateRefreshTime() {
const el = document.getElementById('last-refresh');
- el.textContent = `Last refresh: ${new Date().toLocaleTimeString()}`;
+ el.textContent = `Last refresh: ${formatDashboardTime(new Date())}`;
}
})();