show currrently running activity in logbook
This commit is contained in:
@@ -21,7 +21,8 @@
|
||||
{% for entry in log %}
|
||||
<!-- Wrapped whole card in a link to the detail view -->
|
||||
<a href="{{ url_for('log_entry_detail', entry_id=entry._id) }}" class="log-entry-item" style="text-decoration: none; color: inherit; display: block;">
|
||||
<div class="card" style="border-left: 5px solid {{ entry.activity.color }}; transition: transform 0.1s;">
|
||||
<!-- Highlight running entries with a different border style or shadow -->
|
||||
<div class="card" style="border-left: 5px solid {{ entry.activity.color }}; transition: transform 0.1s; {% if entry.is_running %}background: #fffdf8; border: 1px solid #ffd700; border-left-width: 5px;{% endif %}">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div>
|
||||
<h3 style="margin: 0;" class="entry-title">
|
||||
@@ -31,9 +32,19 @@
|
||||
{{ entry.subcategory }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if entry.is_running %}
|
||||
<span style="font-size: 0.7rem; background: #27ae60; color: white; padding: 2px 6px; border-radius: 4px; vertical-align: middle; margin-left: 5px; text-transform: uppercase; letter-spacing: 0.5px;">
|
||||
Running
|
||||
</span>
|
||||
{% endif %}
|
||||
</h3>
|
||||
<small style="color: #666;">
|
||||
{{ entry.start_time.strftime('%Y-%m-%d %H:%M') }} - {{ entry.end_time.strftime('%H:%M') }}
|
||||
{{ entry.start_time.strftime('%Y-%m-%d %H:%M') }} -
|
||||
{% if entry.is_running %}
|
||||
<span style="color: #27ae60; font-weight: bold;">Now</span>
|
||||
{% else %}
|
||||
{{ entry.end_time.strftime('%H:%M') }}
|
||||
{% endif %}
|
||||
</small>
|
||||
{% if entry.note %}
|
||||
<p class="entry-note" style="margin: 5px 0; font-style: italic; color: #555;">"{{ entry.note }}"</p>
|
||||
@@ -41,8 +52,14 @@
|
||||
<span class="entry-note" style="display:none;"></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div style="font-weight: bold; font-size: 1.2rem;">
|
||||
{{ entry.duration_str }}
|
||||
<div style="font-weight: bold; font-size: 1.2rem; text-align: right;">
|
||||
<!-- Live ticking class and data attribute -->
|
||||
<span class="{% if entry.is_running %}live-timer{% endif %}" {% if entry.is_running %}data-start="{{ entry.start_time.timestamp() * 1000 }}"{% endif %}>
|
||||
{{ entry.duration_str }}
|
||||
</span>
|
||||
{% if entry.is_running %}
|
||||
<div style="font-size: 0.7rem; color: #27ae60; animation: pulse 2s infinite;">● Live</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -94,7 +111,67 @@
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<style>
|
||||
@keyframes pulse {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
// Live Timer Update
|
||||
setInterval(() => {
|
||||
document.querySelectorAll('.live-timer').forEach(el => {
|
||||
const start = parseInt(el.getAttribute('data-start'));
|
||||
if (!start) return;
|
||||
|
||||
const diff = Date.now() - start;
|
||||
if (diff < 0) return;
|
||||
|
||||
const hours = Math.floor(diff / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
|
||||
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
|
||||
|
||||
el.textContent =
|
||||
(hours < 10 ? "0" + hours : hours) + ":" +
|
||||
(minutes < 10 ? "0" + minutes : minutes) + ":" +
|
||||
(seconds < 10 ? "0" + seconds : seconds);
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
// Background Sync (Polls for new tasks or status changes)
|
||||
let lastContentHash = "";
|
||||
setInterval(() => {
|
||||
if (document.hidden) return;
|
||||
|
||||
// Fetch current page in background to check for updates
|
||||
fetch(window.location.href)
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, 'text/html');
|
||||
const newContainer = doc.getElementById('logbook-container');
|
||||
const oldContainer = document.getElementById('logbook-container');
|
||||
|
||||
if (newContainer && oldContainer) {
|
||||
const newContent = newContainer.innerHTML;
|
||||
const oldContent = oldContainer.innerHTML;
|
||||
|
||||
// Simple string comparison. If different, replace.
|
||||
// Note: This replaces the list if *anything* changed (time update server side, new task, stop timer)
|
||||
if (newContent !== lastContentHash && lastContentHash !== "") {
|
||||
// Only update DOM if logic changed, ignoring simple server side time drift (handled by JS above)
|
||||
// But since server renders static time in loop, it will always differ slightly.
|
||||
// However, we want to sync Structure (new tasks, status).
|
||||
// Let's replace. The user wants "live sync".
|
||||
oldContainer.innerHTML = newContent;
|
||||
}
|
||||
lastContentHash = newContent;
|
||||
}
|
||||
})
|
||||
.catch(e => console.error("Logbook background sync failed", e));
|
||||
}, 4000); // Check every 4 seconds
|
||||
|
||||
// Search Functionality
|
||||
function filterLog() {
|
||||
const input = document.getElementById('logSearchInput');
|
||||
|
||||
Reference in New Issue
Block a user