diff --git a/web-app/src/routes/local-api-server/logs.tsx b/web-app/src/routes/local-api-server/logs.tsx index db4189cb4..aa21a6de9 100644 --- a/web-app/src/routes/local-api-server/logs.tsx +++ b/web-app/src/routes/local-api-server/logs.tsx @@ -1,7 +1,7 @@ import { createFileRoute } from '@tanstack/react-router' import { route } from '@/constants/routes' -import { useEffect, useState } from 'react' +import { useEffect, useState, useRef } from 'react' import { parseLogLine, readLogs } from '@/services/app' import { listen } from '@tauri-apps/api/event' @@ -23,6 +23,7 @@ const LOG_EVENT_NAME = 'log://log' function LogsViewer() { const [logs, setLogs] = useState([]) + const logsContainerRef = useRef(null) useEffect(() => { readLogs().then((logData) => { @@ -30,13 +31,25 @@ function LogsViewer() { .filter((log) => log?.target === SERVER_LOG_TARGET) .filter(Boolean) as LogEntry[] setLogs(logs) + + // Scroll to bottom after initial logs are loaded + setTimeout(() => { + scrollToBottom() + }, 100) }) let unsubscribe = () => {} listen(LOG_EVENT_NAME, (event) => { const { message } = event.payload as { message: string } const log: LogEntry | undefined = parseLogLine(message) if (log?.target === SERVER_LOG_TARGET) { - setLogs((prevLogs) => [...prevLogs, log]) + setLogs((prevLogs) => { + const newLogs = [...prevLogs, log] + // Schedule scroll to bottom after state update + setTimeout(() => { + scrollToBottom() + }, 0) + return newLogs + }) } }).then((unsub) => { unsubscribe = unsub @@ -46,6 +59,14 @@ function LogsViewer() { } }, []) + // Function to scroll to the bottom of the logs container + const scrollToBottom = () => { + if (logsContainerRef.current) { + const { scrollHeight, clientHeight } = logsContainerRef.current + logsContainerRef.current.scrollTop = scrollHeight - clientHeight + } + } + // Function to get appropriate color for log level const getLogLevelColor = (level: string) => { switch (level) { @@ -70,7 +91,7 @@ function LogsViewer() { return (
-
+
{logs.length === 0 ? (