Files
dashboard-infra/index.html
T

363 lines
19 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard LABS — Story Points</title>
<link rel="stylesheet" href="./css/styles.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js"></script>
<script type="module" src="./js/app.js" defer></script>
</head>
<body>
<!-- Loading overlay -->
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p>Consultando Jira en tiempo real…</p>
</div>
<!-- Error banner -->
<div class="error-banner" id="errorBanner"></div>
<div class="error-banner" id="limitBanner" style="background:#fff7d6; color:#a15900; border-color:#ffab00;"></div>
<!-- Header Principal -->
<header>
<div>
<h1>📊 Dashboard LABS — Story Points</h1>
<div style="font-size:13px;opacity:.7;margin-top:4px;">
Proyecto: <strong>LABS</strong> · invera.atlassian.net
</div>
</div>
<div class="header-meta">
<span id="lastUpdatedLabel">—</span>
<span class="cache-badge" id="cacheBadge"></span>
<label style="font-size:12px;opacity:0.8;color:white;margin-right:-6px;">Rango:</label>
<select id="timeRangeFilter" style="padding:4px 8px; font-size:12px; border-radius:4px; max-width:120px;">
<option value="1d">Hoy</option>
<option value="7d">Últimos 7 días</option>
<option value="30d">Último mes</option>
<option value="90d" selected>Últimos 3 meses</option>
<option value="365d">Último año</option>
<option value="all">Histórico completo</option>
</select>
<button class="refresh-btn" id="refreshBtn">↻ Actualizar</button>
</div>
</header>
<!-- ── SECCIÓN 1: Carga de Trabajo (Pendientes) ── -->
<div class="section-header current">
<div class="dot" style="background:#0065ff;"></div>
<h2>Carga de Trabajo Actual</h2>
<span id="currentTicketsLabel" style="font-size:12px;color:#5e6c84;margin-left:8px;">Tickets pendientes en el tablero</span>
<div class="filter-group">
<label>Filtrar por Dev:</label>
<select id="devFilter"><option value="all">Cargando...</option></select>
</div>
</div>
<div class="main">
<div class="section-block">
<div class="kpi-row">
<div class="kpi progress" title="Suma de Story Points (SP) de todos los tickets actualmente en la columna En Progreso"><div class="kpi-value" id="kpi-ip">—</div><div class="kpi-label">SP En Progreso</div><div class="kpi-sub">Trabajo en curso</div></div>
<div class="kpi todo" title="Suma de Story Points de tickets pendientes que aún no comenzaron"><div class="kpi-value" id="kpi-todo">—</div><div class="kpi-label">SP Por Hacer</div><div class="kpi-sub">Backlog del periodo</div></div>
<div class="kpi members" title="Cantidad de personas con carga de trabajo (tickets) asignados en este momento"><div class="kpi-value" id="kpi-members">—</div><div class="kpi-label">Devs con Carga</div><div class="kpi-sub">Con tickets pendientes</div></div>
</div>
<div class="charts-grid">
<div class="chart-card">
<h3>🔵 Pendientes por Desarrollador</h3>
<div class="sub">Story Points con trabajo pendiente</div>
<div style="position:relative;height:260px"><canvas id="chartCurrentState"></canvas></div>
</div>
<div class="chart-card">
<h3 style="display:flex;align-items:center;">📢 Alertas de Salud
<div class="pop-trigger" style="margin-left:8px; font-size:14px; cursor:help; border:none;">ℹ️
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left; font-size:12px; width:260px;">
<strong>Tipos de Alertas:</strong><br><br>
<span class="badge" style="background:#ffab00;color:white;font-size:10px;padding:2px 4px;">ESTANCADO</span> &rsaquo; +14 días en curso.<br><br>
<span class="badge" style="background:#ff5630;color:white;font-size:10px;padding:2px 4px;">VENCIDO</span> &rsaquo; Fecha de entrega caducada.<br><br>
<span class="badge" style="background:#6554c0;color:white;font-size:10px;padding:2px 4px;">SIN SP</span> &rsaquo; Completado sin estimación.<br><br>
<span class="badge" style="background:#ff8b00;color:white;font-size:10px;padding:2px 4px;">HUÉRFANO</span> &rsaquo; Ticket con SP sin asignar.<br><br>
<span class="badge" style="background:#36b37e;color:white;font-size:10px;padding:2px 4px;">DEV LIBRE</span> &rsaquo; Dev sin tickets pendientes ni en curso.
</div>
</div>
</h3>
<div class="sub">Tickets estancados o sin estimación</div>
<div id="warningsSection" style="display:none; overflow-y:auto; max-height:230px; margin-top:10px;">
<ul class="warning-list" id="warningsList" style="padding:0; margin:0;"></ul>
</div>
<div id="noWarningsMsg" style="text-align:center; color:#36b37e; padding:40px 0; display:none;">
✅ No hay alertas pendientes
</div>
</div>
</div>
<div class="table-card">
<h3>Detalle de Carga de Trabajo</h3>
<table>
<thead><tr><th>Desarrollador</th><th>🔵 En Progreso</th><th>⏳ Por Hacer</th><th>Total Pendiente</th><th>Carga Visual</th></tr></thead>
<tbody id="tableCurrentState"></tbody>
</table>
</div>
</div>
</div>
<!-- ── SECCIÓN 2: Rendimiento & Resultados ── -->
<div class="section-header history">
<div class="dot" style="background:#36b37e;"></div>
<h2>Resultados del Período</h2>
<span style="font-size:12px;color:#5e6c84;margin-left:8px;">Story Points finalizados y velocidad</span>
<span class="badge" id="filterBadge" style="display:none;"></span>
</div>
<div class="main">
<div class="section-block">
<div class="kpi-row-3">
<div class="kpi done" title="Suma total de Story Points entregados y completados en el período de tiempo seleccionado"><div class="kpi-value" id="kpi-done-period">—</div><div class="kpi-label">SP Completados</div><div class="kpi-sub">en el período</div></div>
<div class="kpi members" title="Cantidad de desarrolladores que han cerrado al menos 1 Story Point en este período"><div class="kpi-value" id="kpi-devs-period">—</div><div class="kpi-label">Desarrolladores</div><div class="kpi-sub">que completaron SP</div></div>
<div class="kpi progress" title="Promedio simple: Total de SP completados dividido por la cantidad de desarrolladores"><div class="kpi-value" id="kpi-avg-period">—</div><div class="kpi-label">SP promedio / dev</div><div class="kpi-sub">en el período</div></div>
</div>
<div class="kpi-row-3" style="margin-top:-8px;">
<div class="kpi" style="border-color:#36b37e;" title="Lead Time: Tiempo total promedio que vive un ticket desde su creación hasta que es cerrado"><div class="kpi-value" id="kpi-lead-time">—</div><div class="kpi-label">Promedio Lead Time</div><div class="kpi-sub">Días (Creación a Fin)</div></div>
<div class="kpi" style="border-color:#00b8d9;" title="Cycle Time: Velocidad de desarrollo neto. Promedio en días desde que un developer mueve el ticket 'En Curso' hasta cerrarse"><div class="kpi-value" id="kpi-cycle-time">—</div><div class="kpi-label">Promedio Cycle Time</div><div class="kpi-sub">Días (En Curso a Fin)</div></div>
<div class="kpi warning" title="Variación entre el Story Point estimado al sprint vs el final real; un número en (+) indica Scope Creep (inflación de puntos)"><div class="kpi-value" id="kpi-sp-deviation">—</div><div class="kpi-label">Desviación SP</div><div class="kpi-sub" id="kpi-sp-deviation-sub">Original vs Final</div></div>
</div>
<div class="charts-grid">
<div class="chart-card">
<h3>✅ SP Completados — por Desarrollador</h3>
<div class="sub">Período seleccionado</div>
<div style="position:relative;height:260px"><canvas id="chartDoneDev"></canvas></div>
</div>
<div class="chart-card">
<h3>📈 Velocidad Histórica</h3>
<div class="sub">SP completados mes a mes</div>
<div style="position:relative;height:260px"><canvas id="chartVelocity"></canvas></div>
</div>
</div>
<div class="table-card">
<h3 style="display:flex; justify-content:space-between; align-items:center;">
<span>SP Completados — Tabla Resumen</span>
<span id="teamAvgLabel" style="font-size:12px; font-weight:normal; background:#e6fcff; color:#0065ff; padding:4px 8px; border-radius:4px; display:none;"></span>
</h3>
<table>
<thead><tr><th>Desarrollador</th><th>✅ SP Total</th><th>🎟️ Tickets</th><th>📉 Media SP/Ticket</th><th>% del impacto total vs Equipo</th></tr></thead>
<tbody id="tableHistory"></tbody>
</table>
</div>
</div>
</div>
<!-- ── SECCIÓN: Revisión de Código (Code Review) ── -->
<div class="section-header" style="border-color:#00b8d9;">
<div class="dot" style="background:#00b8d9;"></div>
<h2>Revisión de Código (Code Review)</h2>
<span style="font-size:12px;color:#5e6c84;margin-left:8px;">Métricas de revisión entre pares antes de QA</span>
</div>
<div class="main">
<div class="section-block">
<!-- Colas Actuales -->
<div class="kpi-row" style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #dfe1e6;">
<div class="kpi warning" style="border-color:#ff8b00;" title="Tickets que se encuentran en este preciso instante en la columna Code Review esperando o siendo revisados">
<div class="kpi-value" id="kpi-cr-queue-now">—</div>
<div class="kpi-label">En Cola Actual CR</div>
<div class="kpi-sub" id="kpi-cr-queue-sp">— SP en espera</div>
</div>
<div class="kpi warning" title="Tickets que se encuentran actualmente y desde hace más de 2 días atascados solos en la columna de revisión">
<div class="kpi-value" id="kpi-cr-stalled">—</div>
<div class="kpi-label">Tickets Atascados CR</div>
<div class="kpi-sub">Demorados actualmente (más de 2 días)</div>
</div>
</div>
<!-- Historial del período -->
<h3 style="font-size:14px; margin-bottom:12px; color:#172b4d;">Métricas del período seleccionado</h3>
<div class="kpi-row">
<div class="kpi" style="border-color:#00b8d9;" title="Cantidad de tickets que registraron actividad en la fase de Code Review">
<div class="kpi-value" id="kpi-cr-tickets">—</div>
<div class="kpi-label">Tickets en CR</div>
<div class="kpi-sub">Procesados en el período</div>
</div>
<div class="kpi" style="border-color:#00b8d9;">
<div class="kpi-value" id="kpi-cr-p50">—</div>
<div class="kpi-label">
<div class="pop-trigger" style="border-bottom: 1px dotted #5e6c84;">Tiempo P50 CR
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left;">
<div class="pop-item" style="font-size:12px;"><strong>Percentil 50 (Mediana)</strong><br>El 50% de las revisiones de código se completan en esta cantidad de horas o menos.<br><br>A diferencia del promedio tradicional, el P50 muestra un valor "habitual" sin ser distorsionado por tickets que queden atascados durante meses.</div>
</div>
</div>
</div>
<div class="kpi-sub">Horas (Mediana)</div>
</div>
<div class="kpi" style="border-color:#ff8b00;">
<div class="kpi-value" id="kpi-cr-p90">—</div>
<div class="kpi-label">
<div class="pop-trigger" style="border-bottom: 1px dotted #5e6c84;">Tiempos P90 y P99
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left;">
<div class="pop-item" style="font-size:12px;"><strong>Métricas de Cuello de Botella</strong><br>Muestran los "peores escenarios" posibles.<br><br><strong>P90:</strong> El 90% de los tickets logra pasar en este tiempo. El 10% restante demoró aún más.<br><strong>P99:</strong> El 99% pasa en este tiempo. Ideal para medir los bloqueos máximos.</div>
</div>
</div>
</div>
<div class="kpi-sub" id="kpi-cr-p99-sub">P99: — hs</div>
</div>
</div>
<div class="charts-grid">
<div class="chart-card full">
<h3>📈 Tiempo Promedio en Code Review — Mes a Mes</h3>
<div class="sub">Evolución de la velocidad de revisión de pares (horas)</div>
<div style="position:relative;height:240px"><canvas id="chartCrMonthly"></canvas></div>
</div>
</div>
</div>
</div>
<!-- ── SECCIÓN 3: Control de Calidad (QA) ── -->
<div class="section-header qa">
<div class="dot qa"></div>
<h2>Control de Calidad (QA)</h2>
<span style="font-size:12px;color:#5e6c84;margin-left:8px;">Métricas del proceso de QA · Tiempos, colas y devoluciones</span>
</div>
<div class="main">
<div class="section-block">
<!-- Colas Actuales -->
<div class="kpi-row" style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #dfe1e6;">
<div class="kpi qa-queue" style="border-color:#ff8b00;" title="Tickets que se encuentran en este preciso instante en la columna Ready to QA">
<div class="kpi-value" id="kpi-qa-queue-now">—</div>
<div class="kpi-label">En Cola Actual RTQA</div>
<div class="kpi-sub" id="kpi-qa-queue-now-sp">— SP esperando</div>
</div>
<div class="kpi qa" style="border-color:#0065ff;" title="Tickets que se encuentran en este preciso instante siendo probados en la columna QA">
<div class="kpi-value" id="kpi-qa-active-now">—</div>
<div class="kpi-label">En Cola Actual QA</div>
<div class="kpi-sub" id="kpi-qa-active-now-sp">— SP en prueba</div>
</div>
</div>
<!-- KPIs del período -->
<h3 style="font-size:14px; margin-bottom:12px; color:#172b4d;">Métricas del período seleccionado</h3>
<div class="kpi-row-3" style="margin-bottom:16px;">
<div class="kpi qa" title="Total de tickets que han pasado por QA">
<div class="kpi-value" id="kpi-qa-tickets">—</div>
<div class="kpi-label">Tickets QA</div>
<div class="kpi-sub">Procesados en el período</div>
</div>
<div class="kpi qa-time">
<div class="kpi-value" id="kpi-qa-p50">—</div>
<div class="kpi-label">
<div class="pop-trigger" style="border-bottom: 1px dotted #5e6c84;">Tiempo P50 QA
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left;">
<div class="pop-item" style="font-size:12px;"><strong>Percentil 50 (Mediana)</strong><br>El 50% de las pruebas se completan en esta cantidad de horas netas o menos.</div>
</div>
</div>
</div>
<div class="kpi-sub">Horas en prueba</div>
</div>
<div class="kpi qa-time" style="border-color:#ff8b00;">
<div class="kpi-value" id="kpi-qa-p90">—</div>
<div class="kpi-label">
<div class="pop-trigger" style="border-bottom: 1px dotted #5e6c84;">Tiempos P90 y P99 QA
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left;">
<div class="pop-item" style="font-size:12px;"><strong>Cuellos de Botella QA</strong><br><strong>P90:</strong> El 90% logran probarse en este tiempo.<br><strong>P99:</strong> El 99% logra terminar en este tiempo.</div>
</div>
</div>
</div>
<div class="kpi-sub" id="kpi-qa-p99-sub">P99: — hs</div>
</div>
</div>
<div class="kpi-row-3">
<div class="kpi returned" title="Tickets que sufrieron rechazos en revisiones (Code Review, Ready to QA o QA) y volvieron a desarrollo.">
<div class="kpi-value" id="kpi-qa-returned">—</div>
<div class="kpi-label">Tickets con Retrabajo</div>
<div class="kpi-sub" id="kpi-qa-returned-pct">Sufrieron rechazos</div>
</div>
<div class="kpi qa-queue">
<div class="kpi-value" id="kpi-qa-rtqa-p50">—</div>
<div class="kpi-label">
<div class="pop-trigger" style="border-bottom: 1px dotted #5e6c84;">Tiempo P50 RTQA
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left;">
<div class="pop-item" style="font-size:12px;"><strong>Percentil 50 (Mediana)</strong><br>El 50% de los tickets espera esta cantidad de horas (o menos) en la cola antes de ser tomado por QA.</div>
</div>
</div>
</div>
<div class="kpi-sub">Horas en cola</div>
</div>
<div class="kpi qa-queue" style="border-color:#ff8b00;">
<div class="kpi-value" id="kpi-qa-rtqa-p90">—</div>
<div class="kpi-label">
<div class="pop-trigger" style="border-bottom: 1px dotted #5e6c84;">Tiempos P90 y P99 Cola
<div class="pop-content" style="text-transform:none; font-weight:normal; letter-spacing:normal; text-align:left;">
<div class="pop-item" style="font-size:12px;"><strong>Cuellos de Botella RTQA</strong><br>Casos atascados sin tester asignado.<br><br><strong>P90:</strong> El 90% de los tickets sale de la cola en este tiempo.<br><strong>P99:</strong> Bloqueos máximos en la cola.</div>
</div>
</div>
</div>
<div class="kpi-sub" id="kpi-qa-rtqa-p99-sub">P99: — hs</div>
</div>
</div>
<!-- Gráficos fila 1 -->
<div class="charts-grid">
<div class="chart-card">
<h3>📊 Distribución de Tiempos en QA</h3>
<div class="sub">Rangos: &lt;30min · 30min–2hs · 2–8hs · &gt;8hs</div>
<div style="position:relative;height:240px"><canvas id="chartQaDist"></canvas></div>
</div>
<div class="chart-card">
<h3>🔄 Flujo Directo vs Retrabajo</h3>
<div class="sub">Tickets con 0 rechazos vs con devoluciones (CR/QA)</div>
<div style="position:relative;height:240px"><canvas id="chartQaReturned"></canvas></div>
</div>
</div>
<!-- Gráficos fila 2 -->
<div class="charts-grid">
<div class="chart-card">
<h3>📈 Tiempo Promedio en QA — Mes a Mes</h3>
<div class="sub">Evolución de la velocidad de revisión (horas)</div>
<div style="position:relative;height:240px"><canvas id="chartQaMonthly"></canvas></div>
</div>
<div class="chart-card">
<h3>⏳ Tiempo en Cola RTQA — Mes a Mes</h3>
<div class="sub">Horas promedio esperando ser tomado por QA</div>
<div style="position:relative;height:240px"><canvas id="chartRtqaMonthly"></canvas></div>
</div>
</div>
<!-- Tabla de tickets QA -->
<div class="table-card">
<h3>🔍 Detalle de Tickets — QA</h3>
<table>
<thead>
<tr>
<th>Ticket</th>
<th>Resumen</th>
<th>⏱️ Dev (hs)</th>
<th>⏱️ CR (hs)</th>
<th>⏱️ QA (hs)</th>
<th>🔄 Veces devuelto</th>
<th>Estado</th>
</tr>
</thead>
<tbody id="tableQA"></tbody>
</table>
</div>
</div>
</div>
<footer>
Dashboard en tiempo real · Arquitectura Modular Serverless · Realizado para Vercel & Jira
</footer>
</body>
</html>