diff --git a/neetbox/frontend/src/components/dashboard/project/logs.tsx b/neetbox/frontend/src/components/dashboard/project/logs.tsx index d5e7868..b920bfe 100644 --- a/neetbox/frontend/src/components/dashboard/project/logs.tsx +++ b/neetbox/frontend/src/components/dashboard/project/logs.tsx @@ -1,4 +1,4 @@ -import { useLayoutEffect, useRef } from "react"; +import React, { useEffect, useLayoutEffect, useRef, useState } from "react"; import { styled } from "styled-components"; import { LogData, useProjectLogs } from "../../../services/projects"; import "./logs.css"; @@ -7,26 +7,50 @@ interface Props { projectName: string; } -const LogsContainer = styled.div` - height: 40vh; - overflow-y: auto; -`; - -export function Logs({ projectName }: Props) { - const logs = useProjectLogs(projectName); +function AutoScrolling({ + style, + children, +}: React.PropsWithChildren<{ style: React.CSSProperties }>) { const containerRef = useRef(null!); + const [following, setFollowing] = useState(true); + const [renderingElement, setRenderingElement] = useState(children); + useEffect(() => { + const dom = containerRef.current; + if (dom) { + setFollowing( + Math.abs(dom.scrollHeight - dom.clientHeight - dom.scrollTop) < 5 + ); + } + setRenderingElement(children); + }, [children]); useLayoutEffect(() => { - containerRef.current.scroll({ top: containerRef.current.scrollHeight }); - }, [logs]); + const dom = containerRef.current; + if (following) { + dom.scroll({ top: dom.scrollHeight }); + } + }, [renderingElement, following]); return ( - - {logs.map((x) => ( - - ))} - +
+ {renderingElement} +
); } +export const Logs = React.memo(({ projectName }: Props) => { + const logs = useProjectLogs(projectName); + return ( + } + /> + ); +}); + +const LogItems = ({ logs }: { logs: LogData[] }) => { + console.info("logitems render logs count", logs.length); + return logs.map((x) => ); +}; + const LogItemContainer = styled.div` margin-bottom: 5px; font-family: "Courier New", Courier, monospace; @@ -63,7 +87,7 @@ function getColorFromWhom(whom: string) { return `hsl(${hue}, 70%, 80%)`; } -function LogItem({ data }: { data: LogData }) { +const LogItem = React.memo(({ data }: { data: LogData }) => { let { prefix } = data; if (!prefix) prefix = "LOG"; return ( @@ -81,4 +105,4 @@ function LogItem({ data }: { data: LogData }) { {data.msg} ); -} +}); diff --git a/neetbox/frontend/src/pages/console/proejctDashboard.tsx b/neetbox/frontend/src/pages/console/proejctDashboard.tsx index 98b74bf..9ac6f33 100644 --- a/neetbox/frontend/src/pages/console/proejctDashboard.tsx +++ b/neetbox/frontend/src/pages/console/proejctDashboard.tsx @@ -39,7 +39,7 @@ function ProjectDashboard() { Project "{projectName}" Logs - + {data.current ? ( <> Actions diff --git a/neetbox/frontend/src/pages/console/sidebar.tsx b/neetbox/frontend/src/pages/console/sidebar.tsx index c4cfb86..c82505a 100644 --- a/neetbox/frontend/src/pages/console/sidebar.tsx +++ b/neetbox/frontend/src/pages/console/sidebar.tsx @@ -6,7 +6,7 @@ import { Link, useLocation } from "react-router-dom"; export default function ConsoleNavBar() { const location = useLocation(); - const { isLoading, data, error } = useAPI("/list"); + const { isLoading, data, error } = useAPI("/list", { refreshInterval: 5000 }); return (