forked from Rockachopa/Timmy-time-dashboard
* chore: stop tracking runtime-generated self-modify reports These 65 files in data/self_modify_reports/ are auto-generated at runtime and already listed in .gitignore. Tracking them caused conflicts when pulling from main. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve 8 dashboard bugs from Round 4 testing report - Fix Ollama timeout regression: request_timeout → timeout (agno API) - Add Bootstrap JS to base.html (fixes creative UI tab switching) - Send initial_state on Swarm Live WebSocket connect - Add /api/queue/status endpoint (stops 404 log spam from chat panel) - Populate agent tools from registry on /tools page - Add notification bell dropdown with /api/notifications endpoint - All 1157 tests pass Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Trip T <trip@local> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
213 lines
10 KiB
HTML
213 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en" data-bs-theme="dark">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content" />
|
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
<meta name="theme-color" content="#080412" />
|
|
<title>{% block title %}Mission Control{% endblock %}</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
|
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet" />
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous" />
|
|
<link rel="stylesheet" href="/static/style.css?v=5" />
|
|
{% block extra_styles %}{% endblock %}
|
|
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.3/dist/htmx.min.js" crossorigin="anonymous"></script>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
var match = document.cookie.match(/csrf_token=([^;]+)/);
|
|
if (match) {
|
|
document.body.setAttribute('hx-headers', JSON.stringify({"X-CSRF-Token": match[1]}));
|
|
}
|
|
});
|
|
</script>
|
|
<script defer src="https://cdn.jsdelivr.net/npm/marked@15.0.7/marked.min.js"></script>
|
|
<script defer src="https://cdn.jsdelivr.net/npm/dompurify@3.2.4/dist/purify.min.js"></script>
|
|
</head>
|
|
<body>
|
|
<header class="mc-header">
|
|
<div class="mc-header-left">
|
|
<a href="/" class="mc-title">MISSION CONTROL</a>
|
|
<span class="mc-subtitle">MISSION CONTROL</span>
|
|
</div>
|
|
|
|
<!-- Desktop nav -->
|
|
<div class="mc-header-right mc-desktop-nav">
|
|
<a href="/calm" class="mc-test-link">CALM</a>
|
|
<a href="/tasks" class="mc-test-link">TASKS</a>
|
|
<a href="/briefing" class="mc-test-link">BRIEFING</a>
|
|
<a href="/thinking" class="mc-test-link mc-link-thinking">THINKING</a>
|
|
<a href="/swarm/mission-control" class="mc-test-link">MISSION CTRL</a>
|
|
<a href="/swarm/live" class="mc-test-link">SWARM</a>
|
|
<a href="/bugs" class="mc-test-link mc-link-bugs">BUGS</a>
|
|
<div class="mc-nav-dropdown">
|
|
<button class="mc-test-link mc-dropdown-toggle" aria-expanded="false">MORE ▾</button>
|
|
<div class="mc-dropdown-menu">
|
|
<a href="/spark/ui" class="mc-test-link">SPARK</a>
|
|
<a href="/marketplace/ui" class="mc-test-link">MARKET</a>
|
|
<a href="/tools" class="mc-test-link">TOOLS</a>
|
|
<a href="/swarm/events" class="mc-test-link">EVENTS</a>
|
|
<a href="/lightning/ledger" class="mc-test-link">LEDGER</a>
|
|
<a href="/memory" class="mc-test-link">MEMORY</a>
|
|
<a href="/router/status" class="mc-test-link">ROUTER</a>
|
|
<a href="/grok/status" class="mc-test-link mc-link-grok">GROK</a>
|
|
<a href="/self-modify/queue" class="mc-test-link">UPGRADES</a>
|
|
<a href="/self-coding" class="mc-test-link">SELF-CODING</a>
|
|
<a href="/hands" class="mc-test-link">HANDS</a>
|
|
<a href="/work-orders/queue" class="mc-test-link">WORK ORDERS</a>
|
|
<a href="/creative/ui" class="mc-test-link">CREATIVE</a>
|
|
<a href="/voice/button" class="mc-test-link">VOICE</a>
|
|
<a href="/mobile" class="mc-test-link" title="Mobile-optimized view">MOBILE</a>
|
|
<a href="/mobile/local" class="mc-test-link" title="Local AI on iPhone">LOCAL AI</a>
|
|
</div>
|
|
</div>
|
|
<div class="mc-nav-dropdown" id="notif-dropdown">
|
|
<button id="enable-notifications" class="mc-test-link mc-dropdown-toggle" style="background:none;cursor:pointer;position:relative;" title="Notifications" aria-expanded="false">🔔<span id="notif-badge" class="notif-badge" style="display:none;"></span></button>
|
|
<div class="mc-dropdown-menu" style="right:0;left:auto;min-width:280px;max-height:350px;overflow-y:auto;">
|
|
<div id="notif-list" style="padding:6px;">
|
|
<div style="color:var(--text-dim);font-size:0.8rem;text-align:center;padding:12px;">Loading...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<span class="mc-time" id="clock"></span>
|
|
</div>
|
|
|
|
<!-- Mobile hamburger -->
|
|
<button class="mc-hamburger" id="hamburger-btn" aria-label="Menu">
|
|
<span></span><span></span><span></span>
|
|
</button>
|
|
</header>
|
|
|
|
<!-- Mobile slide-out menu -->
|
|
<div class="mc-mobile-overlay" id="mobile-overlay"></div>
|
|
<nav class="mc-mobile-menu" id="mobile-menu">
|
|
<div class="mc-mobile-menu-header">
|
|
<span class="mc-mobile-menu-title">NAVIGATE</span>
|
|
<span class="mc-time" id="clock-mobile"></span>
|
|
</div>
|
|
<a href="/" class="mc-mobile-link">HOME</a>
|
|
<div class="mc-mobile-section-label">CORE</div>
|
|
<a href="/calm" class="mc-mobile-link">CALM</a>
|
|
<a href="/tasks" class="mc-mobile-link">TASKS</a>
|
|
<a href="/briefing" class="mc-mobile-link">BRIEFING</a>
|
|
<a href="/thinking" class="mc-mobile-link">THINKING</a>
|
|
<a href="/swarm/mission-control" class="mc-mobile-link">MISSION CONTROL</a>
|
|
<a href="/swarm/live" class="mc-mobile-link">SWARM</a>
|
|
<a href="/bugs" class="mc-mobile-link">BUGS</a>
|
|
<div class="mc-mobile-section-label">INTELLIGENCE</div>
|
|
<a href="/spark/ui" class="mc-mobile-link">SPARK</a>
|
|
<a href="/memory" class="mc-mobile-link">MEMORY</a>
|
|
<a href="/marketplace/ui" class="mc-mobile-link">MARKET</a>
|
|
<div class="mc-mobile-section-label">AGENTS</div>
|
|
<a href="/hands" class="mc-mobile-link">HANDS</a>
|
|
<a href="/work-orders/queue" class="mc-mobile-link">WORK ORDERS</a>
|
|
<a href="/self-modify/queue" class="mc-mobile-link">UPGRADES</a>
|
|
<a href="/self-coding" class="mc-mobile-link">SELF-CODING</a>
|
|
<div class="mc-mobile-section-label">SYSTEM</div>
|
|
<a href="/tools" class="mc-mobile-link">TOOLS</a>
|
|
<a href="/swarm/events" class="mc-mobile-link">EVENTS</a>
|
|
<a href="/router/status" class="mc-mobile-link">ROUTER</a>
|
|
<a href="/grok/status" class="mc-mobile-link">GROK</a>
|
|
<div class="mc-mobile-section-label">COMMERCE</div>
|
|
<a href="/lightning/ledger" class="mc-mobile-link">LEDGER</a>
|
|
<a href="/creative/ui" class="mc-mobile-link">CREATIVE</a>
|
|
<a href="/voice/button" class="mc-mobile-link">VOICE</a>
|
|
<a href="/mobile" class="mc-mobile-link">MOBILE</a>
|
|
<a href="/mobile/local" class="mc-mobile-link">LOCAL AI</a>
|
|
<div class="mc-mobile-menu-footer">
|
|
<button id="enable-notifications-mobile" class="mc-mobile-link" style="background:none;border:none;cursor:pointer;width:100%;text-align:left;font:inherit;color:inherit;padding:inherit;">🔔 NOTIFICATIONS</button>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="mc-main">
|
|
{% block content %}{% endblock %}
|
|
</main>
|
|
|
|
<script>
|
|
// Clock
|
|
function updateClock() {
|
|
const t = new Date().toLocaleTimeString('en-US', { hour12: false });
|
|
const el = document.getElementById('clock');
|
|
const el2 = document.getElementById('clock-mobile');
|
|
if (el) el.textContent = t;
|
|
if (el2) el2.textContent = t;
|
|
}
|
|
setInterval(updateClock, 1000);
|
|
updateClock();
|
|
|
|
// Mobile menu
|
|
const hamburger = document.getElementById('hamburger-btn');
|
|
const overlay = document.getElementById('mobile-overlay');
|
|
const menu = document.getElementById('mobile-menu');
|
|
function toggleMenu() {
|
|
const open = menu.classList.toggle('open');
|
|
overlay.classList.toggle('open', open);
|
|
hamburger.classList.toggle('open', open);
|
|
document.body.style.overflow = open ? 'hidden' : '';
|
|
}
|
|
hamburger.addEventListener('click', toggleMenu);
|
|
overlay.addEventListener('click', toggleMenu);
|
|
|
|
// Highlight current page in mobile menu
|
|
document.querySelectorAll('.mc-mobile-link').forEach(function(a) {
|
|
if (a.getAttribute('href') === window.location.pathname) {
|
|
a.classList.add('active');
|
|
}
|
|
});
|
|
|
|
// Desktop dropdown toggles (More menu + Notification bell)
|
|
document.querySelectorAll('.mc-dropdown-toggle').forEach(function(toggle) {
|
|
toggle.addEventListener('click', function(e) {
|
|
e.stopPropagation();
|
|
var dd = this.closest('.mc-nav-dropdown');
|
|
// Close other dropdowns first
|
|
document.querySelectorAll('.mc-nav-dropdown.open').forEach(function(other) {
|
|
if (other !== dd) {
|
|
other.classList.remove('open');
|
|
var btn = other.querySelector('.mc-dropdown-toggle');
|
|
if (btn) btn.setAttribute('aria-expanded', 'false');
|
|
}
|
|
});
|
|
var isOpen = dd.classList.toggle('open');
|
|
this.setAttribute('aria-expanded', isOpen);
|
|
// Load notifications when opening the bell
|
|
if (isOpen && dd.id === 'notif-dropdown') { loadNotifications(); }
|
|
});
|
|
});
|
|
document.addEventListener('click', function() {
|
|
document.querySelectorAll('.mc-nav-dropdown.open').forEach(function(dd) {
|
|
dd.classList.remove('open');
|
|
var btn = dd.querySelector('.mc-dropdown-toggle');
|
|
if (btn) btn.setAttribute('aria-expanded', 'false');
|
|
});
|
|
});
|
|
|
|
// Notification loader
|
|
function loadNotifications() {
|
|
fetch('/api/notifications')
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
var list = document.getElementById('notif-list');
|
|
if (!data.length) {
|
|
list.innerHTML = '<div style="color:var(--text-dim);font-size:0.8rem;text-align:center;padding:12px;">No recent notifications</div>';
|
|
return;
|
|
}
|
|
list.innerHTML = data.map(function(n) {
|
|
return '<div style="padding:6px 8px;border-bottom:1px solid var(--border);font-size:0.8rem;">'
|
|
+ '<div style="color:var(--text-bright);">' + (n.title || n.event_type || 'Event') + '</div>'
|
|
+ '<div style="color:var(--text-dim);font-size:0.7rem;">' + (n.timestamp || '') + '</div>'
|
|
+ '</div>';
|
|
}).join('');
|
|
var badge = document.getElementById('notif-badge');
|
|
if (badge) { badge.style.display = 'none'; }
|
|
})
|
|
.catch(function() {});
|
|
}
|
|
</script>
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
|
<script src="/static/notifications.js"></script>
|
|
</body>
|
|
</html>
|