Dashboard Status compact în Kanban
- Header colapsabil cu rezumat (ANAF, Git) - Status row: ANAF, Git, ultimul raport cu timestamp - Cron jobs pe un singur rând - Colapsat by default - status.json actualizat de rapoartele zilnice
This commit is contained in:
@@ -15,6 +15,126 @@
|
|||||||
padding: var(--space-5);
|
padding: var(--space-5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dashboard */
|
||||||
|
.dashboard {
|
||||||
|
background: var(--bg-surface);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
margin-bottom: var(--space-5);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-3);
|
||||||
|
padding: var(--space-3) var(--space-4);
|
||||||
|
background: linear-gradient(135deg, rgba(99, 102, 241, 0.15), rgba(139, 92, 246, 0.1));
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-header:hover {
|
||||||
|
filter: brightness(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-2);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-title svg {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-summary {
|
||||||
|
flex: 1;
|
||||||
|
font-size: var(--text-xs);
|
||||||
|
color: var(--text-muted);
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-toggle {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
transition: transform var(--transition-fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard.collapsed .dashboard-toggle {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard.collapsed .dashboard-content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-content {
|
||||||
|
padding: var(--space-2) var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--space-4);
|
||||||
|
margin-bottom: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-1);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-label {
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-value {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-value.ok { color: #22c55e; }
|
||||||
|
.status-value.warning { color: #f59e0b; }
|
||||||
|
.status-value.error { color: #ef4444; }
|
||||||
|
|
||||||
|
.status-time {
|
||||||
|
font-size: var(--text-xs);
|
||||||
|
color: var(--text-muted);
|
||||||
|
margin-left: var(--space-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cron-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-2);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
padding-top: var(--space-2);
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cron-label {
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cron-list {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cron-done {
|
||||||
|
color: var(--text-muted);
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
.page-header {
|
.page-header {
|
||||||
margin-bottom: var(--space-6);
|
margin-bottom: var(--space-6);
|
||||||
}
|
}
|
||||||
@@ -352,6 +472,39 @@
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="main">
|
<main class="main">
|
||||||
|
<!-- Status Dashboard -->
|
||||||
|
<div class="dashboard" id="dashboard">
|
||||||
|
<div class="dashboard-header" onclick="toggleDashboard()">
|
||||||
|
<div class="dashboard-title">
|
||||||
|
<i data-lucide="activity"></i>
|
||||||
|
<span>Status</span>
|
||||||
|
</div>
|
||||||
|
<div class="dashboard-summary" id="dashboardSummary">Se încarcă...</div>
|
||||||
|
<i data-lucide="chevron-down" class="dashboard-toggle" id="dashboardToggle"></i>
|
||||||
|
</div>
|
||||||
|
<div class="dashboard-content" id="dashboardContent">
|
||||||
|
<div class="status-row">
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-label">ANAF:</span>
|
||||||
|
<span class="status-value" id="anafStatus">OK</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-label">Git:</span>
|
||||||
|
<span class="status-value" id="gitStatus">curat</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-label">Raport:</span>
|
||||||
|
<span class="status-value" id="lastReport">-</span>
|
||||||
|
<span class="status-time" id="reportTime"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cron-row">
|
||||||
|
<span class="cron-label">Azi:</span>
|
||||||
|
<span class="cron-list" id="cronList">-</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1 class="page-title">Task Board</h1>
|
<h1 class="page-title">Task Board</h1>
|
||||||
<p class="page-subtitle" id="lastUpdated">Se încarcă...</p>
|
<p class="page-subtitle" id="lastUpdated">Se încarcă...</p>
|
||||||
@@ -397,6 +550,86 @@
|
|||||||
// Init Lucide icons
|
// Init Lucide icons
|
||||||
lucide.createIcons();
|
lucide.createIcons();
|
||||||
|
|
||||||
|
// Dashboard
|
||||||
|
function initDashboard() {
|
||||||
|
const collapsed = localStorage.getItem('dashboardCollapsed');
|
||||||
|
const dashboard = document.getElementById('dashboard');
|
||||||
|
// Default collapsed
|
||||||
|
if (collapsed === null || collapsed === 'true') {
|
||||||
|
dashboard.classList.add('collapsed');
|
||||||
|
}
|
||||||
|
loadDashboardStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleDashboard() {
|
||||||
|
const dashboard = document.getElementById('dashboard');
|
||||||
|
dashboard.classList.toggle('collapsed');
|
||||||
|
localStorage.setItem('dashboardCollapsed', dashboard.classList.contains('collapsed'));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadDashboardStatus() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('status.json?' + Date.now());
|
||||||
|
if (response.ok) {
|
||||||
|
const status = await response.json();
|
||||||
|
updateDashboard(status);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log('No status.json yet');
|
||||||
|
}
|
||||||
|
updateCronList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDashboard(status) {
|
||||||
|
// ANAF
|
||||||
|
const anafEl = document.getElementById('anafStatus');
|
||||||
|
if (status.anaf) {
|
||||||
|
anafEl.textContent = status.anaf.status;
|
||||||
|
anafEl.className = 'status-value ' + (status.anaf.ok ? 'ok' : 'warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Git
|
||||||
|
const gitEl = document.getElementById('gitStatus');
|
||||||
|
if (status.git) {
|
||||||
|
gitEl.textContent = status.git.status;
|
||||||
|
gitEl.className = 'status-value ' + (status.git.clean ? 'ok' : 'warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last report
|
||||||
|
const reportEl = document.getElementById('lastReport');
|
||||||
|
const timeEl = document.getElementById('reportTime');
|
||||||
|
if (status.lastReport) {
|
||||||
|
reportEl.textContent = status.lastReport.summary || 'OK';
|
||||||
|
timeEl.textContent = status.lastReport.time ? '(' + status.lastReport.time + ')' : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Summary in header
|
||||||
|
const summaryEl = document.getElementById('dashboardSummary');
|
||||||
|
let summary = [];
|
||||||
|
if (status.anaf) summary.push('ANAF: ' + status.anaf.status);
|
||||||
|
if (status.git) summary.push('Git: ' + status.git.status);
|
||||||
|
summaryEl.textContent = summary.join(' · ');
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCronList() {
|
||||||
|
const now = new Date();
|
||||||
|
const hour = now.getHours();
|
||||||
|
|
||||||
|
const jobs = [
|
||||||
|
{ time: '07:30', name: 'coaching', done: hour >= 8 },
|
||||||
|
{ time: '08:30', name: 'raport', done: hour >= 9 },
|
||||||
|
{ time: '20:00', name: 'raport', done: hour >= 20 },
|
||||||
|
{ time: '21:00', name: 'coaching', done: hour >= 21 }
|
||||||
|
];
|
||||||
|
|
||||||
|
const listEl = document.getElementById('cronList');
|
||||||
|
listEl.innerHTML = jobs.map(job =>
|
||||||
|
`<span class="${job.done ? 'cron-done' : ''}">${job.time} ${job.name}</span>`
|
||||||
|
).join(' · ');
|
||||||
|
}
|
||||||
|
|
||||||
|
initDashboard();
|
||||||
|
|
||||||
let tasksData = null;
|
let tasksData = null;
|
||||||
let draggedTask = null;
|
let draggedTask = null;
|
||||||
let saveTimeout = null;
|
let saveTimeout = null;
|
||||||
|
|||||||
21
kanban/status.json
Normal file
21
kanban/status.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"anaf": {
|
||||||
|
"status": "OK",
|
||||||
|
"ok": true,
|
||||||
|
"lastCheck": "2026-01-30T13:50:00Z"
|
||||||
|
},
|
||||||
|
"git": {
|
||||||
|
"status": "curat",
|
||||||
|
"clean": true,
|
||||||
|
"files": 0
|
||||||
|
},
|
||||||
|
"agents": {
|
||||||
|
"count": 5,
|
||||||
|
"list": ["echo-work", "echo-health", "echo-growth", "echo-sprijin", "echo-scout"]
|
||||||
|
},
|
||||||
|
"lastReport": {
|
||||||
|
"type": "test",
|
||||||
|
"summary": "Ecosistem configurat, totul în ordine",
|
||||||
|
"time": "30 ian 2026, 13:55"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user