[RFC-ADN-01] Normalizar nomenclatura de proyectos
- Directorios: PascalCase (p2601_dasuten → P2601_Dasuten) - Planes: numeración pura (P2601_6.1.A → P2601.06.01) - Sin caracteres especiales en nombres de archivo - 07_proyectos.md: convención RFC-ADN-01 integrada, P2604/P2605 agregados - evento:listar: nueva opción --detalle para descripciones completas
This commit is contained in:
@@ -30,6 +30,21 @@ module.exports = (pool) => {
|
||||
res.json(rows.map(r => r.fecha));
|
||||
});
|
||||
|
||||
// GET /api/bitacoras/:fecha/version — Devuelve el ID max de entradas para smart refresh
|
||||
router.get('/:fecha/version', async (req, res) => {
|
||||
const { fecha } = req.params;
|
||||
const bResult = await pool.query('SELECT id FROM bitacoras.bitacoras WHERE fecha = $1', [fecha]);
|
||||
if (bResult.rows.length === 0) {
|
||||
return res.json({ max_id: 0, count: 0 });
|
||||
}
|
||||
const bitacoraId = bResult.rows[0].id;
|
||||
const { rows } = await pool.query(`
|
||||
SELECT COALESCE(MAX(id), 0) as max_id, COUNT(*) as count
|
||||
FROM bitacoras.entradas WHERE bitacora_id = $1
|
||||
`, [bitacoraId]);
|
||||
res.json(rows[0]);
|
||||
});
|
||||
|
||||
// GET /api/bitacoras/:fecha/completa — Bitácora completa con entradas agrupadas por nodo
|
||||
router.get('/:fecha/completa', async (req, res) => {
|
||||
const { fecha } = req.params;
|
||||
|
||||
@@ -285,8 +285,54 @@ function App() {
|
||||
setSelectedProyecto(proyectos[nextIndex].codigo);
|
||||
};
|
||||
|
||||
// Auto-refresh inteligente: solo actualizar si hay cambios
|
||||
const [lastVersion, setLastVersion] = useState<{ max_id: number; count: number } | null>(null);
|
||||
|
||||
const fetchBitacoraVersion = useCallback(async () => {
|
||||
try {
|
||||
const res = await fetch(`${API_URL}/bitacoras/${fecha}/version`);
|
||||
return await res.json();
|
||||
} catch { return null; }
|
||||
}, [fecha]);
|
||||
|
||||
const smartRefresh = useCallback(async () => {
|
||||
const newVersion = await fetchBitacoraVersion();
|
||||
if (!newVersion) {
|
||||
fetchBitacora();
|
||||
fetchFechasActivas();
|
||||
return;
|
||||
}
|
||||
if (!lastVersion || newVersion.max_id !== lastVersion.max_id || Number(newVersion.count) !== Number(lastVersion.count)) {
|
||||
setLastVersion(newVersion);
|
||||
fetchBitacora();
|
||||
fetchFechasActivas();
|
||||
}
|
||||
}, [fetchBitacoraVersion, fetchBitacora, fetchFechasActivas, lastVersion]);
|
||||
|
||||
useEffect(() => { fetchBitacora(); }, [fetchBitacora]);
|
||||
useEffect(() => { fetchNodos(); fetchProyectos(); fetchFechasActivas(); }, []);
|
||||
useEffect(() => { fetchNodos(); fetchProyectos(); }, []);
|
||||
useEffect(() => { fetchFechasActivas(); }, [fetchFechasActivas]);
|
||||
|
||||
// Inicializar versión al cargar
|
||||
useEffect(() => {
|
||||
fetchBitacoraVersion().then(v => { if (v) setLastVersion(v); });
|
||||
}, [fetchBitacoraVersion]);
|
||||
|
||||
// Auto-refresh cada 30 segundos (solo si hay cambios)
|
||||
useEffect(() => {
|
||||
const interval = setInterval(smartRefresh, 30000);
|
||||
|
||||
// También actualizar cuando la página recupera el foco
|
||||
const handleVisibility = () => {
|
||||
if (!document.hidden) smartRefresh();
|
||||
};
|
||||
document.addEventListener('visibilitychange', handleVisibility);
|
||||
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
document.removeEventListener('visibilitychange', handleVisibility);
|
||||
};
|
||||
}, [smartRefresh]);
|
||||
|
||||
// Rebuild calendar view month when fecha changes
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user