Fix activity feed blinking and show live relative timestamps
This commit is contained in:
parent
9bee72503f
commit
a159ac3fd6
2 changed files with 37 additions and 22 deletions
|
|
@ -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)"""
|
"""Add activity item to the feed (replicates dashboard.py functionality)"""
|
||||||
try:
|
try:
|
||||||
import time
|
import time
|
||||||
|
from datetime import datetime, timezone
|
||||||
activity_item = {
|
activity_item = {
|
||||||
'icon': icon,
|
'icon': icon,
|
||||||
'title': title,
|
'title': title,
|
||||||
'subtitle': subtitle,
|
'subtitle': subtitle,
|
||||||
'time': time_ago,
|
'time': datetime.now(timezone.utc).isoformat(),
|
||||||
'timestamp': time.time(),
|
'timestamp': time.time(),
|
||||||
'show_toast': show_toast
|
'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) {
|
function updateActivityFeed(activities) {
|
||||||
const feedContainer = document.getElementById('dashboard-activity-feed');
|
const feedContainer = document.getElementById('dashboard-activity-feed');
|
||||||
if (!feedContainer) {
|
if (!feedContainer) return;
|
||||||
console.warn('Activity feed container not found!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Updating activity feed with', activities.length, 'activities:', activities);
|
|
||||||
|
|
||||||
// Clear existing content
|
|
||||||
feedContainer.innerHTML = '';
|
|
||||||
|
|
||||||
if (activities.length === 0) {
|
if (activities.length === 0) {
|
||||||
console.log('No activities found, showing placeholder');
|
if (_lastActivityFeedSig === 'empty') return;
|
||||||
// Show placeholder if no activities
|
_lastActivityFeedSig = 'empty';
|
||||||
feedContainer.innerHTML = `
|
feedContainer.innerHTML = `
|
||||||
<div class="activity-item">
|
<div class="activity-item">
|
||||||
<span class="activity-icon">📊</span>
|
<span class="activity-icon">📊</span>
|
||||||
|
|
@ -29857,14 +29852,30 @@ function updateActivityFeed(activities) {
|
||||||
<p class="activity-title">System Started</p>
|
<p class="activity-title">System Started</p>
|
||||||
<p class="activity-subtitle">Dashboard initialized successfully</p>
|
<p class="activity-subtitle">Dashboard initialized successfully</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="activity-time">Now</p>
|
<p class="activity-time">Just now</p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add activities (limit to 5 most recent)
|
const items = activities.slice(0, 5);
|
||||||
activities.slice(0, 5).forEach((activity, index) => {
|
// 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');
|
const activityElement = document.createElement('div');
|
||||||
activityElement.className = 'activity-item';
|
activityElement.className = 'activity-item';
|
||||||
activityElement.innerHTML = `
|
activityElement.innerHTML = `
|
||||||
|
|
@ -29873,13 +29884,11 @@ function updateActivityFeed(activities) {
|
||||||
<p class="activity-title">${escapeHtml(activity.title)}</p>
|
<p class="activity-title">${escapeHtml(activity.title)}</p>
|
||||||
<p class="activity-subtitle">${escapeHtml(activity.subtitle)}</p>
|
<p class="activity-subtitle">${escapeHtml(activity.subtitle)}</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="activity-time">${escapeHtml(activity.time)}</p>
|
<p class="activity-time">${timeAgo(activity.time)}</p>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
feedContainer.appendChild(activityElement);
|
feedContainer.appendChild(activityElement);
|
||||||
|
|
||||||
// Add separator between items (except after last item)
|
if (index < items.length - 1) {
|
||||||
if (index < activities.slice(0, 5).length - 1) {
|
|
||||||
const separator = document.createElement('div');
|
const separator = document.createElement('div');
|
||||||
separator.className = 'activity-separator';
|
separator.className = 'activity-separator';
|
||||||
feedContainer.appendChild(separator);
|
feedContainer.appendChild(separator);
|
||||||
|
|
@ -47365,9 +47374,14 @@ async function hydrateMirroredDiscoveryStates() {
|
||||||
|
|
||||||
function timeAgo(dateStr) {
|
function timeAgo(dateStr) {
|
||||||
if (!dateStr) return '';
|
if (!dateStr) return '';
|
||||||
const diff = Date.now() - new Date(dateStr + (dateStr.includes('Z') ? '' : 'Z')).getTime();
|
// Handle ISO formats: "Z" suffix, "+00:00" offset, or bare (assume UTC)
|
||||||
const mins = Math.floor(diff / 60000);
|
let ts = dateStr;
|
||||||
if (mins < 1) return 'just now';
|
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`;
|
if (mins < 60) return `${mins}m ago`;
|
||||||
const hrs = Math.floor(mins / 60);
|
const hrs = Math.floor(mins / 60);
|
||||||
if (hrs < 24) return `${hrs}h ago`;
|
if (hrs < 24) return `${hrs}h ago`;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue