3.5 KiB
F-129 — Logs viewer: orden DESC + quitar autoscroll
Diagnóstico
El operador reporta que el visor de logs (/admin/logs) muestra los eventos en orden ASC (más antiguo arriba, más reciente abajo). Con el autoScroll activo, el usuario ve el stream llegando por abajo, pero si hace scroll arriba para buscar un evento anterior, el stream salta automáticamente hacia abajo cada vez que llega un nuevo log, lo que resulta molesto.
Solicitud:
- Orden DESC (evento más reciente arriba)
- Quitar el autoscroll (no hace falta porque el último evento siempre está arriba visible)
Diseño
Usar flex-direction: column-reverse sobre el contenedor del log para invertir visualmente el orden DOM sin tocar el array. Esto preserva:
- Estado del array en orden de llegada (cronológico) — fácil de gestionar
- Cap de 200 líneas:
next.slice(-200)mantiene las 200 más recientes, que con column-reverse quedan al inicio visible - Sin
bottomRef, sinhandleScroll, sinscrollToBottom, sinautoScrollstate
Cambios
apps/admin/src/components/ServerLogViewer.tsx:
- const [autoScroll, setAutoScroll] = useState(true);
- const bottomRef = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
- const isAtBottomRef = useRef(true);
- const scrollToBottom = useCallback(() => {
- if (autoScroll) bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
- }, [autoScroll]);
-
- const handleScroll = useCallback(() => {
- const el = containerRef.current;
- if (!el) return;
- const distFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
- isAtBottomRef.current = distFromBottom < 50;
- setAutoScroll(isAtBottomRef.current);
- }, []);
- useEffect(() => {
- if (status === 'live') scrollToBottom();
- }, [logs, scrollToBottom, status]);
Toolbar:
<div className="flex items-center gap-2">
- <label className="flex items-center gap-1.5 text-xs text-gray-400 cursor-pointer">
- <input type="checkbox" checked={autoScroll} onChange={...} ... />
- Auto-scroll
- </label>
<button onClick={() => setLogs([])} ... >Limpiar</button>
</div>
Contenedor de logs:
<div
ref={containerRef}
- onScroll={handleScroll}
className="flex-1 overflow-y-auto bg-[#0d1117] font-mono text-xs leading-relaxed"
+ className="flex-1 overflow-y-auto bg-[#0d1117] font-mono text-xs leading-relaxed flex flex-col-reverse"
style={{ minHeight: 0 }}
>
<table className="w-full table-fixed">
<tbody>
{logs.map((entry, i) => ...)}
</tbody>
</table>
- <div ref={bottomRef} />
</div>
Cap de 200 líneas
Se mantiene: next.slice(-200) (las 200 más recientes). Con column-reverse, las más recientes se ven arriba automáticamente. El usuario puede hacer scroll hacia abajo para ver las más antiguas.
Sin autoscroll: por qué es OK
Con column-reverse y array en orden cronológico:
- Posición 0 (DOM top) = log más reciente
- El usuario SIEMPRE ve el log más reciente arriba sin necesidad de scroll
- No hay "salto" del stream que moleste al hacer scroll arriba
Sin cambios en backend
El SSE GET /admin/logs/stream sigue emitiendo en orden cronológico. Solo cambiamos la presentación.
Plan
- Editar
apps/admin/src/components/ServerLogViewer.tsx— quitarautoScrollstate,bottomRef,handleScroll,scrollToBottom, useEffect de scroll. Quitar checkbox. Añadirflex flex-col-reverseal contenedor. cd apps/admin && npx tsc --noEmit.cd apps/admin && npm run build.- Cerrar gates.