diff --git a/.gitignore b/.gitignore index 78b73194..b2c0c9ab 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ /.mfsu .swc .DS_Store +.idea diff --git a/config/config.ts b/config/config.ts index 36546891..6b51745c 100644 --- a/config/config.ts +++ b/config/config.ts @@ -19,6 +19,16 @@ export default defineConfig({ history: { type: 'hash' }, + analyze: { + analyzerMode: 'server', + analyzerPort: 8888, + openAnalyzer: true, + // generate stats file while ANALYZE_DUMP exist + generateStatsFile: false, + statsFilename: 'stats.json', + logLevel: 'info', + defaultSizes: 'parsed' // stat // gzip + }, base: process.env.npm_config_base || '/', ...(isProduction ? { diff --git a/src/components/logs-viewer/logs-inner.tsx b/src/components/logs-viewer/logs-inner.tsx index 41f24a52..6e799eca 100644 --- a/src/components/logs-viewer/logs-inner.tsx +++ b/src/components/logs-viewer/logs-inner.tsx @@ -26,10 +26,9 @@ const LogsInner: React.FC = (props) => { index: data.length - 1, align: 'bottom' }); - console.log('scrollToBottom', stopScroll.current, data.length); } }, 200), - [scroller.current, stopScroll.current, data] + [data, scroller.current, stopScroll.current] ); const debounceResetStopScroll = _.debounce(() => { @@ -66,7 +65,6 @@ const LogsInner: React.FC = (props) => { (e: any) => { const isBottom = isScrollBottom(logsWrapper.current); const isTop = isScrollTop(logsWrapper.current); - console.log('isBottom===', isBottom); if (isBottom) { stopScroll.current = false; } else { @@ -79,10 +77,7 @@ const LogsInner: React.FC = (props) => { ); useEffect(() => { - if (!stopScroll.current && data.length > 0) { - updataPositionToBottom(); - console.log('updataPositionToBottom', stopScroll.current); - } + updataPositionToBottom(); }, [updataPositionToBottom]); useEffect(() => { @@ -115,7 +110,7 @@ const LogsInner: React.FC = (props) => { } }} > - {(item: any) => ( + {(item: any, index: number) => (
{item.content}
diff --git a/src/components/logs-viewer/parse-ansi.ts b/src/components/logs-viewer/parse-ansi.ts index 7a581afc..320a7505 100644 --- a/src/components/logs-viewer/parse-ansi.ts +++ b/src/components/logs-viewer/parse-ansi.ts @@ -97,7 +97,6 @@ const useParseAnsi = () => { break; case 'J': // clear the screen if (n === 2) { - console.log('clear===='); screen = [['']]; cursorRow = 0; cursorCol = 0; @@ -132,6 +131,7 @@ const useParseAnsi = () => { uid: setId() }); } + result.push({ content: output, uid: setId() diff --git a/src/components/logs-viewer/styles/index.less b/src/components/logs-viewer/styles/index.less index 78d1893b..8747e6fc 100644 --- a/src/components/logs-viewer/styles/index.less +++ b/src/components/logs-viewer/styles/index.less @@ -5,6 +5,44 @@ position: absolute; top: 16px; right: 16px; + width: 40px; + height: 130px; + + .pg-inner { + position: relative; + + &::before { + content: ''; + position: absolute; + top: 30px; + bottom: 30px; + right: 0; + width: 100px; + height: 60px; + + &:hover { + .pagination { + display: flex; + } + } + } + + .pagination { + display: none; + } + + &:hover { + .pagination { + display: flex; + } + } + + &.at-top { + .pagination { + display: flex; + } + } + } } .loading { @@ -18,10 +56,6 @@ display: flex; justify-content: center; background-color: rgba(255, 255, 255, 25%); - - .ant-spin-dot-holder { - color: rgba(255, 255, 255, 90%); - } } .copy { diff --git a/src/components/logs-viewer/virtual-log-list.tsx b/src/components/logs-viewer/virtual-log-list.tsx index 786e5bbb..85545418 100644 --- a/src/components/logs-viewer/virtual-log-list.tsx +++ b/src/components/logs-viewer/virtual-log-list.tsx @@ -1,9 +1,16 @@ import useSetChunkFetch from '@/hooks/use-chunk-fetch'; -import useSetChunkRequest from '@/hooks/use-chunk-request'; import { Spin } from 'antd'; import classNames from 'classnames'; import _ from 'lodash'; -import { memo, useCallback, useEffect, useRef, useState } from 'react'; +import { + forwardRef, + memo, + useCallback, + useEffect, + useImperativeHandle, + useRef, + useState +} from 'react'; import { controlSeqRegex, replaceLineRegex } from './config'; import LogsInner from './logs-inner'; import LogsPagination from './logs-pagination'; @@ -15,28 +22,38 @@ interface LogsViewerProps { content?: string; url: string; params?: object; + ref?: any; diffHeight?: number; } -const LogsViewer: React.FC = (props) => { +const LogsViewer: React.FC = forwardRef((props, ref) => { const { diffHeight, url } = props; const { pageSize, page, setPage, setTotalPage, totalPage } = useLogsPagination(); - const { setChunkRequest } = useSetChunkRequest(); const { setChunkFetch } = useSetChunkFetch(); const chunkRequedtRef = useRef(null); const cacheDataRef = useRef(''); const [logs, setLogs] = useState([]); const logParseWorker = useRef(null); const tail = useRef(pageSize); - const isLoadend = useRef(false); + const [isLoadend, setIsLoadend] = useState(false); const [loading, setLoading] = useState(false); const [isAtTop, setIsAtTop] = useState(false); + useImperativeHandle(ref, () => ({ + abort() { + chunkRequedtRef.current?.current?.abort?.(); + } + })); + useEffect(() => { logParseWorker.current?.terminate?.(); logParseWorker.current = new Worker( - new URL('./parse-worker.ts', import.meta.url) + // @ts-ignore + new URL('./parse-worker.ts', import.meta.url), + { + type: 'module' + } ); logParseWorker.current.onmessage = (event: any) => { @@ -53,7 +70,7 @@ const LogsViewer: React.FC = (props) => { const debounceLoading = _.debounce(() => { setLoading(false); - }, 100); + }, 200); const isClean = useCallback((input: string) => { let match = controlSeqRegex.exec(input) || []; @@ -64,9 +81,9 @@ const LogsViewer: React.FC = (props) => { const getLastPage = useCallback( (data: string) => { - const list = _.split(data, '\n'); - isLoadend.current = list.length < pageSize; - console.log('isLoadend.current===', isLoadend.current, list.length); + const list = _.split(data.trim(), '\n'); + console.log('list.length', list.length); + if (list.length <= pageSize) { setTotalPage(1); return data; @@ -84,7 +101,7 @@ const LogsViewer: React.FC = (props) => { ); const getPrePage = useCallback(() => { - const list = _.split(cacheDataRef.current, '\n'); + const list = _.split(cacheDataRef.current.trim(), '\n'); let newPage = page - 1; if (newPage < 1) { newPage = 1; @@ -99,7 +116,7 @@ const LogsViewer: React.FC = (props) => { }, [page, pageSize]); const getNextPage = useCallback(() => { - const list = _.split(cacheDataRef.current, '\n'); + const list = _.split(cacheDataRef.current.trim(), '\n'); let newPage = page + 1; if (newPage > totalPage) { newPage = totalPage; @@ -146,17 +163,18 @@ const LogsViewer: React.FC = (props) => { }; const handleOnScroll = useCallback( - (isTop: boolean) => { - setIsAtTop(isTop && isLoadend.current); - if (loading || isLoadend.current) { + async (isTop: boolean) => { + setIsAtTop(isTop); + if (loading || isLoadend || logs.length < pageSize) { return; } - if (isTop && !isLoadend.current) { + if (isTop && !isLoadend) { tail.current = undefined; createChunkConnection(); + setIsLoadend(true); } }, - [loading, isLoadend.current] + [loading, isLoadend, logs.length, pageSize] ); useEffect(() => { @@ -182,19 +200,26 @@ const LogsViewer: React.FC = (props) => { loading: loading && isAtTop })} > - {totalPage > 1 && isAtTop && ( + {totalPage > 1 && (
- +
+ +
)} ); -}; +}); export default memo(LogsViewer); diff --git a/src/hooks/use-chunk-fetch.ts b/src/hooks/use-chunk-fetch.ts index f949a2c3..262b313c 100644 --- a/src/hooks/use-chunk-fetch.ts +++ b/src/hooks/use-chunk-fetch.ts @@ -8,6 +8,7 @@ interface RequestConfig { beforeReconnect?: () => void; params?: object; byLine?: boolean; + watch?: boolean; contentType?: 'json' | 'text'; } @@ -70,6 +71,7 @@ const useSetChunkFetch = () => { const fetchChunkRequest = async ({ url, handler, + watch, byLine = false, params = {} }: RequestConfig) => { @@ -79,7 +81,7 @@ const useSetChunkFetch = () => { const response = await fetch( `v1${url}?${qs.stringify({ ...params, - watch: true + watch: watch === undefined ? true : watch })}`, { method: 'GET', diff --git a/src/pages/llmodels/components/view-logs-modal.tsx b/src/pages/llmodels/components/view-logs-modal.tsx index 9b332dcf..1c62116b 100644 --- a/src/pages/llmodels/components/view-logs-modal.tsx +++ b/src/pages/llmodels/components/view-logs-modal.tsx @@ -17,6 +17,7 @@ const ViewCodeModal: React.FC = (props) => { height: 420 }); const isFullScreenRef = React.useRef(false); + const logsViewerRef = React.useRef(null); const intl = useIntl(); const viewportHeight = window.innerHeight; const viewHeight = viewportHeight - 86; @@ -31,6 +32,11 @@ const ViewCodeModal: React.FC = (props) => { }); }, []); + const handleCancel = useCallback(() => { + logsViewerRef.current?.abort(); + onCancel(); + }, [onCancel]); + useEffect(() => { if (open) { isFullScreenRef.current = false; @@ -53,7 +59,7 @@ const ViewCodeModal: React.FC = (props) => { } open={open} centered={true} - onCancel={onCancel} + onCancel={handleCancel} destroyOnClose={true} closeIcon={true} maskClosable={false} @@ -67,6 +73,7 @@ const ViewCodeModal: React.FC = (props) => { footer={null} >