diff options
| author | Stefan Boberg <[email protected]> | 2026-03-09 17:43:08 +0100 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2026-03-09 17:43:08 +0100 |
| commit | b37b34ea6ad906f54e8104526e77ba66aed997da (patch) | |
| tree | e80ce17d666aff6d2f0d73d4977128ffb4055476 /src/zenserver/frontend/html/compute/compute.html | |
| parent | add fallback for zencache multirange (#816) (diff) | |
| download | zen-b37b34ea6ad906f54e8104526e77ba66aed997da.tar.xz zen-b37b34ea6ad906f54e8104526e77ba66aed997da.zip | |
Dashboard overhaul, compute integration (#814)
- **Frontend dashboard overhaul**: Unified compute/main dashboards into a single shared UI. Added new pages for cache, projects, metrics, sessions, info (build/runtime config, system stats). Added live-update via WebSockets with pause control, sortable detail tables, themed styling. Refactored compute/hub/orchestrator pages into modular JS.
- **HTTP server fixes and stats**: Fixed http.sys local-only fallback when default port is in use, implemented root endpoint redirect for http.sys, fixed Linux/Mac port reuse. Added /stats endpoint exposing HTTP server metrics (bytes transferred, request rates). Added WebSocket stats tracking.
- **OTEL/diagnostics hardening**: Improved OTLP HTTP exporter with better error handling and resilience. Extended diagnostics services configuration.
- **Session management**: Added new sessions service with HTTP endpoints for registering, updating, querying, and removing sessions. Includes session log file support. This is still WIP.
- **CLI subcommand support**: Added support for commands with subcommands in the zen CLI tool, with improved command dispatch.
- **Misc**: Exposed CPU usage/hostname to frontend, fixed JS compact binary float32/float64 decoding, limited projects displayed on front page to 25 sorted by last access, added vscode:// link support.
Also contains some fixes from TSAN analysis.
Diffstat (limited to 'src/zenserver/frontend/html/compute/compute.html')
| -rw-r--r-- | src/zenserver/frontend/html/compute/compute.html | 327 |
1 files changed, 92 insertions, 235 deletions
diff --git a/src/zenserver/frontend/html/compute/compute.html b/src/zenserver/frontend/html/compute/compute.html index 1e101d839..66c20175f 100644 --- a/src/zenserver/frontend/html/compute/compute.html +++ b/src/zenserver/frontend/html/compute/compute.html @@ -5,101 +5,13 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Zen Compute Dashboard</title> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script> - <script src="banner.js" defer></script> - <script src="nav.js" defer></script> + <link rel="stylesheet" type="text/css" href="../zen.css" /> + <script src="../theme.js"></script> + <script src="../banner.js" defer></script> + <script src="../nav.js" defer></script> <style> - * { - margin: 0; - padding: 0; - box-sizing: border-box; - } - - body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; - background: #0d1117; - color: #c9d1d9; - padding: 20px; - } - - .container { - max-width: 1400px; - margin: 0 auto; - } - - h1 { - font-size: 32px; - font-weight: 600; - margin-bottom: 10px; - color: #f0f6fc; - } - - .header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 30px; - } - - .health-indicator { - display: flex; - align-items: center; - gap: 8px; - font-size: 14px; - padding: 8px 16px; - border-radius: 6px; - background: #161b22; - border: 1px solid #30363d; - } - - .health-indicator .status-dot { - width: 10px; - height: 10px; - border-radius: 50%; - background: #6e7681; - } - - .health-indicator.healthy .status-dot { - background: #3fb950; - } - - .health-indicator.unhealthy .status-dot { - background: #f85149; - } - .grid { - display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); - gap: 20px; - margin-bottom: 30px; - } - - .card { - background: #161b22; - border: 1px solid #30363d; - border-radius: 6px; - padding: 20px; - } - - .card-title { - font-size: 14px; - font-weight: 600; - color: #8b949e; - margin-bottom: 12px; - text-transform: uppercase; - letter-spacing: 0.5px; - } - - .metric-value { - font-size: 36px; - font-weight: 600; - color: #f0f6fc; - line-height: 1; - } - - .metric-label { - font-size: 12px; - color: #8b949e; - margin-top: 4px; } .chart-container { @@ -113,7 +25,7 @@ justify-content: space-between; margin-bottom: 12px; padding: 8px 0; - border-bottom: 1px solid #21262d; + border-bottom: 1px solid var(--theme_border_subtle); } .stats-row:last-child { @@ -122,12 +34,12 @@ } .stats-label { - color: #8b949e; + color: var(--theme_g1); font-size: 13px; } .stats-value { - color: #f0f6fc; + color: var(--theme_bright); font-weight: 600; font-size: 13px; } @@ -146,77 +58,39 @@ .rate-value { font-size: 20px; font-weight: 600; - color: #58a6ff; + color: var(--theme_p0); } .rate-label { font-size: 11px; - color: #8b949e; + color: var(--theme_g1); margin-top: 4px; text-transform: uppercase; } - .progress-bar { - width: 100%; - height: 8px; - background: #21262d; - border-radius: 4px; - overflow: hidden; - margin-top: 8px; - } - - .progress-fill { - height: 100%; - background: #58a6ff; - transition: width 0.3s ease; - } - - .timestamp { - font-size: 12px; - color: #6e7681; - text-align: right; - margin-top: 30px; - } - - .error { - color: #f85149; - padding: 12px; - background: #1c1c1c; - border-radius: 6px; - margin: 20px 0; - font-size: 13px; - } - - .section-title { - font-size: 20px; - font-weight: 600; - margin-bottom: 20px; - color: #f0f6fc; - } - .worker-row { cursor: pointer; transition: background 0.15s; } .worker-row:hover { - background: #1c2128; + background: var(--theme_p4); } .worker-row.selected { - background: #1f2d3d; + background: var(--theme_p3); } .worker-detail { margin-top: 20px; - border-top: 1px solid #30363d; + border-top: 1px solid var(--theme_g2); padding-top: 16px; } .worker-detail-title { font-size: 15px; font-weight: 600; - color: #f0f6fc; + color: var(--theme_bright); margin-bottom: 12px; } @@ -227,7 +101,7 @@ .detail-section-label { font-size: 11px; font-weight: 600; - color: #8b949e; + color: var(--theme_g1); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px; @@ -241,13 +115,13 @@ .detail-table td { padding: 4px 8px; - color: #c9d1d9; - border-bottom: 1px solid #21262d; + color: var(--theme_g0); + border-bottom: 1px solid var(--theme_border_subtle); vertical-align: top; } .detail-table td:first-child { - color: #8b949e; + color: var(--theme_g1); width: 40%; font-family: monospace; } @@ -259,42 +133,25 @@ .detail-mono { font-family: monospace; font-size: 11px; - color: #8b949e; + color: var(--theme_g1); } .detail-tag { display: inline-block; padding: 2px 8px; border-radius: 4px; - background: #21262d; - color: #c9d1d9; + background: var(--theme_border_subtle); + color: var(--theme_g0); font-size: 11px; margin: 2px 4px 2px 0; } - - .status-badge { - display: inline-block; - padding: 2px 8px; - border-radius: 4px; - font-size: 11px; - font-weight: 600; - } - - .status-badge.success { - background: rgba(63, 185, 80, 0.15); - color: #3fb950; - } - - .status-badge.failure { - background: rgba(248, 81, 73, 0.15); - color: #f85149; - } </style> </head> <body> - <div class="container"> - <zen-banner cluster-status="nominal" load="0" tagline="Node Overview"></zen-banner> + <div class="container" style="max-width: 1400px; margin: 0 auto;"> + <zen-banner cluster-status="nominal" load="0" tagline="Node Overview" logo-src="../favicon.ico"></zen-banner> <zen-nav> + <a href="/dashboard/">Home</a> <a href="compute.html">Node</a> <a href="orchestrator.html">Orchestrator</a> </zen-nav> @@ -369,15 +226,15 @@ <span class="stats-value" id="worker-count">-</span> </div> <div id="worker-table-container" style="margin-top: 16px; display: none;"> - <table id="worker-table" style="width: 100%; border-collapse: collapse; font-size: 13px;"> + <table id="worker-table"> <thead> <tr> - <th style="text-align: left; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Name</th> - <th style="text-align: left; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Platform</th> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Cores</th> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Timeout</th> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Functions</th> - <th style="text-align: left; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Worker ID</th> + <th>Name</th> + <th>Platform</th> + <th style="text-align: right;">Cores</th> + <th style="text-align: right;">Timeout</th> + <th style="text-align: right;">Functions</th> + <th>Worker ID</th> </tr> </thead> <tbody id="worker-table-body"></tbody> @@ -390,19 +247,19 @@ <div class="section-title">Queues</div> <div class="card" style="margin-bottom: 30px;"> <div class="card-title">Queue Status</div> - <div id="queue-list-empty" style="color: #6e7681; font-size: 13px;">No queues.</div> + <div id="queue-list-empty" class="empty-state" style="text-align: left;">No queues.</div> <div id="queue-list-container" style="display: none;"> - <table id="queue-list-table" style="width: 100%; border-collapse: collapse; font-size: 13px;"> + <table id="queue-list-table"> <thead> <tr> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px; width: 60px;">ID</th> - <th style="text-align: center; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px; width: 80px;">Status</th> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Active</th> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Completed</th> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Failed</th> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Abandoned</th> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Cancelled</th> - <th style="text-align: left; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Token</th> + <th style="text-align: right; width: 60px;">ID</th> + <th style="text-align: center; width: 80px;">Status</th> + <th style="text-align: right;">Active</th> + <th style="text-align: right;">Completed</th> + <th style="text-align: right;">Failed</th> + <th style="text-align: right;">Abandoned</th> + <th style="text-align: right;">Cancelled</th> + <th>Token</th> </tr> </thead> <tbody id="queue-list-body"></tbody> @@ -414,20 +271,20 @@ <div class="section-title">Recent Actions</div> <div class="card" style="margin-bottom: 30px;"> <div class="card-title">Action History</div> - <div id="action-history-empty" style="color: #6e7681; font-size: 13px;">No actions recorded yet.</div> + <div id="action-history-empty" class="empty-state" style="text-align: left;">No actions recorded yet.</div> <div id="action-history-container" style="display: none;"> - <table id="action-history-table" style="width: 100%; border-collapse: collapse; font-size: 13px;"> + <table id="action-history-table"> <thead> <tr> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px; width: 60px;">LSN</th> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px; width: 60px;">Queue</th> - <th style="text-align: center; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px; width: 70px;">Status</th> - <th style="text-align: left; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Function</th> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px; width: 80px;">Started</th> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px; width: 80px;">Finished</th> - <th style="text-align: right; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px; width: 80px;">Duration</th> - <th style="text-align: left; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Worker ID</th> - <th style="text-align: left; color: #8b949e; padding: 6px 8px; border-bottom: 1px solid #30363d; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; font-size: 11px;">Action ID</th> + <th style="text-align: right; width: 60px;">LSN</th> + <th style="text-align: right; width: 60px;">Queue</th> + <th style="text-align: center; width: 70px;">Status</th> + <th>Function</th> + <th style="text-align: right; width: 80px;">Started</th> + <th style="text-align: right; width: 80px;">Finished</th> + <th style="text-align: right; width: 80px;">Duration</th> + <th>Worker ID</th> + <th>Action ID</th> </tr> </thead> <tbody id="action-history-body"></tbody> @@ -766,7 +623,7 @@ // Functions const functions = desc.functions || []; - const functionsHtml = functions.length === 0 ? '<span style="color:#6e7681;font-size:12px;">none</span>' : + const functionsHtml = functions.length === 0 ? '<span style="color:var(--theme_faint);font-size:12px;">none</span>' : `<table class="detail-table">${functions.map(f => `<tr><td>${escapeHtml(f.name || '-')}</td><td class="detail-mono">${escapeHtml(f.version || '-')}</td></tr>` ).join('')}</table>`; @@ -774,12 +631,12 @@ // Executables const executables = desc.executables || []; const totalExecSize = executables.reduce((sum, e) => sum + (e.size || 0), 0); - const execHtml = executables.length === 0 ? '<span style="color:#6e7681;font-size:12px;">none</span>' : + const execHtml = executables.length === 0 ? '<span style="color:var(--theme_faint);font-size:12px;">none</span>' : `<table class="detail-table"> <tr style="font-size:11px;"> - <td style="color:#6e7681;padding-bottom:4px;">Path</td> - <td style="color:#6e7681;padding-bottom:4px;">Hash</td> - <td style="color:#6e7681;padding-bottom:4px;text-align:right;">Size</td> + <td style="color:var(--theme_faint);padding-bottom:4px;">Path</td> + <td style="color:var(--theme_faint);padding-bottom:4px;">Hash</td> + <td style="color:var(--theme_faint);padding-bottom:4px;text-align:right;">Size</td> </tr> ${executables.map(e => `<tr> @@ -788,28 +645,28 @@ <td style="text-align:right;white-space:nowrap;">${e.size != null ? formatBytes(e.size) : '-'}</td> </tr>` ).join('')} - <tr style="border-top:1px solid #30363d;"> - <td style="color:#8b949e;padding-top:6px;">Total</td> + <tr style="border-top:1px solid var(--theme_g2);"> + <td style="color:var(--theme_g1);padding-top:6px;">Total</td> <td></td> - <td style="text-align:right;white-space:nowrap;padding-top:6px;color:#f0f6fc;font-weight:600;">${formatBytes(totalExecSize)}</td> + <td style="text-align:right;white-space:nowrap;padding-top:6px;color:var(--theme_bright);font-weight:600;">${formatBytes(totalExecSize)}</td> </tr> </table>`; // Files const files = desc.files || []; - const filesHtml = files.length === 0 ? '<span style="color:#6e7681;font-size:12px;">none</span>' : + const filesHtml = files.length === 0 ? '<span style="color:var(--theme_faint);font-size:12px;">none</span>' : `<table class="detail-table">${files.map(f => `<tr><td>${escapeHtml(f.name || f)}</td><td class="detail-mono">${escapeHtml(f.hash || '')}</td></tr>` ).join('')}</table>`; // Dirs const dirs = desc.dirs || []; - const dirsHtml = dirs.length === 0 ? '<span style="color:#6e7681;font-size:12px;">none</span>' : + const dirsHtml = dirs.length === 0 ? '<span style="color:var(--theme_faint);font-size:12px;">none</span>' : dirs.map(d => `<span class="detail-tag">${escapeHtml(d)}</span>`).join(''); // Environment const env = desc.environment || []; - const envHtml = env.length === 0 ? '<span style="color:#6e7681;font-size:12px;">none</span>' : + const envHtml = env.length === 0 ? '<span style="color:var(--theme_faint);font-size:12px;">none</span>' : env.map(e => `<span class="detail-tag">${escapeHtml(e)}</span>`).join(''); panel.innerHTML = ` @@ -880,16 +737,16 @@ const timeout = desc ? (desc.timeout != null ? desc.timeout + 's' : '-') : '-'; const functions = desc ? (desc.functions ? desc.functions.length : 0) : '-'; - const tr = document.createElement('tr'); + const tr = document.createElement('tr'); tr.className = 'worker-row' + (id === selectedWorkerId ? ' selected' : ''); tr.dataset.workerId = id; tr.innerHTML = ` - <td style="padding: 6px 8px; color: #f0f6fc; border-bottom: 1px solid #21262d;">${escapeHtml(name)}</td> - <td style="padding: 6px 8px; color: #c9d1d9; border-bottom: 1px solid #21262d;">${escapeHtml(host)}</td> - <td style="padding: 6px 8px; color: #c9d1d9; border-bottom: 1px solid #21262d; text-align: right;">${escapeHtml(String(cores))}</td> - <td style="padding: 6px 8px; color: #c9d1d9; border-bottom: 1px solid #21262d; text-align: right;">${escapeHtml(String(timeout))}</td> - <td style="padding: 6px 8px; color: #c9d1d9; border-bottom: 1px solid #21262d; text-align: right;">${escapeHtml(String(functions))}</td> - <td style="padding: 6px 8px; color: #8b949e; border-bottom: 1px solid #21262d; font-family: monospace; font-size: 11px;">${escapeHtml(id)}</td> + <td style="color: var(--theme_bright);">${escapeHtml(name)}</td> + <td>${escapeHtml(host)}</td> + <td style="text-align: right;">${escapeHtml(String(cores))}</td> + <td style="text-align: right;">${escapeHtml(String(timeout))}</td> + <td style="text-align: right;">${escapeHtml(String(functions))}</td> + <td style="color: var(--theme_g1); font-family: monospace; font-size: 11px;">${escapeHtml(id)}</td> `; tr.addEventListener('click', () => { document.querySelectorAll('.worker-row').forEach(r => r.classList.remove('selected')); @@ -963,24 +820,24 @@ const badge = q.state === 'cancelled' ? '<span class="status-badge failure">cancelled</span>' : q.state === 'draining' - ? '<span class="status-badge" style="background:rgba(210,153,34,0.15);color:#d29922;">draining</span>' + ? '<span class="status-badge" style="background:color-mix(in srgb, var(--theme_warn) 15%, transparent);color:var(--theme_warn);">draining</span>' : q.is_complete ? '<span class="status-badge success">complete</span>' - : '<span class="status-badge" style="background:rgba(88,166,255,0.15);color:#58a6ff;">active</span>'; + : '<span class="status-badge" style="background:color-mix(in srgb, var(--theme_p0) 15%, transparent);color:var(--theme_p0);">active</span>'; const token = q.queue_token ? `<span class="detail-mono">${escapeHtml(q.queue_token)}</span>` - : '<span style="color:#6e7681;">-</span>'; + : '<span style="color:var(--theme_faint);">-</span>'; const tr = document.createElement('tr'); tr.innerHTML = ` - <td style="padding: 6px 8px; color: #f0f6fc; border-bottom: 1px solid #21262d; text-align: right; font-family: monospace;">${escapeHtml(String(id))}</td> - <td style="padding: 6px 8px; border-bottom: 1px solid #21262d; text-align: center;">${badge}</td> - <td style="padding: 6px 8px; color: #c9d1d9; border-bottom: 1px solid #21262d; text-align: right;">${q.active_count ?? 0}</td> - <td style="padding: 6px 8px; color: #3fb950; border-bottom: 1px solid #21262d; text-align: right;">${q.completed_count ?? 0}</td> - <td style="padding: 6px 8px; color: #f85149; border-bottom: 1px solid #21262d; text-align: right;">${q.failed_count ?? 0}</td> - <td style="padding: 6px 8px; color: #d29922; border-bottom: 1px solid #21262d; text-align: right;">${q.abandoned_count ?? 0}</td> - <td style="padding: 6px 8px; color: #f0883e; border-bottom: 1px solid #21262d; text-align: right;">${q.cancelled_count ?? 0}</td> - <td style="padding: 6px 8px; border-bottom: 1px solid #21262d;">${token}</td> + <td style="text-align: right; font-family: monospace; color: var(--theme_bright);">${escapeHtml(String(id))}</td> + <td style="text-align: center;">${badge}</td> + <td style="text-align: right;">${q.active_count ?? 0}</td> + <td style="text-align: right; color: var(--theme_ok);">${q.completed_count ?? 0}</td> + <td style="text-align: right; color: var(--theme_fail);">${q.failed_count ?? 0}</td> + <td style="text-align: right; color: var(--theme_warn);">${q.abandoned_count ?? 0}</td> + <td style="text-align: right; color: var(--theme_warn);">${q.cancelled_count ?? 0}</td> + <td>${token}</td> `; tbody.appendChild(tr); } @@ -1010,7 +867,7 @@ const lsn = entry.lsn ?? '-'; const succeeded = entry.succeeded; const badge = succeeded == null - ? '<span class="status-badge" style="background:#21262d;color:#8b949e;">unknown</span>' + ? '<span class="status-badge" style="background:var(--theme_border_subtle);color:var(--theme_g1);">unknown</span>' : succeeded ? '<span class="status-badge success">ok</span>' : '<span class="status-badge failure">failed</span>'; @@ -1024,20 +881,20 @@ const queueId = entry.queueId || 0; const queueCell = queueId - ? `<a href="/compute/queues/${queueId}" style="color: #58a6ff; text-decoration: none; font-family: monospace;">${escapeHtml(String(queueId))}</a>` - : '<span style="color: #6e7681;">-</span>'; + ? `<a href="/compute/queues/${queueId}" style="color: var(--theme_ln); text-decoration: none; font-family: monospace;">${escapeHtml(String(queueId))}</a>` + : '<span style="color: var(--theme_faint);">-</span>'; const tr = document.createElement('tr'); tr.innerHTML = ` - <td style="padding: 6px 8px; color: #8b949e; border-bottom: 1px solid #21262d; text-align: right; font-family: monospace;">${escapeHtml(String(lsn))}</td> - <td style="padding: 6px 8px; border-bottom: 1px solid #21262d; text-align: right;">${queueCell}</td> - <td style="padding: 6px 8px; border-bottom: 1px solid #21262d; text-align: center;">${badge}</td> - <td style="padding: 6px 8px; color: #f0f6fc; border-bottom: 1px solid #21262d;">${escapeHtml(fn)}</td> - <td style="padding: 6px 8px; color: #8b949e; border-bottom: 1px solid #21262d; text-align: right; font-size: 12px; white-space: nowrap;">${formatTime(startDate)}</td> - <td style="padding: 6px 8px; color: #8b949e; border-bottom: 1px solid #21262d; text-align: right; font-size: 12px; white-space: nowrap;">${formatTime(endDate)}</td> - <td style="padding: 6px 8px; color: #c9d1d9; border-bottom: 1px solid #21262d; text-align: right; font-size: 12px; white-space: nowrap;">${formatDuration(startDate, endDate)}</td> - <td style="padding: 6px 8px; color: #8b949e; border-bottom: 1px solid #21262d; font-family: monospace; font-size: 11px;">${escapeHtml(workerId)}</td> - <td style="padding: 6px 8px; color: #8b949e; border-bottom: 1px solid #21262d; font-family: monospace; font-size: 11px;">${escapeHtml(actionId)}</td> + <td style="text-align: right; font-family: monospace; color: var(--theme_g1);">${escapeHtml(String(lsn))}</td> + <td style="text-align: right;">${queueCell}</td> + <td style="text-align: center;">${badge}</td> + <td style="color: var(--theme_bright);">${escapeHtml(fn)}</td> + <td style="text-align: right; font-size: 12px; white-space: nowrap; color: var(--theme_g1);">${formatTime(startDate)}</td> + <td style="text-align: right; font-size: 12px; white-space: nowrap; color: var(--theme_g1);">${formatTime(endDate)}</td> + <td style="text-align: right; font-size: 12px; white-space: nowrap;">${formatDuration(startDate, endDate)}</td> + <td style="font-family: monospace; font-size: 11px; color: var(--theme_g1);">${escapeHtml(workerId)}</td> + <td style="font-family: monospace; font-size: 11px; color: var(--theme_g1);">${escapeHtml(actionId)}</td> `; tbody.appendChild(tr); } |