mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-19 03:00:49 +08:00
feat(logs): optimize log loading with auto-prepend functionality
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useDeferredValue, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useDeferredValue, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
import type { PointerEvent as ReactPointerEvent } from 'react';
|
import type { PointerEvent as ReactPointerEvent } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Card } from '@/components/ui/Card';
|
import { Card } from '@/components/ui/Card';
|
||||||
@@ -643,6 +643,29 @@ export function LogsPage() {
|
|||||||
|
|
||||||
const canLoadMore = !isSearching && logState.visibleFrom > 0;
|
const canLoadMore = !isSearching && logState.visibleFrom > 0;
|
||||||
|
|
||||||
|
const prependVisibleLines = useCallback(() => {
|
||||||
|
const node = logViewerRef.current;
|
||||||
|
if (!node) return;
|
||||||
|
if (pendingPrependScrollRef.current) return;
|
||||||
|
if (isSearching) return;
|
||||||
|
|
||||||
|
setLogState((prev) => {
|
||||||
|
if (prev.visibleFrom <= 0) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingPrependScrollRef.current = {
|
||||||
|
scrollHeight: node.scrollHeight,
|
||||||
|
scrollTop: node.scrollTop,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
visibleFrom: Math.max(prev.visibleFrom - LOAD_MORE_LINES, 0),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, [isSearching]);
|
||||||
|
|
||||||
const handleLogScroll = () => {
|
const handleLogScroll = () => {
|
||||||
const node = logViewerRef.current;
|
const node = logViewerRef.current;
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
@@ -651,14 +674,7 @@ export function LogsPage() {
|
|||||||
if (pendingPrependScrollRef.current) return;
|
if (pendingPrependScrollRef.current) return;
|
||||||
if (node.scrollTop > LOAD_MORE_THRESHOLD_PX) return;
|
if (node.scrollTop > LOAD_MORE_THRESHOLD_PX) return;
|
||||||
|
|
||||||
pendingPrependScrollRef.current = {
|
prependVisibleLines();
|
||||||
scrollHeight: node.scrollHeight,
|
|
||||||
scrollTop: node.scrollTop,
|
|
||||||
};
|
|
||||||
setLogState((prev) => ({
|
|
||||||
...prev,
|
|
||||||
visibleFrom: Math.max(prev.visibleFrom - LOAD_MORE_LINES, 0),
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@@ -671,6 +687,53 @@ export function LogsPage() {
|
|||||||
pendingPrependScrollRef.current = null;
|
pendingPrependScrollRef.current = null;
|
||||||
}, [logState.visibleFrom]);
|
}, [logState.visibleFrom]);
|
||||||
|
|
||||||
|
const tryAutoLoadMoreUntilScrollable = useCallback(() => {
|
||||||
|
const node = logViewerRef.current;
|
||||||
|
if (!node) return;
|
||||||
|
if (!canLoadMore) return;
|
||||||
|
if (isSearching) return;
|
||||||
|
if (pendingPrependScrollRef.current) return;
|
||||||
|
|
||||||
|
const hasVerticalOverflow = node.scrollHeight > node.clientHeight + 1;
|
||||||
|
if (hasVerticalOverflow) return;
|
||||||
|
|
||||||
|
prependVisibleLines();
|
||||||
|
}, [canLoadMore, isSearching, prependVisibleLines]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (loading) return;
|
||||||
|
if (activeTab !== 'logs') return;
|
||||||
|
|
||||||
|
const raf = window.requestAnimationFrame(() => {
|
||||||
|
tryAutoLoadMoreUntilScrollable();
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
window.cancelAnimationFrame(raf);
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
activeTab,
|
||||||
|
loading,
|
||||||
|
tryAutoLoadMoreUntilScrollable,
|
||||||
|
filteredLines.length,
|
||||||
|
showRawLogs,
|
||||||
|
logState.visibleFrom,
|
||||||
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeTab !== 'logs') return;
|
||||||
|
|
||||||
|
const onResize = () => {
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
tryAutoLoadMoreUntilScrollable();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('resize', onResize);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', onResize);
|
||||||
|
};
|
||||||
|
}, [activeTab, tryAutoLoadMoreUntilScrollable]);
|
||||||
|
|
||||||
const copyLogLine = async (raw: string) => {
|
const copyLogLine = async (raw: string) => {
|
||||||
const ok = await copyToClipboard(raw);
|
const ok = await copyToClipboard(raw);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
|
|||||||
Reference in New Issue
Block a user