diff --git a/enclave-manager/web/src/components/enclaves/logs/LogViewer.tsx b/enclave-manager/web/src/components/enclaves/logs/LogViewer.tsx index a690bc8bb4..6664a77aff 100644 --- a/enclave-manager/web/src/components/enclaves/logs/LogViewer.tsx +++ b/enclave-manager/web/src/components/enclaves/logs/LogViewer.tsx @@ -94,7 +94,7 @@ export const LogViewer = ({ } }; - const handleSearchStateChange = (updater: ((prevState: SearchState) => SearchState) | SearchState) => { + const handleSearchStateChange = useCallback((updater: ((prevState: SearchState) => SearchState) | SearchState) => { setSearchState((prevState) => { const newState = typeof updater === "object" ? updater : updater(prevState); if ( @@ -106,7 +106,7 @@ export const LogViewer = ({ } return newState; }); - }; + }, []); const getLogsValue = () => { return logLines @@ -213,6 +213,8 @@ const SearchControls = ({ searchState, onChangeSearchState, logLines }: SearchCo const searchRef: MutableRefObject = useRef(null); const [showSearchForm, setShowSearchForm] = useState(false); + const maybeCurrentSearchIndex = searchState.type === "success" ? searchState.currentSearchIndex : null; + const updateMatches = useCallback( (searchTerm: string) => { if (isNotEmpty(searchTerm)) { @@ -247,7 +249,7 @@ const SearchControls = ({ searchState, onChangeSearchState, logLines }: SearchCo [logLines, onChangeSearchState], ); - const debouncedUpdateMatches = useMemo(() => debounce(updateMatches, 100), [updateMatches]); + const debouncedUpdateMatches = useMemo(() => debounce(updateMatches, 300), [updateMatches]); const handleOnChange = (e: ChangeEvent) => { onChangeSearchState((state) => ({ ...state, rawSearchTerm: e.target.value })); @@ -256,35 +258,29 @@ const SearchControls = ({ searchState, onChangeSearchState, logLines }: SearchCo const updateSearchIndexBounded = useCallback( (newIndex: number) => { - if (searchState.type !== "success") { - return; - } - if (newIndex > searchState.searchMatchesIndices.length - 1) { - newIndex = 0; - } - if (newIndex < 0) { - newIndex = searchState.searchMatchesIndices.length - 1; - } - onChangeSearchState((state) => ({ ...state, currentSearchIndex: newIndex })); + onChangeSearchState((searchState) => { + if (searchState.type !== "success" || searchState.searchMatchesIndices.length === 0) { + return searchState; + } + if (newIndex > searchState.searchMatchesIndices.length - 1) { + newIndex = 0; + } + if (newIndex < 0) { + newIndex = searchState.searchMatchesIndices.length - 1; + } + return { ...searchState, currentSearchIndex: newIndex }; + }); }, - [onChangeSearchState, searchState], + [onChangeSearchState], ); const handlePriorMatchClick = useCallback(() => { - updateSearchIndexBounded( - searchState.type === "success" && isDefined(searchState.currentSearchIndex) - ? searchState.currentSearchIndex - 1 - : 0, - ); - }, [updateSearchIndexBounded, searchState]); + updateSearchIndexBounded(isDefined(maybeCurrentSearchIndex) ? maybeCurrentSearchIndex - 1 : 0); + }, [updateSearchIndexBounded, maybeCurrentSearchIndex]); const handleNextMatchClick = useCallback(() => { - updateSearchIndexBounded( - searchState.type === "success" && isDefined(searchState.currentSearchIndex) - ? searchState.currentSearchIndex + 1 - : 0, - ); - }, [updateSearchIndexBounded, searchState]); + updateSearchIndexBounded(isDefined(maybeCurrentSearchIndex) ? maybeCurrentSearchIndex + 1 : 0); + }, [updateSearchIndexBounded, maybeCurrentSearchIndex]); const handleClearSearch = useCallback(() => { onChangeSearchState({ type: "init", rawSearchTerm: "" });