Fix activity feed blinking and show live relative timestamps

pull/253/head
Broque Thomas 2 months ago
parent 9bee72503f
commit a159ac3fd6

@ -3846,11 +3846,12 @@ def add_activity_item(icon: str, title: str, subtitle: str, time_ago: str = "Now
"""Add activity item to the feed (replicates dashboard.py functionality)"""
try:
import time
from datetime import datetime, timezone
activity_item = {
'icon': icon,
'title': title,
'subtitle': subtitle,
'time': time_ago,
'time': datetime.now(timezone.utc).isoformat(),
'timestamp': time.time(),
'show_toast': show_toast
}

@ -29835,21 +29835,16 @@ async function fetchAndUpdateActivityFeed() {
}
}
// Cache last feed signature to avoid unnecessary DOM rebuilds (prevents blink)
let _lastActivityFeedSig = '';
function updateActivityFeed(activities) {
const feedContainer = document.getElementById('dashboard-activity-feed');
if (!feedContainer) {
console.warn('Activity feed container not found!');
return;
}
console.log('Updating activity feed with', activities.length, 'activities:', activities);
// Clear existing content
feedContainer.innerHTML = '';
if (!feedContainer) return;
if (activities.length === 0) {
console.log('No activities found, showing placeholder');
// Show placeholder if no activities
if (_lastActivityFeedSig === 'empty') return;
_lastActivityFeedSig = 'empty';
feedContainer.innerHTML = `
<div class="activity-item">
<span class="activity-icon">📊</span>
@ -29857,14 +29852,30 @@ function updateActivityFeed(activities) {
<p class="activity-title">System Started</p>
<p class="activity-subtitle">Dashboard initialized successfully</p>
</div>
<p class="activity-time">Now</p>
<p class="activity-time">Just now</p>
</div>
`;
return;
}
// Add activities (limit to 5 most recent)
activities.slice(0, 5).forEach((activity, index) => {
const items = activities.slice(0, 5);
// Build signature from titles+subtitles to detect actual changes
const sig = items.map(a => a.title + a.subtitle).join('|');
const feedChanged = sig !== _lastActivityFeedSig;
_lastActivityFeedSig = sig;
if (!feedChanged) {
// Just update timestamps without rebuilding DOM
const timeEls = feedContainer.querySelectorAll('.activity-time');
items.forEach((activity, i) => {
if (timeEls[i]) timeEls[i].textContent = timeAgo(activity.time);
});
return;
}
// Full rebuild only when feed content actually changed
feedContainer.innerHTML = '';
items.forEach((activity, index) => {
const activityElement = document.createElement('div');
activityElement.className = 'activity-item';
activityElement.innerHTML = `
@ -29873,13 +29884,11 @@ function updateActivityFeed(activities) {
<p class="activity-title">${escapeHtml(activity.title)}</p>
<p class="activity-subtitle">${escapeHtml(activity.subtitle)}</p>
</div>
<p class="activity-time">${escapeHtml(activity.time)}</p>
<p class="activity-time">${timeAgo(activity.time)}</p>
`;
feedContainer.appendChild(activityElement);
// Add separator between items (except after last item)
if (index < activities.slice(0, 5).length - 1) {
if (index < items.length - 1) {
const separator = document.createElement('div');
separator.className = 'activity-separator';
feedContainer.appendChild(separator);
@ -47365,9 +47374,14 @@ async function hydrateMirroredDiscoveryStates() {
function timeAgo(dateStr) {
if (!dateStr) return '';
const diff = Date.now() - new Date(dateStr + (dateStr.includes('Z') ? '' : 'Z')).getTime();
const mins = Math.floor(diff / 60000);
if (mins < 1) return 'just now';
// Handle ISO formats: "Z" suffix, "+00:00" offset, or bare (assume UTC)
let ts = dateStr;
if (!ts.includes('Z') && !ts.includes('+') && !ts.includes('-', 10)) ts += 'Z';
const diff = Date.now() - new Date(ts).getTime();
const secs = Math.floor(diff / 1000);
if (secs < 5) return 'just now';
if (secs < 60) return `${secs}s ago`;
const mins = Math.floor(secs / 60);
if (mins < 60) return `${mins}m ago`;
const hrs = Math.floor(mins / 60);
if (hrs < 24) return `${hrs}h ago`;

Loading…
Cancel
Save