217 lines
7.6 KiB
HTML
217 lines
7.6 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}Dashboard{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="hero-section">
|
||
<div class="d-flex align-items-center justify-content-between flex-wrap gap-3">
|
||
<div>
|
||
<h1 style="font-size:1.75rem;margin-bottom:.4rem;-webkit-text-fill-color:unset;background:none;color:var(--text-primary);">
|
||
Diversity-Ball Wien 2026
|
||
</h1>
|
||
<p style="color:var(--text-secondary);margin:0;font-size:.9rem;">
|
||
Agenten-Orchestrierung · Samstag 5. September · Wiener Rathaus
|
||
</p>
|
||
</div>
|
||
<div class="d-flex gap-2 flex-wrap">
|
||
<a href="/orchestrator" class="btn btn-primary">🤖 Orchestrator</a>
|
||
<a href="/chat" class="btn btn-secondary">💬 Chat</a>
|
||
<a href="/files" class="btn btn-secondary">📂 Dateien</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Stats -->
|
||
<div class="row g-3 mb-4">
|
||
<div class="col-6 col-md-3">
|
||
<div class="stat-card">
|
||
<div class="stat-number">{{ agents|length }}</div>
|
||
<div class="stat-label">Agenten</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-6 col-md-3">
|
||
<div class="stat-card">
|
||
<div class="stat-number">{{ recent_tasks|length }}</div>
|
||
<div class="stat-label">Letzte Tasks</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-6 col-md-3">
|
||
<div class="stat-card">
|
||
<div class="stat-number">5. Sep</div>
|
||
<div class="stat-label">Event-Datum</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-6 col-md-3">
|
||
<div class="stat-card">
|
||
<div class="stat-number">3.500</div>
|
||
<div class="stat-label">Gäste</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Agents -->
|
||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||
<h3 style="margin:0;">Verfügbare Agenten</h3>
|
||
<a href="/agents" class="btn btn-outline-secondary btn-sm">Alle verwalten</a>
|
||
</div>
|
||
|
||
<div class="row g-3 mb-4">
|
||
{% for key, agent in agents.items() %}
|
||
<div class="col-sm-6 col-md-4 col-lg-3">
|
||
<div class="card agent-card h-100">
|
||
<div class="card-body">
|
||
<div class="d-flex align-items-center gap-2 mb-2">
|
||
<span style="width:8px;height:8px;border-radius:50%;background:var(--success);flex-shrink:0;box-shadow:0 0 6px var(--success);"></span>
|
||
<h5 style="margin:0;font-size:.875rem;font-weight:600;">{{ agent.name }}</h5>
|
||
</div>
|
||
<p style="font-size:.775rem;color:var(--text-muted);line-height:1.45;margin-bottom:.75rem;">
|
||
{{ agent.description[:90] }}{% if agent.description|length > 90 %}…{% endif %}
|
||
</p>
|
||
<span class="badge bg-success">aktiv</span>
|
||
</div>
|
||
<div class="card-footer">
|
||
<a href="/agents?edit={{ key }}" class="btn btn-outline-primary btn-sm w-100">⚙ Bearbeiten</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
|
||
<!-- System-Steuerung -->
|
||
<div class="card mb-4">
|
||
<div class="card-body">
|
||
<h5 style="margin-bottom:1rem;font-weight:600;">System-Steuerung</h5>
|
||
<div class="d-flex align-items-center justify-content-between flex-wrap gap-3">
|
||
<!-- Daily Standup Toggle -->
|
||
<div class="d-flex align-items-center gap-3">
|
||
<div>
|
||
<div style="font-weight:500;font-size:.9rem;">Daily Standup</div>
|
||
<div style="font-size:.78rem;color:var(--text-muted);">Täglich 09:00 – automatische Statusabfrage</div>
|
||
</div>
|
||
<div class="form-check form-switch mb-0">
|
||
<input class="form-check-input" type="checkbox" role="switch" id="standupToggle"
|
||
{% if standup_enabled %}checked{% endif %}
|
||
style="width:2.5em;height:1.4em;cursor:pointer;">
|
||
</div>
|
||
<span id="standupLabel" class="badge {% if standup_enabled %}bg-success{% else %}bg-secondary{% endif %}">
|
||
{% if standup_enabled %}Aktiv{% else %}Inaktiv{% endif %}
|
||
</span>
|
||
</div>
|
||
<!-- Tasks leeren -->
|
||
<button id="clearTasksBtn" class="btn btn-outline-danger btn-sm" onclick="clearAllTasks()">
|
||
Alle Tasks leeren
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Recent Tasks -->
|
||
{% if recent_tasks %}
|
||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||
<h3 style="margin:0;">Letzte Tasks</h3>
|
||
<a href="/tasks" class="btn btn-outline-secondary btn-sm">Alle Tasks</a>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-body p-0">
|
||
<div class="table-responsive">
|
||
<table class="table table-hover mb-0">
|
||
<thead>
|
||
<tr>
|
||
<th>#</th>
|
||
<th>Titel</th>
|
||
<th>Agent</th>
|
||
<th>Status</th>
|
||
<th>Erstellt</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for task in recent_tasks %}
|
||
<tr>
|
||
<td><span style="color:var(--text-muted);font-size:.8rem;">#{{ task.id }}</span></td>
|
||
<td style="font-weight:500;">{{ task.title }}</td>
|
||
<td style="font-size:.8rem;color:var(--text-muted);">{{ task.assigned_agent }}</td>
|
||
<td>
|
||
{% if task.status == 'pending' %}
|
||
<span class="badge bg-warning">Pending</span>
|
||
{% elif task.status == 'in_progress' %}
|
||
<span class="badge bg-primary">Läuft</span>
|
||
{% elif task.status == 'completed' %}
|
||
<span class="badge bg-success">Fertig</span>
|
||
{% elif task.status == 'error' %}
|
||
<span class="badge bg-danger">Fehler</span>
|
||
{% else %}
|
||
<span class="badge bg-secondary">{{ task.status }}</span>
|
||
{% endif %}
|
||
</td>
|
||
<td style="color:var(--text-muted);font-size:.78rem;">{{ task.created }}</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<script>
|
||
// Daily Standup Toggle
|
||
document.getElementById('standupToggle').addEventListener('change', function() {
|
||
const enabled = this.checked;
|
||
const label = document.getElementById('standupLabel');
|
||
fetch('/api/standup/toggle', {
|
||
method: 'POST',
|
||
headers: {'Content-Type': 'application/json'},
|
||
body: JSON.stringify({enabled: enabled})
|
||
})
|
||
.then(r => r.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
label.textContent = enabled ? 'Aktiv' : 'Inaktiv';
|
||
label.className = 'badge ' + (enabled ? 'bg-success' : 'bg-secondary');
|
||
} else {
|
||
// Revert on error
|
||
this.checked = !enabled;
|
||
alert('Fehler: ' + data.message);
|
||
}
|
||
})
|
||
.catch(() => {
|
||
this.checked = !enabled;
|
||
alert('Netzwerkfehler beim Speichern.');
|
||
});
|
||
});
|
||
|
||
// Alle Tasks leeren
|
||
function clearAllTasks() {
|
||
if (!confirm('Alle Tasks wirklich löschen? Dies kann nicht rückgängig gemacht werden.')) return;
|
||
const btn = document.getElementById('clearTasksBtn');
|
||
btn.disabled = true;
|
||
btn.textContent = 'Löschen...';
|
||
fetch('/api/tasks/clear', {method: 'POST'})
|
||
.then(r => r.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
// Task-Tabelle aus DOM entfernen falls vorhanden
|
||
const taskSection = document.querySelector('.table-responsive');
|
||
if (taskSection) taskSection.closest('.card').remove();
|
||
const taskHeader = document.querySelectorAll('h3');
|
||
taskHeader.forEach(h => { if (h.textContent.includes('Letzte Tasks')) h.closest('.d-flex').remove(); });
|
||
btn.textContent = 'Geleert';
|
||
btn.className = 'btn btn-success btn-sm';
|
||
setTimeout(() => {
|
||
btn.textContent = 'Alle Tasks leeren';
|
||
btn.className = 'btn btn-outline-danger btn-sm';
|
||
btn.disabled = false;
|
||
}, 2000);
|
||
} else {
|
||
alert('Fehler: ' + data.message);
|
||
btn.disabled = false;
|
||
btn.textContent = 'Alle Tasks leeren';
|
||
}
|
||
})
|
||
.catch(() => {
|
||
alert('Netzwerkfehler.');
|
||
btn.disabled = false;
|
||
btn.textContent = 'Alle Tasks leeren';
|
||
});
|
||
}
|
||
</script>
|
||
{% endblock %}
|