import { PlayCircleOutlineRounded, PauseCircleOutlineRounded, SwapVertRounded, } from '@mui/icons-material' import { Box, Button, IconButton, MenuItem } from '@mui/material' import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { Virtuoso } from 'react-virtuoso' import { BaseEmpty, BasePage, BaseSearchBox, BaseStyledSelect, type SearchState, } from '@/components/base' import LogItem from '@/components/log/log-item' import { useClashLog } from '@/hooks/use-clash-log' import { useLogData } from '@/hooks/use-log-data' 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 [match, setMatch] = useState(() => (_: string) => true) const [searchState, setSearchState] = useState() const { response: { data: logData }, refreshGetClashLog, } = useLogData() const filterLogs = useMemo(() => { if (!logData || logData.length === 0) { return [] } // Server-side filtering handles level filtering via query parameters // We only need to apply search filtering here return logData.filter((data) => { // 构建完整的搜索文本,包含时间、类型和内容 const searchText = `${data.time || ''} ${data.type} ${data.payload}`.toLowerCase() const matchesSearch = match(searchText) return ( (logState == 'all' ? true : data.type.includes(logState)) && matchesSearch ) }) }, [logData, logState, match]) const filteredLogs = useMemo( () => (isDescending ? [...filterLogs].reverse() : filterLogs), [filterLogs, isDescending], ) const handleLogLevelChange = (newLevel: string) => { setClashLog((pre: any) => ({ ...pre, logFilter: newLevel })) } const handleToggleLog = async () => { setClashLog((pre: any) => ({ ...pre, enable: !enableLog })) } const handleToggleOrder = () => { setClashLog((pre: any) => ({ ...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')} { setMatch(() => matcher) setSearchState(state) }} /> {filteredLogs.length > 0 ? ( ( )} followOutput={isDescending ? false : 'smooth'} /> ) : ( )} ) } export default LogPage