import {useEffect, useRef, useState} from "react"; import {create} from "zustand"; import formatDuration from "../../utils/formatDuration.ts"; import {type LogFilterPredicate, type LogRecord, useLogs} from "./useLogs.ts"; import Filters from "./Filters.tsx"; import {type Cell, useCell} from "../../utils/cellStore.ts"; import styles from "./Logging.module.css"; type LoggingSettings = { showRelativeTime: boolean; setShowRelativeTime: (showRelativeTime: boolean) => void; scrollToBottom: boolean; setScrollToBottom: (scrollToBottom: boolean) => void; }; const useLoggingSettings = create((set) => ({ showRelativeTime: false, setShowRelativeTime: (showRelativeTime: boolean) => set({ showRelativeTime }), scrollToBottom: true, setScrollToBottom: (scrollToBottom: boolean) => set({ scrollToBottom }), })); function LogMessage({ recordCell, onUpdate, }: { recordCell: Cell, onUpdate?: () => void, }) { const { showRelativeTime, setShowRelativeTime } = useLoggingSettings(); const record = useCell(recordCell); /** * Normalizes the log level number to a multiple of 10, for which there are CSS styles. */ const normalizedLevelNo = (() => { // By default, the highest level is 50 (CRITICAL). Custom levels can be higher, but we don't have more critical color. if (record.levelno >= 50) return 50; return Math.round(record.levelno / 10) * 10; })(); const normalizedName = record.name.split(".").pop() || record.name; useEffect(() => { if (onUpdate) onUpdate(); }, [record, onUpdate]); return
{record.levelname} setShowRelativeTime(!showRelativeTime)} >{showRelativeTime ? formatDuration(record.relativeCreated) : new Date(record.created * 1000).toLocaleTimeString() }
{normalizedName} {record.message}
; } function LogMessages({ recordCells }: { recordCells: Cell[] }) { const scrollableRef = useRef(null); const lastElementRef = useRef(null) const { scrollToBottom, setScrollToBottom } = useLoggingSettings(); useEffect(() => { if (!scrollableRef.current) return; const currentScrollableRef = scrollableRef.current; const handleScroll = () => setScrollToBottom(false); currentScrollableRef.addEventListener("wheel", handleScroll); currentScrollableRef.addEventListener("touchmove", handleScroll); return () => { currentScrollableRef.removeEventListener("wheel", handleScroll); currentScrollableRef.removeEventListener("touchmove", handleScroll); } }, [scrollableRef, setScrollToBottom]); function scrollLastElementIntoView(force = false) { if ((!scrollToBottom && !force) || !lastElementRef.current) return; lastElementRef.current.scrollIntoView({ behavior: "smooth" }); } return
    {recordCells.map((recordCell, i) => (
  1. ))}
{!scrollToBottom && }
; } export default function Logging() { const [filterPredicates, setFilterPredicates] = useState(new Map()); const { filteredLogs, distinctNames } = useLogs(filterPredicates) return

Logs

; }