import { PlayCircleOutlineRounded, PauseCircleOutlineRounded, SwapVertRounded, } from '@mui/icons-material' import { Box, Button, IconButton, MenuItem } from '@mui/material' import { useEffect, useMemo, useRef } from 'react' import { useTranslation } from 'react-i18next' import { BaseEmpty, BasePage, BaseSearchBox, BaseStyledSelect, VirtualList, type VirtualListHandle, } from '@/components/base' import LogItem from '@/components/log/log-item' import { useClashLog } from '@/hooks/use-clash-log' import { useLogData } from '@/hooks/use-log-data' import { usePageSearch } from '@/hooks/use-page-search' const LogPage = () => { const { t } = useTranslation() const [clashLog, setClashLog] = useClashLog() const enableLog = clashLog.enable const logState = clashLog.logFilter const logOrder = clashLog.logOrder ?? 'asc' const isDescending = logOrder === 'desc' const { searchState, match, onSearch } = usePageSearch('logs') const { response: { data: logData }, refreshGetClashLog, } = useLogData() const filterLogs = useMemo(() => { if (!logData || logData.length === 0) { return [] } const hasSearch = searchState.text.length > 0 if (!hasSearch && logState === 'all') return logData return logData.filter((data) => { if (logState !== 'all' && !data.type.includes(logState)) return false if (!hasSearch) return true const searchText = `${data.time || ''} ${data.type} ${data.payload}`.toLowerCase() return match(searchText) }) }, [logData, logState, match, searchState.text]) const filteredLogs = useMemo( () => (isDescending ? [...filterLogs].reverse() : filterLogs), [filterLogs, isDescending], ) const scrollRef = useRef({ isNearBottom: true }) const virtuosoRef = useRef(null) useEffect(() => { if (!isDescending && scrollRef.current.isNearBottom) { virtuosoRef.current?.scrollToIndex(filteredLogs.length - 1, { behavior: 'smooth', }) } }, [isDescending, filteredLogs.length]) const handleLogLevelChange = (newLevel: LogFilter) => { setClashLog((pre) => ({ ...pre!, logFilter: newLevel })) } const handleToggleLog = async () => { setClashLog((pre) => ({ ...pre!, enable: !enableLog })) } const handleToggleOrder = () => { setClashLog((pre) => ({ ...pre!, logOrder: pre!.logOrder === 'desc' ? 'asc' : 'desc', })) } return ( {enableLog ? ( ) : ( )} } > handleLogLevelChange(e.target.value as LogFilter)} > {t('shared.filters.logLevels.all')} {t('shared.filters.logLevels.debug')} {t('shared.filters.logLevels.info')} {t('shared.filters.logLevels.warn')} {t('shared.filters.logLevels.error')} {filteredLogs.length > 0 ? ( ( )} onScroll={(event) => { const element = event.currentTarget as HTMLDivElement scrollRef.current.isNearBottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 20 }} style={{ flex: 1 }} /> ) : ( )} ) } export default LogPage