From 0239438b946eddcc952e325a22503998dcb43320 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 14 Feb 2026 14:33:07 +0100 Subject: [PATCH] Logs auto scroll --- src/app/logs/page.tsx | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/app/logs/page.tsx b/src/app/logs/page.tsx index 1d2ab12..f2d0a36 100644 --- a/src/app/logs/page.tsx +++ b/src/app/logs/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { DashboardLayout } from "@/components/dashboard/DashboardLayout"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; @@ -14,6 +14,10 @@ import { AnsiText } from "@/components/ansi/Ansi"; export default function LogsPage() { const [isPaused, setIsPaused] = useState(false); + const containerRef = useRef(null); + const bottomRef = useRef(null); + const shouldAutoScroll = useRef(true); + const [filter, setFilter] = useState<"all" | "info" | "warn" | "error">( "all", ); @@ -28,6 +32,25 @@ export default function LogsPage() { filter === "all" ? true : log.level === filter, ); + const handleScroll = () => { + const el = containerRef.current; + if (!el) return; + + const threshold = 20; // px from bottom + const isAtBottom = + el.scrollHeight - el.scrollTop - el.clientHeight < threshold; + + shouldAutoScroll.current = isAtBottom; + }; + + useEffect(() => { + if (!shouldAutoScroll.current || isPaused) return; + + bottomRef.current?.scrollIntoView({ + behavior: "smooth", + }); + }, [filteredLogs, isPaused]); + const handleExport = () => { // Convert data to JSON string const json = JSON.stringify(filteredLogs, null, 2); @@ -156,7 +179,11 @@ export default function LogsPage() { - +
{filteredLogs.map((log, index) => (
*/} + + {/* Scroll anchor */} +
))}