From c27707cbd18c38b4e8866e40d3399680ae190cb5 Mon Sep 17 00:00:00 2001 From: Supra4E8C Date: Wed, 29 Apr 2026 23:37:13 +0800 Subject: [PATCH] feat(logs): integrate useLocalStorage for auto-refresh and filter states --- src/hooks/useLocalStorage.ts | 27 +++++++++++++++++---------- src/pages/LogsPage.tsx | 9 ++++++--- src/pages/hooks/useLogFilters.ts | 20 ++++++++++++++------ 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/hooks/useLocalStorage.ts b/src/hooks/useLocalStorage.ts index 8830893..0454557 100644 --- a/src/hooks/useLocalStorage.ts +++ b/src/hooks/useLocalStorage.ts @@ -2,7 +2,7 @@ * LocalStorage Hook */ -import { useState } from 'react'; +import { useCallback, useState } from 'react'; export function useLocalStorage( key: string, @@ -18,15 +18,22 @@ export function useLocalStorage( } }); - const setValue = (value: T | ((val: T) => T)) => { - try { - const valueToStore = value instanceof Function ? value(storedValue) : value; - setStoredValue(valueToStore); - window.localStorage.setItem(key, JSON.stringify(valueToStore)); - } catch (error) { - console.error(`Error setting localStorage key "${key}":`, error); - } - }; + const setValue = useCallback( + (value: T | ((val: T) => T)) => { + setStoredValue((currentValue) => { + const valueToStore = value instanceof Function ? value(currentValue) : value; + + try { + window.localStorage.setItem(key, JSON.stringify(valueToStore)); + } catch (error) { + console.error(`Error setting localStorage key "${key}":`, error); + } + + return valueToStore; + }); + }, + [key] + ); return [storedValue, setValue]; } diff --git a/src/pages/LogsPage.tsx b/src/pages/LogsPage.tsx index 3053191..b132ae8 100644 --- a/src/pages/LogsPage.tsx +++ b/src/pages/LogsPage.tsx @@ -78,11 +78,14 @@ export function LogsPage() { const [logState, setLogState] = useState({ buffer: [], visibleFrom: 0 }); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); - const [autoRefresh, setAutoRefresh] = useState(false); + const [autoRefresh, setAutoRefresh] = useLocalStorage('logsPage.autoRefresh', false); const [searchQuery, setSearchQuery] = useState(''); const deferredSearchQuery = useDeferredValue(searchQuery); - const [hideManagementLogs, setHideManagementLogs] = useState(true); - const [showRawLogs, setShowRawLogs] = useState(false); + const [hideManagementLogs, setHideManagementLogs] = useLocalStorage( + 'logsPage.hideManagementLogs', + true + ); + const [showRawLogs, setShowRawLogs] = useLocalStorage('logsPage.showRawLogs', false); const [structuredFiltersExpanded, setStructuredFiltersExpanded] = useLocalStorage( 'logsPage.structuredFiltersExpanded', true diff --git a/src/pages/hooks/useLogFilters.ts b/src/pages/hooks/useLogFilters.ts index 0072276..4bbe9bd 100644 --- a/src/pages/hooks/useLogFilters.ts +++ b/src/pages/hooks/useLogFilters.ts @@ -1,4 +1,5 @@ -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo } from 'react'; +import { useLocalStorage } from '@/hooks/useLocalStorage'; import type { HttpMethod, ParsedLogLine, StatusGroup } from './logTypes'; import { resolveStatusGroup } from './logTypes'; @@ -28,9 +29,15 @@ interface UseLogFiltersReturn { export function useLogFilters(options: UseLogFiltersOptions): UseLogFiltersReturn { const { parsedLines } = options; - const [methodFilters, setMethodFilters] = useState([]); - const [statusFilters, setStatusFilters] = useState([]); - const [pathFilters, setPathFilters] = useState([]); + const [methodFilters, setMethodFilters] = useLocalStorage( + 'logsPage.methodFilters', + [] + ); + const [statusFilters, setStatusFilters] = useLocalStorage( + 'logsPage.statusFilters', + [] + ); + const [pathFilters, setPathFilters] = useLocalStorage('logsPage.pathFilters', []); const methodFilterSet = useMemo(() => new Set(methodFilters), [methodFilters]); const statusFilterSet = useMemo(() => new Set(statusFilters), [statusFilters]); @@ -70,14 +77,15 @@ export function useLogFilters(options: UseLogFiltersOptions): UseLogFiltersRetur }, [parsedLines]); useEffect(() => { + if (parsedLines.length === 0) return; + const validPathSet = new Set(pathOptions.map((item) => item.path)); - // eslint-disable-next-line react-hooks/set-state-in-effect setPathFilters((prev) => { if (prev.length === 0) return prev; const next = prev.filter((path) => validPathSet.has(path)); return next.length === prev.length ? prev : next; }); - }, [pathOptions]); + }, [parsedLines.length, pathOptions, setPathFilters]); const toggleMethodFilter = (method: HttpMethod) => { setMethodFilters((prev) =>