diff --git a/CHANGELOG.md b/CHANGELOG.md index e291987..6da09f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog - project.linkedcorp.net +## [2.2.4] - 2026-09-22 +### Fixed +- El botón "Actualizar" se quedaba visible después de aplicar la actualización, hasta que se + refrescaba la pestaña a mano. Ahora, mientras se aplica, el panel consulta el estado cada + pocos segundos y en cuanto confirma que ya quedó en la última versión, el botón desaparece + solo (sin depender de la recarga automática del service worker). + ## [2.2.3] - 2026-09-22 ### Fixed - Al actualizar (ya sea con el botón nuevo o por deploy manual), la pestaña abierta seguía diff --git a/VERSION b/VERSION index 5859406..530cdd9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.3 +2.2.4 diff --git a/backend/package.json b/backend/package.json index dd469c7..f9b099b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "project-linkedcorp-backend", - "version": "2.2.3", + "version": "2.2.4", "private": true, "type": "module", "main": "src/server.js", diff --git a/frontend/package.json b/frontend/package.json index 0a1232a..2b31c51 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "project-linkedcorp-frontend", "private": true, - "version": "2.2.3", + "version": "2.2.4", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/pages/Configuracion/UpdaterPanel.jsx b/frontend/src/pages/Configuracion/UpdaterPanel.jsx index f683bd2..3f25a12 100644 --- a/frontend/src/pages/Configuracion/UpdaterPanel.jsx +++ b/frontend/src/pages/Configuracion/UpdaterPanel.jsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { RefreshCw, Download } from 'lucide-react'; import { useUi } from '../../context/ui-context.jsx'; import { useAsync, useAction } from '../../hooks/useAsync.js'; @@ -8,12 +8,36 @@ import { Badge } from '../../components/Badge.jsx'; import { InfoBar } from '../../components/InfoBar.jsx'; const CRITICALITY_COLOR = { alta: 'danger', media: 'warning', baja: 'success' }; +const POLL_INTERVAL_MS = 5000; +const POLL_MAX_ATTEMPTS = 60; // ~5 minutos tope export default function UpdaterPanel() { const { t, openDialog, pushToast } = useUi(); - const { data: status, loading, error, reload } = useAsync(getUpdateStatus, []); + const { data: status, loading, error, reload, setData } = useAsync(getUpdateStatus, []); const runAction = useAction(); const [applying, setApplying] = useState(false); + const mountedRef = useRef(true); + useEffect(() => () => { mountedRef.current = false; }, []); + + // El servidor se reinicia a mitad de la actualizacion (backend y frontend), asi que durante + // ese rato las llamadas van a fallar por un momento -- se ignoran y se sigue insistiendo. + // Cuando confirma que ya esta al dia, el boton "Actualizar" desaparece solo (esta gateado por + // !status.upToDate mas abajo) sin depender de que la pestaña se recargue. + async function pollUntilUpToDate() { + for (let i = 0; i < POLL_MAX_ATTEMPTS && mountedRef.current; i++) { + await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS)); + if (!mountedRef.current) return; + try { + const result = await getUpdateStatus(); + if (!mountedRef.current) return; + setData(result); + if (result.upToDate) { setApplying(false); return; } + } catch { + // backend reiniciandose -- se ignora y se reintenta en el proximo ciclo + } + } + if (mountedRef.current) setApplying(false); + } function confirmApply() { openDialog({ @@ -28,7 +52,7 @@ export default function UpdaterPanel() { setApplying(true); await applyUpdate(); pushToast({ tone: 'success', message: t('updater_apply_started') }); - }).finally(() => setApplying(false)), + }).then(pollUntilUpToDate).catch(() => setApplying(false)), }, ], });