diff --git a/react-ui/src/hooks/resource.ts b/react-ui/src/hooks/resource.ts index cb4434ab..6331edab 100644 --- a/react-ui/src/hooks/resource.ts +++ b/react-ui/src/hooks/resource.ts @@ -49,7 +49,10 @@ export function useComputingResource() { // 根据 standard 获取 description const getDescription = useCallback( - (standard: string) => { + (standard?: string) => { + if (!standard) { + return undefined; + } return resourceStandardList.find((item) => item.standard === standard)?.description; }, [resourceStandardList], diff --git a/react-ui/src/pages/Authorize/index.tsx b/react-ui/src/pages/Authorize/index.tsx index e42a0f1b..2caf3195 100644 --- a/react-ui/src/pages/Authorize/index.tsx +++ b/react-ui/src/pages/Authorize/index.tsx @@ -3,7 +3,7 @@ import { loginByOauth2Req } from '@/services/auth'; import { to } from '@/utils/promise'; import { history, useModel, useSearchParams } from '@umijs/max'; import { message } from 'antd'; -import { useEffect } from 'react'; +import { useCallback, useEffect } from 'react'; import { flushSync } from 'react-dom'; import styles from './index.less'; @@ -12,12 +12,21 @@ function Authorize() { const [searchParams] = useSearchParams(); const code = searchParams.get('code'); const redirect = searchParams.get('redirect'); - useEffect(() => { - loginByOauth2(); - }, []); + + const fetchUserInfo = useCallback(async () => { + const userInfo = await initialState?.fetchUserInfo?.(); + if (userInfo) { + flushSync(() => { + setInitialState((s) => ({ + ...s, + currentUser: userInfo, + })); + }); + } + }, [initialState, setInitialState]); // 登录 - const loginByOauth2 = async () => { + const loginByOauth2 = useCallback(async () => { const params = { code, }; @@ -29,19 +38,11 @@ function Authorize() { await fetchUserInfo(); history.push(redirect || '/'); } - }; + }, [fetchUserInfo, redirect, code]); - const fetchUserInfo = async () => { - const userInfo = await initialState?.fetchUserInfo?.(); - if (userInfo) { - flushSync(() => { - setInitialState((s) => ({ - ...s, - currentUser: userInfo, - })); - }); - } - }; + useEffect(() => { + loginByOauth2(); + }, [loginByOauth2]); return
; } diff --git a/react-ui/src/pages/AutoML/Instance/index.tsx b/react-ui/src/pages/AutoML/Instance/index.tsx index 8b525bdd..2dead784 100644 --- a/react-ui/src/pages/AutoML/Instance/index.tsx +++ b/react-ui/src/pages/AutoML/Instance/index.tsx @@ -39,6 +39,7 @@ function AutoMLInstance() { return () => { closeSSE(); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // 获取实验实例详情 @@ -83,9 +84,6 @@ function AutoMLInstance() { const setupSSE = (name: string, namespace: string) => { const { origin } = location; - // if (process.env.NODE_ENV === 'development') { - // origin = 'http://172.20.32.197:31213'; - // } const params = encodeURIComponent(`metadata.namespace=${namespace},metadata.name=${name}`); const evtSource = new EventSource( `${origin}/api/v1/realtimeStatus?listOptions.fieldSelector=${params}`, diff --git a/react-ui/src/pages/Experiment/Info/index.jsx b/react-ui/src/pages/Experiment/Info/index.jsx index e05480df..f0cf9ae6 100644 --- a/react-ui/src/pages/Experiment/Info/index.jsx +++ b/react-ui/src/pages/Experiment/Info/index.jsx @@ -21,7 +21,6 @@ function ExperimentText() { const [experimentIns, setExperimentIns] = useState(undefined); const [experimentNodeData, setExperimentNodeData, experimentNodeDataRef] = useStateRef(undefined); const graphRef = useRef(); - const timerRef = useRef(); const workflowRef = useRef(); const locationParams = useParams(); // 新版本获取路由参数接口 const [paramsModalOpen, openParamsModal, closeParamsModal] = useVisible(false); @@ -36,6 +35,16 @@ function ExperimentText() { initGraph(); getWorkflow(); + return () => { + if (evtSourceRef.current) { + evtSourceRef.current.close(); + evtSourceRef.current = null; + } + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { const changeSize = () => { if (!graph || graph.get('destroyed')) return; if (!graphRef.current) return; @@ -46,13 +55,6 @@ function ExperimentText() { window.addEventListener('resize', changeSize); return () => { window.removeEventListener('resize', changeSize); - if (timerRef.current) { - clearTimeout(timerRef.current); - } - if (evtSourceRef.current) { - evtSourceRef.current.close(); - evtSourceRef.current = null; - } }; }, []); diff --git a/react-ui/src/pages/Experiment/components/LogGroup/index.tsx b/react-ui/src/pages/Experiment/components/LogGroup/index.tsx index dfedac5c..e69b4773 100644 --- a/react-ui/src/pages/Experiment/components/LogGroup/index.tsx +++ b/react-ui/src/pages/Experiment/components/LogGroup/index.tsx @@ -46,12 +46,94 @@ function LogGroup({ setHasRun(true); } + // 进入页面时,滚动到底部 useEffect(() => { + scrollToBottom(false); + }, []); + + useEffect(() => { + // 建立 socket 连接 + const setupSockect = () => { + let { host } = location; + if (process.env.NODE_ENV === 'development') { + host = '172.20.32.197:31213'; + } + const socket = new WebSocket( + `ws://${host}/newlog/realtimeLog?start=${start_time}&query={pod="${pod_name}"}`, + ); + + socket.addEventListener('open', () => { + console.log('WebSocket is open now.'); + }); + + socket.addEventListener('close', (event) => { + console.log('WebSocket is closed:', event); + // 有时候会出现连接失败,重试 3 次 + if (event.code !== 1000 && retryRef.current > 0) { + retryRef.current -= 1; + setTimeout(() => { + setupSockect(); + }, 2 * 1000); + } + }); + + socket.addEventListener('error', (event) => { + console.error('WebSocket error observed:', event); + }); + + socket.addEventListener('message', (event) => { + // console.log('message received.', event); + if (!event.data) { + return; + } + try { + const data = JSON.parse(event.data); + const streams = data.streams; + if (!streams || !Array.isArray(streams)) { + return; + } + let startTime = start_time; + const logContent = streams.reduce((result, item) => { + const values = item.values; + return ( + result + + values.reduce((prev: string, cur: [string, string]) => { + const [time, value] = cur; + startTime = time; + const str = `[${dayjs(Number(time) / 1.0e6).format( + 'YYYY-MM-DD HH:mm:ss', + )}] ${value}`; + return prev + str; + }, '') + ); + }, ''); + const logDetail: Log = { + start_time: startTime!, + log_content: logContent, + pod_name: pod_name, + }; + setLogList((oldList) => oldList.concat(logDetail)); + if (!isMouseDownRef.current && logContent) { + setTimeout(() => { + scrollToBottom(); + }, 100); + } + } catch (error) { + console.error('JSON parse error: ', error); + } + }); + + socketRef.current = socket; + }; + if (status === ExperimentStatus.Running) { setupSockect(); } - scrollToBottom(false); - }, [status]); + + return () => { + closeSocket(); + }; + }, [status, start_time, pod_name, isMouseDownRef, setLogList]); // 鼠标拖到中不滚动到底部 useEffect(() => { @@ -66,7 +148,6 @@ function LogGroup({ return () => { document.removeEventListener('mousedown', mouseDown); document.removeEventListener('mouseup', mouseUp); - closeSocket(); }; }, [setIsMouseDown]); @@ -120,78 +201,7 @@ function LogGroup({ requestExperimentPodsLog(); }; - // 建立 socket 连接 - const setupSockect = () => { - let { host } = location; - if (process.env.NODE_ENV === 'development') { - host = '172.20.32.197:31213'; - } - const socket = new WebSocket( - `ws://${host}/newlog/realtimeLog?start=${start_time}&query={pod="${pod_name}"}`, - ); - - socket.addEventListener('open', () => { - console.log('WebSocket is open now.'); - }); - - socket.addEventListener('close', (event) => { - console.log('WebSocket is closed:', event); - // 有时候会出现连接失败,重试 3 次 - if (event.code !== 1000 && retryRef.current > 0) { - retryRef.current -= 1; - setTimeout(() => { - setupSockect(); - }, 2 * 1000); - } - }); - - socket.addEventListener('error', (event) => { - console.error('WebSocket error observed:', event); - }); - - socket.addEventListener('message', (event) => { - // console.log('message received.', event); - if (!event.data) { - return; - } - try { - const data = JSON.parse(event.data); - const streams = data.streams; - if (!streams || !Array.isArray(streams)) { - return; - } - let startTime = start_time; - const logContent = streams.reduce((result, item) => { - const values = item.values; - return ( - result + - values.reduce((prev: string, cur: [string, string]) => { - const [time, value] = cur; - startTime = time; - const str = `[${dayjs(Number(time) / 1.0e6).format('YYYY-MM-DD HH:mm:ss')}] ${value}`; - return prev + str; - }, '') - ); - }, ''); - const logDetail: Log = { - start_time: startTime!, - log_content: logContent, - pod_name: pod_name, - }; - setLogList((oldList) => oldList.concat(logDetail)); - if (!isMouseDownRef.current && logContent) { - setTimeout(() => { - scrollToBottom(); - }, 100); - } - } catch (error) { - console.error('JSON parse error: ', error); - } - }); - - socketRef.current = socket; - }; - + // 关闭 socket const closeSocket = () => { if (socketRef.current) { socketRef.current.close(1000, 'completed'); diff --git a/react-ui/src/pages/HyperParameter/Instance/index.tsx b/react-ui/src/pages/HyperParameter/Instance/index.tsx index aa206059..5e4c5ab7 100644 --- a/react-ui/src/pages/HyperParameter/Instance/index.tsx +++ b/react-ui/src/pages/HyperParameter/Instance/index.tsx @@ -22,6 +22,8 @@ enum TabKeys { History = 'history', } +const NodePrefix = 'workflow'; + function HyperParameterInstance() { const [experimentInfo, setExperimentInfo] = useState