Endpoint GET /api/sidebar-counts — Conteos en vivo para el Sidebar
Endpoint GET /api/sidebar-counts
Cloudflare Pages Function que devuelve los conteos en tiempo real de las entidades principales del workspace. Reemplaza los badges hardcoded que existían en Sidebar.tsx hasta la sesión s60 (2026-05-13).
Ubicación
functions/api/sidebar-counts/index.ts
Handler: onRequestGet: PagesFunction<Env>
Responsabilidad
Proporcionar 4 conteos ligeros a través de un único fetch que el componente Sidebar.tsx ejecuta al montarse. Antes de este endpoint, los valores Tareas=9, Noticias=2, Alertas=1 estaban hardcoded en el componente — Edu detectó la desincronización al crear la task #27 cuando la base ya tenía 22 pending.
Response schema
interface CountsResponse {
tasks_pending: number; // tasks WHERE status = 'pending'
news_recent: number; // news WHERE created_at >= now() - 7 días
alerts_active: number; // alerts WHERE active = 1
notes_total: number; // COUNT(*) de notes
}
Queries D1
| Campo | Query |
|---|---|
tasks_pending | SELECT COUNT(*) AS c FROM tasks WHERE status = 'pending' |
news_recent | SELECT COUNT(*) AS c FROM news WHERE datetime(created_at) >= datetime('now', '-7 days') |
alerts_active | SELECT COUNT(*) AS c FROM alerts WHERE active = 1 |
notes_total | SELECT COUNT(*) AS c FROM notes |
Las 4 queries se ejecutan en paralelo con Promise.all. Si alguna falla, el campo correspondiente devuelve 0 (via .catch(() => null)).
Cache
Cache-Control: private, max-age=60
60 segundos de caché privado. Suficiente para que el sidebar sea reactivo sin machacar D1 en cada cambio de página. El caché es private (por navegador, no CDN) para garantizar consistencia por usuario.
Integración con Sidebar.tsx
Sidebar.tsx consume el endpoint en un useEffect al montar el componente:
const [counts, setCounts] = useState<SidebarCounts | null>(null);
useEffect(() => {
fetch('/api/sidebar-counts')
.then((r) => (r.ok ? r.json<SidebarCounts>() : null))
.then((c) => { if (!cancelled && c) setCounts(c); })
.catch(() => { /* badges quedan ocultos */ });
}, []);
Cada item de navegación declara un countKey opcional que apunta al campo del response:
interface NavDef {
title: string;
icon?: string;
href: string;
countKey?: 'tasks_pending' | 'news_recent' | 'alerts_active' | 'notes_total';
}
Si badgeValue es 0 o undefined (fetch fallido), no se renderiza badge. Esto evita mostrar números incorrectos ante fallos de red.
Items y countKey actuales (v1.0.73)
| Ítem | countKey |
|---|---|
| Tareas | tasks_pending |
| Noticias | news_recent |
| Alertas | alerts_active |
| Notas | — (sin badge; notes_total está cableado por si se activa) |
| Dashboard | — (sin badge) |
Activar badge de Notas en el futuro
El campo notes_total se calcula y se devuelve en el response, pero el item Notas en NAV no declara countKey. Para activarlo:
// src/components/shell/Sidebar.tsx — array NAV
{ title: 'Notas', icon: 'sticky', href: '/notes', countKey: 'notes_total' },
Historial
| Fecha | Versión | Cambio |
|---|---|---|
| 2026-05-13 | v1.0.73 | Creación — reemplaza badges hardcoded (s60, commit 689023f) |
Véase también
- [[workspace—que-es-workspace]]
- [[crearack—conceptos—interfaz-general]]
- [[incident—20260513—shell-s60-regressions]]