From a1a7979fb39c4a1ca55afa87c4db245f8ebfa308 Mon Sep 17 00:00:00 2001 From: jialin Date: Thu, 5 Feb 2026 11:54:20 +0800 Subject: [PATCH] fix: update open playground btn --- src/assets/styles/common.less | 5 ++ src/components/icon-font/index.tsx | 2 +- src/pages/_components/grafana-icon.tsx | 37 ++++++++ .../backends/community/commnity-backends.tsx | 6 +- src/pages/cluster-management/config/index.ts | 47 ---------- .../hooks/use-cluster-columns.tsx | 55 +++++++++++- .../llmodels/components/instance-item.tsx | 53 +++++------- src/pages/llmodels/components/table-list.tsx | 10 +-- .../llmodels/components/update-modal.tsx | 1 + src/pages/llmodels/config/button-actions.ts | 41 --------- src/pages/llmodels/config/form-context.ts | 1 + src/pages/llmodels/forms/advance-config.tsx | 61 +++++++------ src/pages/llmodels/forms/index.tsx | 3 + src/pages/llmodels/hooks/index.ts | 6 -- .../llmodels/hooks/use-models-columns.tsx | 58 ++++++++++++- src/pages/resources/hooks/use-gpu-columns.tsx | 40 +++++---- .../resources/hooks/use-grafana-link.tsx | 8 +- .../resources/hooks/use-worker-columns.tsx | 86 ++++++++++++------- 18 files changed, 302 insertions(+), 218 deletions(-) create mode 100644 src/pages/_components/grafana-icon.tsx diff --git a/src/assets/styles/common.less b/src/assets/styles/common.less index 15b35616..7f5fc96d 100644 --- a/src/assets/styles/common.less +++ b/src/assets/styles/common.less @@ -104,6 +104,11 @@ display: flex; } +.flex-full { + display: flex; + flex: 1; +} + // space-between .flex-between { display: flex; diff --git a/src/components/icon-font/index.tsx b/src/components/icon-font/index.tsx index 1d544043..d38cc3d7 100644 --- a/src/components/icon-font/index.tsx +++ b/src/components/icon-font/index.tsx @@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons'; // import './iconfont/iconfont.js'; const IconFont = createFromIconfontCN({ - scriptUrl: '//at.alicdn.com/t/c/font_4613488_c3lajf3mdtk.js' + scriptUrl: '//at.alicdn.com/t/c/font_4613488_i617h54opsm.js' }); export default IconFont; diff --git a/src/pages/_components/grafana-icon.tsx b/src/pages/_components/grafana-icon.tsx new file mode 100644 index 00000000..815bca95 --- /dev/null +++ b/src/pages/_components/grafana-icon.tsx @@ -0,0 +1,37 @@ +import React from 'react'; + +interface GrafanaIconProps { + style?: React.SVGProps; +} +const GrafanaIcon: React.FC = ({ style }) => { + return ( + + + + + + + + + + ); +}; + +export default GrafanaIcon; diff --git a/src/pages/backends/community/commnity-backends.tsx b/src/pages/backends/community/commnity-backends.tsx index 44f6996d..b800e2ae 100644 --- a/src/pages/backends/community/commnity-backends.tsx +++ b/src/pages/backends/community/commnity-backends.tsx @@ -98,7 +98,11 @@ const CommunityBackends: React.FC<{ > <> {data.enabled && ( - + {intl.formatMessage({ id: 'common.status.enabled' })} )} diff --git a/src/pages/cluster-management/config/index.ts b/src/pages/cluster-management/config/index.ts index 532cab9c..6d2aeb67 100644 --- a/src/pages/cluster-management/config/index.ts +++ b/src/pages/cluster-management/config/index.ts @@ -88,53 +88,6 @@ export const credentialActionList = [ } ]; -export const clusterActionList = [ - { - key: 'edit', - label: 'common.button.edit', - icon: icons.EditOutlined - }, - { - label: 'resources.metrics.details', - key: 'metrics', - icon: icons.Metrics - }, - { - key: 'add_worker', - label: 'resources.button.create', - provider: ProviderValueMap.Docker, - locale: true, - icon: icons.DockerOutlined - }, - { - key: 'register_cluster', - label: 'clusters.button.register', - provider: ProviderValueMap.Kubernetes, - locale: true, - icon: icons.KubernetesOutlined - }, - { - key: 'addPool', - label: 'clusters.button.addNodePool', - provider: ProviderValueMap.DigitalOcean, - locale: true, - icon: icons.Catalog1 - }, - { - key: 'isDefault', - label: 'clusters.form.setDefault', - icon: icons.StarOutlined - }, - { - key: 'delete', - label: 'common.button.delete', - icon: icons.DeleteOutlined, - props: { - danger: true - } - } -]; - export const CloudOptionItems = [ { label: 'Volumes', diff --git a/src/pages/cluster-management/hooks/use-cluster-columns.tsx b/src/pages/cluster-management/hooks/use-cluster-columns.tsx index 703b3e6c..893505d2 100644 --- a/src/pages/cluster-management/hooks/use-cluster-columns.tsx +++ b/src/pages/cluster-management/hooks/use-cluster-columns.tsx @@ -2,9 +2,11 @@ import { systemConfigAtom } from '@/atoms/system'; import AutoTooltip from '@/components/auto-tooltip'; import DropdownButtons from '@/components/drop-down-buttons'; +import icons from '@/components/icon-font/icons'; import { SealColumnProps } from '@/components/seal-table/types'; import StatusTag from '@/components/status-tag'; import { tableSorter } from '@/config/settings'; +import GrafanaIcon from '@/pages/_components/grafana-icon'; import { StarFilled } from '@ant-design/icons'; import { useIntl } from '@umijs/max'; import { Tooltip } from 'antd'; @@ -15,10 +17,61 @@ import { ClusterStatus, ClusterStatusLabelMap, ProviderLabelMap, - clusterActionList + ProviderValueMap } from '../config'; import { ClusterListItem } from '../config/types'; +const clusterActionList = [ + { + key: 'edit', + label: 'common.button.edit', + icon: icons.EditOutlined + }, + { + label: 'resources.metrics.details', + key: 'metrics', + icon: ( + + + + ) + }, + { + key: 'add_worker', + label: 'resources.button.create', + provider: ProviderValueMap.Docker, + locale: true, + icon: icons.DockerOutlined + }, + { + key: 'register_cluster', + label: 'clusters.button.register', + provider: ProviderValueMap.Kubernetes, + locale: true, + icon: icons.KubernetesOutlined + }, + { + key: 'addPool', + label: 'clusters.button.addNodePool', + provider: ProviderValueMap.DigitalOcean, + locale: true, + icon: icons.Catalog1 + }, + { + key: 'isDefault', + label: 'clusters.form.setDefault', + icon: icons.StarOutlined + }, + { + key: 'delete', + label: 'common.button.delete', + icon: icons.DeleteOutlined, + props: { + danger: true + } + } +]; + const useClusterColumns = ( handleSelect: (val: string, record: ClusterListItem) => void, onCellClick?: (record: ClusterListItem, dataIndex: string) => void diff --git a/src/pages/llmodels/components/instance-item.tsx b/src/pages/llmodels/components/instance-item.tsx index 9ef8448b..083e78ab 100644 --- a/src/pages/llmodels/components/instance-item.tsx +++ b/src/pages/llmodels/components/instance-item.tsx @@ -12,7 +12,6 @@ import { HandlerOptions } from '@/hooks/use-chunk-fetch'; import useDownloadStream from '@/hooks/use-download-stream'; import { useBenchmarkTargetInstance } from '@/pages/llmodels/hooks/use-run-benchmark'; import { ListItem as WorkerListItem } from '@/pages/resources/config/types'; -import useGranfanaLink from '@/pages/resources/hooks/use-grafana-link'; import { convertFileSize } from '@/utils'; import { DeleteOutlined, @@ -330,12 +329,6 @@ const childActionList = [ ], icon: }, - { - label: 'resources.metrics.details', - key: 'metrics', - status: [InstanceStatusMap.Running], - icon: - }, { label: 'common.button.downloadLog', key: 'download', @@ -438,7 +431,6 @@ const InstanceItem: React.FC = ({ handleChildSelect }) => { const systemConfig = useAtomValue(systemConfigAtom); - const { goToGrafana } = useGranfanaLink({ type: 'instance' }); const { runBenchmarkOnInstance } = useBenchmarkTargetInstance(); const [api, contextHolder] = notification.useNotification({ stack: { threshold: 1 } @@ -456,9 +448,6 @@ const InstanceItem: React.FC = ({ if (action.status && action.status.length > 0) { return action.status.includes(instanceData.state); } - if (action.key === 'metrics') { - return systemConfig.showMonitoring; - } return true; }); }, [instanceData.state, modelData, systemConfig.showMonitoring]); @@ -668,25 +657,27 @@ const InstanceItem: React.FC = ({ } > - - - {intl.formatMessage({ - id: 'models.table.cpuoffload' - })} - + + + + {intl.formatMessage({ + id: 'models.table.cpuoffload' + })} + + ); }, [ @@ -703,8 +694,6 @@ const InstanceItem: React.FC = ({ filename: createFileName(instanceData.name), downloadNotification }); - } else if (val === 'metrics') { - goToGrafana(instanceData); } else { handleChildSelect(val, instanceData); } diff --git a/src/pages/llmodels/components/table-list.tsx b/src/pages/llmodels/components/table-list.tsx index 300e0a97..c1edf919 100644 --- a/src/pages/llmodels/components/table-list.tsx +++ b/src/pages/llmodels/components/table-list.tsx @@ -13,11 +13,12 @@ import { PageActionType } from '@/config/types'; import useBodyScroll from '@/hooks/use-body-scroll'; import useExpandedRowKeys from '@/hooks/use-expanded-row-keys'; import useTableRowSelection from '@/hooks/use-table-row-selection'; +import useWatchList from '@/hooks/use-watch-list'; import PageBox from '@/pages/_components/page-box'; import useNoResourceResult from '@/pages/llmodels/hooks/use-no-resource-result'; +import { MODEL_ROUTE_TARGETS } from '@/pages/model-routes/apis'; import { TargetStatusValueMap } from '@/pages/model-routes/config'; import useOpenPlayground from '@/pages/model-routes/hooks/use-open-playground'; -import useQueryTargets from '@/pages/model-routes/services/use-query-targets'; import useGranfanaLink from '@/pages/resources/hooks/use-grafana-link'; import { handleBatchRequest } from '@/utils'; import { DownOutlined, SearchOutlined, SyncOutlined } from '@ant-design/icons'; @@ -166,11 +167,8 @@ const Models: React.FC = ({ useFilterStatus({ onStatusChange: onStatusChange }); - const { fetchData: fetchTargets, dataList: targetList } = useQueryTargets(); + const { watchDataList: targetList } = useWatchList(MODEL_ROUTE_TARGETS); - useEffect(() => { - fetchTargets({}); - }, []); const { goToGrafana, ActionButton } = useGranfanaLink({ type: 'model', dataList: dataSource || [] @@ -554,7 +552,7 @@ const Models: React.FC = ({ sortOrder, targetList: targetList }; - }, [handleSelect, clusterList, sortOrder]); + }, [handleSelect, clusterList, sortOrder, targetList]); const columns = useModelsColumns(options); diff --git a/src/pages/llmodels/components/update-modal.tsx b/src/pages/llmodels/components/update-modal.tsx index 23ec9daa..f205f6d9 100644 --- a/src/pages/llmodels/components/update-modal.tsx +++ b/src/pages/llmodels/components/update-modal.tsx @@ -275,6 +275,7 @@ const UpdateModal: React.FC = (props) => { initialValues={formData} source={formData.source || ''} action={action} + realAction={realAction} clusterList={clusterList} onOk={handleOk} ref={formRef} diff --git a/src/pages/llmodels/config/button-actions.ts b/src/pages/llmodels/config/button-actions.ts index 7b28c624..d2e1dae1 100644 --- a/src/pages/llmodels/config/button-actions.ts +++ b/src/pages/llmodels/config/button-actions.ts @@ -33,47 +33,6 @@ interface ActionItem { }; } -export const ActionList: ActionItem[] = [ - { - label: 'common.button.edit', - key: 'edit', - icon: icons.EditOutlined - }, - { - label: 'models.openinplayground', - key: 'chat', - icon: icons.ExperimentOutlined - }, - { - key: 'copy', - label: 'common.button.clone', - icon: icons.CopyOutlined - }, - { - label: 'common.button.start', - key: 'start', - icon: icons.Play - }, - { - label: 'common.button.stop', - key: 'stop', - icon: icons.Stop - }, - { - label: 'resources.metrics.details', - key: 'metrics', - icon: icons.Metrics - }, - { - label: 'common.button.delete', - key: 'delete', - props: { - danger: true - }, - icon: icons.DeleteOutlined - } -]; - export const ButtonList = [ { label: 'common.button.start', diff --git a/src/pages/llmodels/config/form-context.ts b/src/pages/llmodels/config/form-context.ts index d656c737..6e8cbb32 100644 --- a/src/pages/llmodels/config/form-context.ts +++ b/src/pages/llmodels/config/form-context.ts @@ -18,6 +18,7 @@ interface FormContextProps { formKey: DeployFormKey; source: string; action: PageActionType; + realAction?: PageActionType; gpuOptions: CascaderOption[]; workerLabelOptions: CascaderOption[]; backendOptions: { diff --git a/src/pages/llmodels/forms/advance-config.tsx b/src/pages/llmodels/forms/advance-config.tsx index 62220619..cbac98a8 100644 --- a/src/pages/llmodels/forms/advance-config.tsx +++ b/src/pages/llmodels/forms/advance-config.tsx @@ -1,6 +1,7 @@ import LabelSelector from '@/components/label-selector'; import CheckboxField from '@/components/seal-form/checkbox-field'; import SealSelect from '@/components/seal-form/seal-select'; +import { PageAction } from '@/config'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; @@ -19,6 +20,8 @@ const AdvanceConfig = () => { const modelRouteEnable = Form.useWatch('enable_model_route', form); const { onValuesChange, + realAction, + action, backendOptions, flatBackendOptions, isGGUF, @@ -133,33 +136,37 @@ const AdvanceConfig = () => { })} > - - name="enable_model_route" - valuePropName="checked" - style={{ marginBottom: 8 }} - > - - - {modelRouteEnable && ( - - name="generic_proxy" - valuePropName="checked" - style={{ marginBottom: 8 }} - > - - - )} + {realAction === PageAction.COPY || action === PageAction.CREATE ? ( + <> + + name="enable_model_route" + valuePropName="checked" + style={{ marginBottom: 8 }} + > + + + {modelRouteEnable && ( + + name="generic_proxy" + valuePropName="checked" + style={{ marginBottom: 8 }} + > + + + )} + + ) : null} ); }; diff --git a/src/pages/llmodels/forms/index.tsx b/src/pages/llmodels/forms/index.tsx index abf408c7..67b5bc1f 100644 --- a/src/pages/llmodels/forms/index.tsx +++ b/src/pages/llmodels/forms/index.tsx @@ -50,6 +50,7 @@ interface DataFormProps { ref?: any; source: SourceType; action: PageActionType; + realAction?: PageActionType; isGGUF: boolean; formKey: DeployFormKey; sourceDisable?: boolean; @@ -77,6 +78,7 @@ const DataForm: React.FC = forwardRef((props, ref) => { isGGUF, formKey, source, + realAction, initialValues, sourceDisable = true, sourceList, @@ -392,6 +394,7 @@ const DataForm: React.FC = forwardRef((props, ref) => { formKey: formKey, source: props.source, action: action, + realAction: realAction, gpuOptions: gpuOptions, backendOptions: backendOptions, flatBackendOptions: flatBackendOptions, diff --git a/src/pages/llmodels/hooks/index.ts b/src/pages/llmodels/hooks/index.ts index b5d30c94..4559840a 100644 --- a/src/pages/llmodels/hooks/index.ts +++ b/src/pages/llmodels/hooks/index.ts @@ -271,12 +271,6 @@ export const useCheckCompatibility = () => { let compatibilityMessage = compatibility_messages.join(' '); - compatibilityMessage = compatibilityMessage.startsWith( - 'The model file path you specified does not exist on the GPUStack server' - ) - ? intl.formatMessage({ id: 'models.form.modelfile.notfound' }) - : compatibilityMessage; - let msgData = { title: scheduling_messages?.length > 0 ? compatibilityMessage : '', message: diff --git a/src/pages/llmodels/hooks/use-models-columns.tsx b/src/pages/llmodels/hooks/use-models-columns.tsx index 4905cafd..192853d3 100644 --- a/src/pages/llmodels/hooks/use-models-columns.tsx +++ b/src/pages/llmodels/hooks/use-models-columns.tsx @@ -2,8 +2,10 @@ import { systemConfigAtom } from '@/atoms/system'; import AutoTooltip from '@/components/auto-tooltip'; import DropdownButtons from '@/components/drop-down-buttons'; +import icons from '@/components/icon-font/icons'; import { SealColumnProps } from '@/components/seal-table/types'; import { OPENAI_COMPATIBLE, tableSorter } from '@/config/settings'; +import GrafanaIcon from '@/pages/_components/grafana-icon'; import { TargetStatusValueMap } from '@/pages/model-routes/config'; import { QuestionCircleOutlined } from '@ant-design/icons'; import { useIntl } from '@umijs/max'; @@ -14,9 +16,63 @@ import { useAtomValue } from 'jotai'; import _ from 'lodash'; import { useMemo } from 'react'; import ModelTag from '../../_components/model-tag'; -import { ActionList, generateSource } from '../config/button-actions'; +import { generateSource } from '../config/button-actions'; import { ListItem } from '../config/types'; +interface ActionItem { + label: string; + key: string; + icon: React.ReactNode; + props?: { + danger?: boolean; + }; +} + +const ActionList: ActionItem[] = [ + { + label: 'common.button.edit', + key: 'edit', + icon: icons.EditOutlined + }, + { + label: 'models.openinplayground', + key: 'chat', + icon: icons.ExperimentOutlined + }, + { + label: 'common.button.start', + key: 'start', + icon: icons.Play + }, + { + label: 'common.button.stop', + key: 'stop', + icon: icons.Stop + }, + { + label: 'resources.metrics.details', + key: 'metrics', + icon: ( + + + + ) + }, + { + key: 'copy', + label: 'common.button.clone', + icon: icons.CopyOutlined + }, + { + label: 'common.button.delete', + key: 'delete', + props: { + danger: true + }, + icon: icons.DeleteOutlined + } +]; + interface ModelsColumnsHookProps { handleSelect: (val: string, record: ListItem) => void; sortOrder: string[]; diff --git a/src/pages/resources/hooks/use-gpu-columns.tsx b/src/pages/resources/hooks/use-gpu-columns.tsx index a1eff26a..7cc18adc 100644 --- a/src/pages/resources/hooks/use-gpu-columns.tsx +++ b/src/pages/resources/hooks/use-gpu-columns.tsx @@ -102,7 +102,7 @@ const useGPUColumns = (props: { sorter: tableSorter(6), render: (text: number, record: GPUDeviceItem) => { return ( - <> + {record.core ? ( + ); } }, @@ -121,23 +121,25 @@ const useGPUColumns = (props: { sorter: tableSorter(7), render: (text: number, record: GPUDeviceItem, index: number) => { return ( - - } - > + + + } + > + ); } } diff --git a/src/pages/resources/hooks/use-grafana-link.tsx b/src/pages/resources/hooks/use-grafana-link.tsx index 2115fd94..5883fa33 100644 --- a/src/pages/resources/hooks/use-grafana-link.tsx +++ b/src/pages/resources/hooks/use-grafana-link.tsx @@ -1,13 +1,13 @@ import { systemConfigAtom } from '@/atoms/system'; -import IconFont from '@/components/icon-font'; import { GPUSTACK_API_BASE_URL } from '@/config/settings'; +import GrafanaIcon from '@/pages/_components/grafana-icon'; import { useIntl } from '@umijs/max'; import { Button } from 'antd'; import { useAtomValue } from 'jotai'; const useGranfanaLink = (options: { type: 'model' | 'worker' | 'instance' | 'cluster'; - dataList: any[]; + dataList?: any[]; }) => { const intl = useIntl(); const systemConfig = useAtomValue(systemConfigAtom); @@ -53,7 +53,7 @@ const useGranfanaLink = (options: { }; const handleClick = () => { - if (options.dataList?.length > 0) { + if (options.dataList && options.dataList.length > 0) { goToGrafana(options.dataList?.[0]); } }; @@ -63,7 +63,7 @@ const useGranfanaLink = (options: { return ( diff --git a/src/pages/resources/hooks/use-worker-columns.tsx b/src/pages/resources/hooks/use-worker-columns.tsx index c84567ca..ddc3aafa 100644 --- a/src/pages/resources/hooks/use-worker-columns.tsx +++ b/src/pages/resources/hooks/use-worker-columns.tsx @@ -1,12 +1,12 @@ import { systemConfigAtom } from '@/atoms/system'; import AutoTooltip from '@/components/auto-tooltip'; import DropdownButtons from '@/components/drop-down-buttons'; -import IconFont from '@/components/icon-font'; import LabelsCell from '@/components/label-cell'; import ProgressBar from '@/components/progress-bar'; import InfoColumn from '@/components/simple-table/info-column'; import StatusTag from '@/components/status-tag'; import { tableSorter } from '@/config/settings'; +import GrafanaIcon from '@/pages/_components/grafana-icon'; import { convertFileSize } from '@/utils'; import { DeleteOutlined, @@ -48,7 +48,11 @@ const ActionList = [ { label: 'resources.metrics.details', key: 'metrics', - icon: + icon: ( + + + + ) }, // { // label: 'common.button.detail', @@ -123,7 +127,10 @@ const GPUCell = ({ devices }: { devices: GPUDeviceItem[] }) => ( _.sortBy(devices || [], ['index']), (item: GPUDeviceItem, index: number) => ( - + [{item.index}] {item.core ? ( @@ -155,7 +162,10 @@ const VRAMCell = ({ _.sortBy(devices || [], ['index']), (item: GPUDeviceItem, index: number) => ( - + [{item.index}] - statusAvailable(record) ? ( - - ) : ( - - ) + render: (text: string, record) => ( + + {statusAvailable(record) ? ( + + ) : ( + + )} + + ) }, { title: intl.formatMessage({ id: 'resources.table.memory' }), dataIndex: 'status.memory.utilization_rate', sorter: tableSorter(5), - render: (_, record) => - statusAvailable(record) ? ( - - } - /> - ) : ( - - ) + render: (_, record) => ( + + {statusAvailable(record) ? ( + + } + /> + ) : ( + + )} + + ) }, { title: 'GPU', @@ -400,12 +419,15 @@ const useWorkerColumns = ({ { title: intl.formatMessage({ id: 'resources.table.disk' }), dataIndex: 'storage', - render: (_, record) => - statusAvailable(record) ? ( - - ) : ( - - ) + render: (_, record) => ( + + {statusAvailable(record) ? ( + + ) : ( + + )} + + ) }, { title: intl.formatMessage({ id: 'common.table.operation' }),