Skip to content

Commit

Permalink
feat: show worker execution in the web status display
Browse files Browse the repository at this point in the history
  • Loading branch information
provos committed Dec 15, 2024
1 parent 028afb9 commit ed734d8
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/planai/static/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import { setupEventSource } from './core.js';
import { initTaskListeners } from './tasks.js';
import { initTraceListeners } from './trace.js';
import { initWorkerStatsListeners } from './workers.js';
import { initStatusListeners } from './status.js';
import { initTheme } from './theme.js';
import { initTabs } from './utils.js';

setupEventSource();
initTaskListeners();
initTraceListeners();
initWorkerStatsListeners();
initStatusListeners();
initTheme();
initTabs();

// Quit button functionality
document.getElementById('quit-button').addEventListener('click', function () {
Expand Down
57 changes: 57 additions & 0 deletions src/planai/static/js/status.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
export function initStatusListeners() {
window.addEventListener('statsUpdated', (e) => updateStatus(e.detail));
}

function createStatusBar(count, type) {
const bar = document.createElement('div');
bar.className = `status-${type}`;
bar.style.display = 'flex';
for (let i = 0; i < count; i++) {
const square = document.createElement('div');
square.className = `status-square ${type}`;
bar.appendChild(square);
}
return bar;
}

function updateStatus(workerStats) {
const container = document.getElementById('worker-status');
container.innerHTML = ''; // Clear previous state

const maxWidth = 50; // Maximum number of squares to show

Object.entries(workerStats).forEach(([worker, stats]) => {
const row = document.createElement('div');
row.className = 'worker-row';

// Worker name
const name = document.createElement('div');
name.className = 'worker-name';
name.textContent = worker;
row.appendChild(name);

// Status bars container
const bars = document.createElement('div');
bars.className = 'status-bars';

// Calculate scaling
const total = stats.completed + stats.active + stats.queued + stats.failed;
const scale = total > maxWidth ? maxWidth / total : 1;

// Add status bars
if (stats.completed > 0) bars.appendChild(createStatusBar(Math.max(1, Math.floor(stats.completed * scale)), 'completed'));
if (stats.active > 0) bars.appendChild(createStatusBar(Math.max(1, Math.floor(stats.active * scale)), 'active'));
if (stats.queued > 0) bars.appendChild(createStatusBar(Math.max(1, Math.floor(stats.queued * scale)), 'queued'));
if (stats.failed > 0) bars.appendChild(createStatusBar(Math.max(1, Math.floor(stats.failed * scale)), 'failed'));

row.appendChild(bars);

// Statistics
const stats_div = document.createElement('div');
stats_div.className = 'worker-stats';
stats_div.textContent = `C:${stats.completed} A:${stats.active} Q:${stats.queued} F:${stats.failed}`;
row.appendChild(stats_div);

container.appendChild(row);
});
}
21 changes: 21 additions & 0 deletions src/planai/static/js/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,24 @@ export function renderObject(obj, indent = '') {
}).join('<br>');
}

export function initTabs() {
const tabs = document.querySelectorAll('.tab-button');
const contents = document.querySelectorAll('.tab-content');

// Show first tab by default
tabs[0]?.classList.add('active');
contents[0]?.classList.add('active');

tabs.forEach(tab => {
tab.addEventListener('click', () => {
// Remove active class from all tabs and contents
tabs.forEach(t => t.classList.remove('active'));
contents.forEach(c => c.classList.remove('active'));

// Add active class to clicked tab and corresponding content
tab.classList.add('active');
const content = document.querySelector(tab.dataset.target);
content?.classList.add('active');
});
});
}
108 changes: 108 additions & 0 deletions src/planai/static/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -331,4 +331,112 @@ a:visited {

[data-theme="dark"] .abort-button:hover {
background-color: #992626;
}

/* Worker execution status */

#worker-status {
width: 100%;
}

.worker-row {
display: grid;
grid-template-columns: 15% 70% 15%;
align-items: center;
margin: 5px 0;
gap: 10px;
width: 100%;
}

.worker-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-right: 10px;
}

.status-bars {
display: flex;
flex-wrap: nowrap;
gap: 2px;
height: 20px;
width: 100%;
margin: 0;
justify-content: flex-start;
overflow: hidden;
padding: 0 5px;
}

.status-square {
flex: 1 0 0;
height: 100%;
margin: 1px;
min-width: 8px;
}

.status-square.completed {
background: #4caf50;
}

.status-square.active {
background: #2196f3;
}

.status-square.queued {
background: #ff9800;
}

.status-square.failed {
background: #f44336;
}

.worker-stats {
text-align: right;
white-space: nowrap;
padding-left: 10px;
/* Prevent overflow */
overflow: hidden;
/* Show ellipsis if text overflows */
text-overflow: ellipsis;
}

/* Tabbed Display */
.tab-container {
margin: 20px 0;
width: 100%;
}

.tab-header {
display: flex;
gap: 2px;
border-bottom: 2px solid var(--border-color);
}

.tab-button {
padding: 10px 20px;
background: var(--task-list-bg);
border: 1px solid var(--border-color);
border-bottom: none;
cursor: pointer;
color: var(--text-color);
border-radius: 4px 4px 0 0;
}

.tab-button.active {
background: var(--bg-color);
border-bottom: 2px solid var(--bg-color);
margin-bottom: -2px;
font-weight: bold;
}

.tab-content {
display: none;
padding: 20px;
border: 1px solid var(--border-color);
border-top: none;
background: var(--bg-color);
}

.tab-content.active {
display: block;
}
24 changes: 19 additions & 5 deletions src/planai/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,25 @@ <h2>User Input Requests</h2>
<!-- User request tiles will be dynamically inserted here -->
</div>

<h2>Worker Statistics</h2>
<div id="worker-stats"></div>

<h2>Provenance Trace</h2>
<div id="trace-visualization" class="trace-list"></div>
<div class="tab-container">
<div class="tab-header">
<button class="tab-button" data-target="#worker-status">Worker Status</button>
<button class="tab-button" data-target="#worker-stats">Worker Statistics</button>
<button class="tab-button" data-target="#trace-visualization">Provenance Trace</button>
</div>

<div id="worker-status" class="tab-content">
<!-- Worker status content -->
</div>

<div id="worker-stats" class="tab-content">
<!-- Worker statistics content -->
</div>

<div id="trace-visualization" class="tab-content">
<!-- Provenance trace content -->
</div>
</div>

<h2>Queued Tasks</h2>
<div id="queued-tasks" class="task-list"></div>
Expand Down

0 comments on commit ed734d8

Please sign in to comment.