diff --git a/server/build.rs b/server/build.rs
index af36bd4..848267e 100644
--- a/server/build.rs
+++ b/server/build.rs
@@ -1,25 +1,29 @@
use std::process::Command;
fn main() {
- let git_hash = Command::new("git")
+ let mut git_hash = Command::new("git")
.args(["rev-parse", "--short", "HEAD"])
.output()
.ok()
.and_then(|out| String::from_utf8(out.stdout).ok())
.unwrap_or_else(|| "unknown".to_string());
+
+ git_hash = git_hash.trim().to_string();
- let git_date = Command::new("git")
- .args(["log", "-1", "--format=%cd", "--date=format:%y.%m.%d.%H%M%S"])
+ let is_dirty = Command::new("git")
+ .args(["status", "--porcelain"])
.output()
.ok()
- .and_then(|out| String::from_utf8(out.stdout).ok())
- .unwrap_or_else(|| "unknown".to_string());
+ .map(|out| !out.stdout.is_empty())
+ .unwrap_or(false);
- let version = format!(
- "{} ({})",
- git_date.trim(),
- git_hash.trim()
- );
+ if is_dirty {
+ git_hash.push_str("-dirty");
+ }
+
+ let build_date = chrono::Local::now().format("%y.%m.%d.%H%M%S").to_string();
+
+ let version = format!("{} ({})", build_date, git_hash);
println!("cargo:rustc-env=APP_VERSION={}", version);
if std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default() == "windows" {
diff --git a/server/src/dashboard.html b/server/src/dashboard.html
index 2dc8deb..41585f3 100644
--- a/server/src/dashboard.html
+++ b/server/src/dashboard.html
@@ -893,6 +893,33 @@
}
// --- WebSocket Activity Feed ---
+ const MAX_ACTIVITY_HISTORY = 100;
+
+ function saveActivityHistory(time, htmlData) {
+ try {
+ let history = JSON.parse(localStorage.getItem('activityHistory') || '[]');
+ history.push({ time, data: htmlData });
+ if (history.length > MAX_ACTIVITY_HISTORY) history = history.slice(-MAX_ACTIVITY_HISTORY);
+ localStorage.setItem('activityHistory', JSON.stringify(history));
+ } catch(e) {}
+ }
+
+ function loadActivityHistory() {
+ try {
+ const feed = document.getElementById('activity-feed');
+ let history = JSON.parse(localStorage.getItem('activityHistory') || '[]');
+ history.forEach(item => {
+ const div = document.createElement('div');
+ div.className = 'feed-entry';
+ div.innerHTML = `[${item.time}] ${item.data}`;
+ feed.appendChild(div);
+ });
+ if (history.length > 0) {
+ feed.scrollTop = feed.scrollHeight;
+ }
+ } catch(e) {}
+ }
+
function setupWS() {
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const ws = new WebSocket(`${protocol}//${location.host}/ws?client=ui`);
@@ -908,6 +935,8 @@
div.innerHTML = `[${time}] ${data.data}`;
feed.appendChild(div);
+ saveActivityHistory(time, data.data);
+
// Auto-scroll logic
const isScrolledToBottom = feed.scrollHeight - feed.clientHeight <= feed.scrollTop + 20;
if (isScrolledToBottom) {
@@ -967,6 +996,7 @@
loadGraph();
loadTasks();
loadStickyNotes();
+ loadActivityHistory();
setupWS();
// Listen to theme toggle changes to update graph font colors