From 769cc09906cb686eb0f191697f51bf0112b18b2f Mon Sep 17 00:00:00 2001 From: jialin Date: Sun, 30 Nov 2025 20:29:23 +0800 Subject: [PATCH] fix: logs are not fully loaded --- config/config.ts | 1 - src/components/logs-viewer/logs-list.tsx | 6 +- .../logs-viewer/virtual-log-list.tsx | 15 +-- src/components/seal-form/base/select.tsx | 98 +++++++++++-------- src/components/seal-form/seal-select.tsx | 4 +- src/locales/en-US/models.ts | 3 +- src/locales/ja-JP/models.ts | 6 +- src/locales/ru-RU/models.ts | 6 +- src/locales/zh-CN/models.ts | 3 +- src/pages/backends/config/index.ts | 12 +-- src/pages/backends/forms/versions-config.tsx | 2 +- .../components/add-credential.tsx | 33 ++++--- src/pages/llmodels/forms/backend.tsx | 26 ++++- src/pages/llmodels/forms/basic.tsx | 29 +----- 14 files changed, 133 insertions(+), 111 deletions(-) diff --git a/config/config.ts b/config/config.ts index 7ed4d0f5..2673605b 100644 --- a/config/config.ts +++ b/config/config.ts @@ -4,7 +4,6 @@ import { compressionPluginConfig, monacoPluginConfig } from './plugins'; import proxy from './proxy'; import routes from './routes'; import { getBranchInfo } from './utils'; -const CompressionWebpackPlugin = require('compression-webpack-plugin'); const versionInfo = getBranchInfo(); process.env.VERSION = JSON.stringify(versionInfo); diff --git a/src/components/logs-viewer/logs-list.tsx b/src/components/logs-viewer/logs-list.tsx index e8ba5820..c7b1f14a 100644 --- a/src/components/logs-viewer/logs-list.tsx +++ b/src/components/logs-viewer/logs-list.tsx @@ -64,9 +64,9 @@ const LogsList: React.FC = forwardRef((props, ref) => { const handleOnWheel = useCallback( (e: any) => { - const scrollTop = scrollEventElement?.scrollTop; - const scrollHeight = scrollEventElement?.scrollHeight; - const clientHeight = scrollEventElement?.clientHeight; + const scrollTop = scrollEventElement?.current.scrollTop; + const scrollHeight = scrollEventElement?.current.scrollHeight; + const clientHeight = scrollEventElement?.current.clientHeight; stopScroll.current = scrollTop + clientHeight <= scrollHeight; diff --git a/src/components/logs-viewer/virtual-log-list.tsx b/src/components/logs-viewer/virtual-log-list.tsx index 37604575..6bf5a563 100644 --- a/src/components/logs-viewer/virtual-log-list.tsx +++ b/src/components/logs-viewer/virtual-log-list.tsx @@ -1,4 +1,5 @@ import useSetChunkFetch from '@/hooks/use-chunk-fetch'; +import { useMemoizedFn } from 'ahooks'; import { Spin } from 'antd'; import classNames from 'classnames'; import _ from 'lodash'; @@ -177,7 +178,7 @@ const LogsViewer: React.FC = forwardRef((props, ref) => { }); }; - const handleOnScroll = useCallback( + const handleOnScroll = useMemoizedFn( async (data: { isTop: boolean; isBottom: boolean }) => { const { isTop, isBottom } = data; setIsAtTop(isTop); @@ -225,17 +226,7 @@ const LogsViewer: React.FC = forwardRef((props, ref) => { } else if (isBottom && page < totalPage) { // getNextPage(); } - }, - [ - loading, - logs.length, - pageSize, - enableScorllLoad, - page, - totalPage, - setScrollPos, - createChunkConnection - ] + } ); const debouncedScroll = useCallback( diff --git a/src/components/seal-form/base/select.tsx b/src/components/seal-form/base/select.tsx index 7132f553..4575e188 100644 --- a/src/components/seal-form/base/select.tsx +++ b/src/components/seal-form/base/select.tsx @@ -2,52 +2,68 @@ import IconFont from '@/components/icon-font'; import type { SelectProps } from 'antd'; import { Select } from 'antd'; import React, { forwardRef, useImperativeHandle } from 'react'; +import styled from 'styled-components'; import NotFoundContent from '../components/not-found-content'; -const BaseSelect: React.FC = forwardRef( - (props, ref) => { - const { notFoundContent, loading, ...restProps } = props; - const [isFocus, setIsFocus] = React.useState(false); - const inputRef = React.useRef(null); +const Footer = styled.div` + color: var(--ant-color-text-tertiary); + margin-top: 8px; + margin-bottom: 0; + padding: 8px 12px; + border-top: 1px solid var(--ant-color-split); +`; - useImperativeHandle(ref, () => ({ - ...(inputRef.current || ({} as any)) - })); +const BaseSelect: React.FC< + SelectProps & { ref?: any; footer?: React.ReactNode } +> = forwardRef((props, ref) => { + const { notFoundContent, loading, ...restProps } = props; + const [isFocus, setIsFocus] = React.useState(false); + const inputRef = React.useRef(null); - const handleFocus = (e: React.FocusEvent) => { - setIsFocus(true); - props.onFocus?.(e); - }; - const handleBlur = (e: React.FocusEvent) => { - setIsFocus(false); - props.onBlur?.(e); - }; - const renderSuffixIcon = () => { - if (props.suffixIcon) { - return props.suffixIcon; + useImperativeHandle(ref, () => ({ + ...(inputRef.current || ({} as any)) + })); + + const handleFocus = (e: React.FocusEvent) => { + setIsFocus(true); + props.onFocus?.(e); + }; + const handleBlur = (e: React.FocusEvent) => { + setIsFocus(false); + props.onBlur?.(e); + }; + const renderSuffixIcon = () => { + if (props.suffixIcon) { + return props.suffixIcon; + } + if (!props.showSearch) { + return ; + } + return !isFocus ? : undefined; + }; + + return ( + - } - ref={inputRef} - onFocus={handleFocus} - onBlur={handleBlur} - suffixIcon={renderSuffixIcon()} - /> - ); - } -); + /> + ); +}); export default BaseSelect; diff --git a/src/components/seal-form/seal-select.tsx b/src/components/seal-form/seal-select.tsx index 7e302278..23d2ac8b 100644 --- a/src/components/seal-form/seal-select.tsx +++ b/src/components/seal-form/seal-select.tsx @@ -10,7 +10,9 @@ import { SealFormItemProps } from './types'; import Wrapper from './wrapper'; import SelectWrapper from './wrapper/select'; -const SealSelect: React.FC = (props) => { +const SealSelect: React.FC< + SelectProps & SealFormItemProps & { footer?: React.ReactNode } +> = (props) => { const { label, placeholder, diff --git a/src/locales/en-US/models.ts b/src/locales/en-US/models.ts index cc62d249..67388828 100644 --- a/src/locales/en-US/models.ts +++ b/src/locales/en-US/models.ts @@ -267,5 +267,6 @@ export default { 'models.accessSettings.authed.tips': 'Accessible to all authenticated platform users.', 'models.accessSettings.allowedUsers.tips': - 'Only designated users can access the model.' + 'Only designated users can access the model.', + 'models.form.backendVersions.tips': `To use more versions, go to the {link} page and edit the backend to add versions.` }; diff --git a/src/locales/ja-JP/models.ts b/src/locales/ja-JP/models.ts index 51612f3e..5df8f7d1 100644 --- a/src/locales/ja-JP/models.ts +++ b/src/locales/ja-JP/models.ts @@ -267,7 +267,8 @@ export default { 'models.accessSettings.authed.tips': 'Accessible to all authenticated platform users.', 'models.accessSettings.allowedUsers.tips': - 'Only designated users can access the model.' + 'Only designated users can access the model.', + 'models.form.backendVersions.tips': `To use more versions, go to the {link} page and edit the backend to add versions.` }; // ========== To-Do: Translate Keys (Remove After Translation) ========== @@ -358,5 +359,6 @@ export default { // 68. 'models.form.backendVersion.deprecated': 'Deprecated', // 69. 'models.accessSettings.public.desc': 'Accessible to anyone without authentication.', // 70. 'models.accessSettings.authed.tips': 'Accessible to all authenticated platform users.', -// 71.'models.accessSettings.allowedUsers.tips': 'Only designated users can access the model.' +// 71.'models.accessSettings.allowedUsers.tips': 'Only designated users can access the model.', +// 72. 'models.form.backendVersions.tips': `To use more versions, go to the {link} page and edit the backend to add versions.` // ========== End of To-Do List ========== diff --git a/src/locales/ru-RU/models.ts b/src/locales/ru-RU/models.ts index 98f83408..57f1905d 100644 --- a/src/locales/ru-RU/models.ts +++ b/src/locales/ru-RU/models.ts @@ -272,11 +272,13 @@ export default { 'models.accessSettings.authed.tips': 'Accessible to all authenticated platform users.', 'models.accessSettings.allowedUsers.tips': - 'Only designated users can access the model.' + 'Only designated users can access the model.', + 'models.form.backendVersions.tips': `To use more versions, go to the {link} page and edit the backend to add versions.` }; // ========== To-Do: Translate Keys (Remove After Translation) ========== // 1. 'models.accessSettings.public.desc': 'Accessible to anyone without authentication.', // 2. 'models.accessSettings.authed.tips': 'Accessible to all authenticated platform users.', -// 3. 'models.accessSettings.allowedUsers.tips': 'Only designated users can access the model.' +// 3. 'models.accessSettings.allowedUsers.tips': 'Only designated users can access the model.', +// 4. 'models.form.backendVersions.tips': `To use more versions, go to the {link} page and edit the backend to add versions.` // ========== End of To-Do List ========== diff --git a/src/locales/zh-CN/models.ts b/src/locales/zh-CN/models.ts index 1ebbab93..095dab70 100644 --- a/src/locales/zh-CN/models.ts +++ b/src/locales/zh-CN/models.ts @@ -251,5 +251,6 @@ export default { 'models.form.backendVersion.deprecated': '已弃用', 'models.accessSettings.public.desc': '任何人无需认证即可访问。', 'models.accessSettings.authed.tips': '平台内所有已认证用户可访问。', - 'models.accessSettings.allowedUsers.tips': '仅允许选定的特定用户访问。' + 'models.accessSettings.allowedUsers.tips': '仅允许选定的特定用户访问。', + 'models.form.backendVersions.tips': `如需使用更多版本,请前往{link}页面并编辑对应的后端以添加版本。` }; diff --git a/src/pages/backends/config/index.ts b/src/pages/backends/config/index.ts index 20f0c12f..257ea793 100644 --- a/src/pages/backends/config/index.ts +++ b/src/pages/backends/config/index.ts @@ -152,37 +152,37 @@ export const frameworks = [ label: 'CANN', value: GPUDriverMap.ASCEND, tips: ManufacturerMap[GPUDriverMap.ASCEND], - locale: true + tipLocale: true }, { label: 'DTK', value: GPUDriverMap.HYGON, tips: ManufacturerMap[GPUDriverMap.HYGON], - locale: true + tipLocale: true }, { label: 'MACA', value: GPUDriverMap.METAX, tips: ManufacturerMap[GPUDriverMap.METAX], - locale: true + tipLocale: true }, { label: 'CoreX', value: GPUDriverMap.ILUVATAR, tips: ManufacturerMap[GPUDriverMap.ILUVATAR], - locale: true + tipLocale: true }, { label: 'MUSA', value: GPUDriverMap.MOORE_THREADS, tips: ManufacturerMap[GPUDriverMap.MOORE_THREADS], - locale: true + tipLocale: true }, { label: 'Neuware', value: GPUDriverMap.CAMBRICON, tips: ManufacturerMap[GPUDriverMap.CAMBRICON], - locale: true + tipLocale: true }, { label: 'CPU', diff --git a/src/pages/backends/forms/versions-config.tsx b/src/pages/backends/forms/versions-config.tsx index 4b767c1d..65d97f0e 100644 --- a/src/pages/backends/forms/versions-config.tsx +++ b/src/pages/backends/forms/versions-config.tsx @@ -163,7 +163,7 @@ const VersionsForm: React.FC = ({ {option.label} {data.tips ? ( - data.locale ? ( + data.tipLocale ? ( {` [${intl.formatMessage({ id: data.tips })}]`} ) : ( {` [${data.tips}]`} diff --git a/src/pages/cluster-management/components/add-credential.tsx b/src/pages/cluster-management/components/add-credential.tsx index fe18b7e3..d8b18f32 100644 --- a/src/pages/cluster-management/components/add-credential.tsx +++ b/src/pages/cluster-management/components/add-credential.tsx @@ -8,12 +8,24 @@ import { ExportOutlined } from '@ant-design/icons'; import { useIntl } from '@umijs/max'; import { Form, Typography } from 'antd'; import React, { useEffect } from 'react'; +import styled from 'styled-components'; import { ProviderType, ProviderValueMap } from '../config'; import { CredentialFormData as FormData, CredentialListItem as ListItem } from '../config/types'; +const ExtraContent = styled.div` + display: flex; + justify-content: flex-end; + align-items: center; + position: absolute; + bottom: 6px; + right: 32px; + z-index: 1; + background: var(--ant-color-bg-container); + padding-inline: 8px; +`; type AddModalProps = { title: string; action: PageActionType; @@ -105,18 +117,17 @@ const AddModal: React.FC = ({ id: 'clusters.credential.token' })} required={action === PageAction.CREATE} - labelExtra={ - - {intl.formatMessage({ id: 'clusters.button.genToken' })}{' '} - - - } > + + + {intl.formatMessage({ id: 'clusters.button.genToken' })}{' '} + + + )} diff --git a/src/pages/llmodels/forms/backend.tsx b/src/pages/llmodels/forms/backend.tsx index c24ec0b3..b4016887 100644 --- a/src/pages/llmodels/forms/backend.tsx +++ b/src/pages/llmodels/forms/backend.tsx @@ -1,8 +1,8 @@ import SealSelect from '@/components/seal-form/seal-select'; import TooltipList from '@/components/tooltip-list'; import useAppUtils from '@/hooks/use-app-utils'; -import { CaretDownOutlined } from '@ant-design/icons'; -import { useIntl } from '@umijs/max'; +import { CaretDownOutlined, InfoCircleOutlined } from '@ant-design/icons'; +import { useIntl, useNavigate } from '@umijs/max'; import { Form, Select } from 'antd'; import React, { useMemo } from 'react'; import styled from 'styled-components'; @@ -24,6 +24,7 @@ const CaretDownWrapper = styled.span` const BackendFields: React.FC = () => { const intl = useIntl(); + const navigate = useNavigate(); const { getRuleMessage } = useAppUtils(); const form = Form.useFormInstance(); const { onValuesChange, backendOptions, onBackendChange } = useFormContext(); @@ -193,6 +194,27 @@ const BackendFields: React.FC = () => { })} onChange={handleBackendVersionOnChange} label={intl.formatMessage({ id: 'models.form.backendVersion' })} + footer={ +
+
+ +
+
+ {intl.formatMessage( + { + id: 'models.form.backendVersions.tips' + }, + { + link: ( + navigate('/resources/backends')}> + {intl.formatMessage({ id: 'backends.title' })} + + ) + } + )} +
+
+ } > {renderVersionOptions( backendVersions.builtIn, diff --git a/src/pages/llmodels/forms/basic.tsx b/src/pages/llmodels/forms/basic.tsx index 091a5aa1..d655ceea 100644 --- a/src/pages/llmodels/forms/basic.tsx +++ b/src/pages/llmodels/forms/basic.tsx @@ -1,16 +1,14 @@ -import { clusterSessionAtom } from '@/atoms/clusters'; import SealInput from '@/components/seal-form/seal-input'; import SealSelect from '@/components/seal-form/seal-select'; -import { modelNameReg, PageAction } from '@/config'; +import { modelNameReg } from '@/config'; import { GPUSTACK_API_BASE_URL } from '@/config/settings'; import useAppUtils from '@/hooks/use-app-utils'; import { ClusterStatusLabelMap, ClusterStatusValueMap } from '@/pages/cluster-management/config'; -import { Link, useIntl } from '@umijs/max'; +import { useIntl } from '@umijs/max'; import { Form } from 'antd'; -import { useAtom } from 'jotai'; import { useMemo } from 'react'; import { sourceOptions } from '../config'; import { FormData } from '../config/types'; @@ -30,26 +28,6 @@ interface BasicFormProps { onSourceChange?: (value: string) => void; } -const NotFoundCredentialContent: React.FC = () => { - const [, setFromClusterCreation] = useAtom(clusterSessionAtom); - const intl = useIntl(); - const handleOnClick = () => { - setFromClusterCreation({ - firstAddWorker: false, - firstAddCluster: true - }); - }; - - return ( - - {intl.formatMessage({ id: 'noresult.resources.gotocluster' })} - - ); -}; - const BasicForm: React.FC = (props) => { const { fields = [], @@ -140,9 +118,6 @@ const BasicForm: React.FC = (props) => { > { - } onChange={handleClusterChange} label={intl.formatMessage({ id: 'clusters.title' })} options={clusterOptions}