diff --git a/config/routes.ts b/config/routes.ts index cb4f7826..393dec47 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -89,7 +89,7 @@ export default [ name: 'apikeys', path: '/api-keys', key: 'apikeys', - icon: 'LockOutlined', + icon: 'KeyOutlined', component: './api-keys' }, { diff --git a/src/components/drop-down-buttons/index.tsx b/src/components/drop-down-buttons/index.tsx index 6a9dd6da..8a29d4f4 100644 --- a/src/components/drop-down-buttons/index.tsx +++ b/src/components/drop-down-buttons/index.tsx @@ -10,6 +10,11 @@ interface DropdownButtonsProps { items: MenuProps['items']; size?: 'small' | 'middle' | 'large'; trigger?: Trigger[]; + showText?: boolean; + disabled?: boolean; + variant?: 'filled' | 'outlined'; + color?: string; + extra?: React.ReactNode; onSelect: (val: any, item?: any) => void; } @@ -17,9 +22,16 @@ const DropdownButtons: React.FC = ({ items, size = 'middle', trigger = ['hover'], + showText, + disabled, + variant, + color, + extra, onSelect }) => { + const headItem = _.head(items); const intl = useIntl(); + const handleMenuClick = (item: any) => { const selectItem = _.find(items, { key: item.key }); onSelect(item.key, selectItem); @@ -37,19 +49,20 @@ const DropdownButtons: React.FC = ({ return ( <> {items?.length === 1 ? ( - + ) : ( { return (
= ({ - , + <> + {showText ? ( + + ) : ( + + + + )} + , ]} diff --git a/src/components/label-selector/wrapper.tsx b/src/components/label-selector/wrapper.tsx index 491f1a0b..ddc9a8e2 100644 --- a/src/components/label-selector/wrapper.tsx +++ b/src/components/label-selector/wrapper.tsx @@ -3,15 +3,20 @@ import React from 'react'; import styles from './styles/wrapper.less'; const Wrapper: React.FC<{ - label?: string; + label?: React.ReactNode; description?: React.ReactNode; + labelExtra?: React.ReactNode; children: React.ReactNode; -}> = ({ children, label, description, ...rest }) => { +}> = ({ children, label, description, labelExtra, ...rest }) => { return (
{label && ( - + )} {React.isValidElement(children) diff --git a/src/components/list-input/index.tsx b/src/components/list-input/index.tsx index 05de9f29..8bb200ad 100644 --- a/src/components/list-input/index.tsx +++ b/src/components/list-input/index.tsx @@ -8,17 +8,26 @@ import ListItem from './list-item'; interface ListInputProps { dataList: string[]; - label: string; + label: React.ReactNode; description?: React.ReactNode; btnText?: string; options?: Global.HintOptions[]; placeholder?: string; + labelExtra?: React.ReactNode; onChange: (data: string[]) => void; } const ListInput: React.FC = (props) => { const intl = useIntl(); - const { dataList, label, description, onChange, btnText, options } = props; + const { + dataList, + label, + description, + onChange, + btnText, + options, + labelExtra + } = props; const [list, setList] = React.useState<{ value: string; uid: number }[]>([]); const countRef = React.useRef(0); const buttonRef = React.useRef(null); @@ -71,7 +80,7 @@ const ListInput: React.FC = (props) => { }, [dataList]); return ( - + <> {_.map(list, (item: any, index: number) => { return ( diff --git a/src/components/seal-form/components/label-info.tsx b/src/components/seal-form/components/label-info.tsx index 2755cc7a..831c0645 100644 --- a/src/components/seal-form/components/label-info.tsx +++ b/src/components/seal-form/components/label-info.tsx @@ -7,9 +7,10 @@ interface NoteInfoProps { required?: boolean; label: React.ReactNode; description?: React.ReactNode; + labelExtra?: React.ReactNode; } const NoteInfo: React.FC = (props) => { - const { required, description, label } = props || {}; + const { required, description, label, labelExtra } = props || {}; if (!label) return null; return ( @@ -43,6 +44,7 @@ const NoteInfo: React.FC = (props) => { )} + {labelExtra} ); }; diff --git a/src/components/seal-form/components/wrapper.tsx b/src/components/seal-form/components/wrapper.tsx index 2331dec9..90917ab7 100644 --- a/src/components/seal-form/components/wrapper.tsx +++ b/src/components/seal-form/components/wrapper.tsx @@ -17,6 +17,7 @@ interface WrapperProps { variant?: string; hasPrefix?: boolean; classList?: string; + labelExtra?: React.ReactNode; onClick?: () => void; } @@ -35,6 +36,7 @@ const Wrapper: React.FC = ({ hasPrefix, noWrapperStyle, classList, + labelExtra, onClick }) => { return ( @@ -74,6 +76,7 @@ const Wrapper: React.FC = ({ label={label} required={required} description={description} + labelExtra={labelExtra} > {extra &&
{extra}
} diff --git a/src/components/seal-form/seal-input.tsx b/src/components/seal-form/seal-input.tsx index 4df51b96..fbcc62a3 100644 --- a/src/components/seal-form/seal-input.tsx +++ b/src/components/seal-form/seal-input.tsx @@ -20,6 +20,7 @@ const SealInput: React.FC = (props) => { checkStatus, trim = true, loading, + labelExtra, ...rest } = props; const [isFocus, setIsFocus] = useState(false); @@ -74,6 +75,7 @@ const SealInput: React.FC = (props) => { (null); const [updateChild, setUpdateChild] = useState(true); + const [currentExpand, setCurrentExpand] = useState(false); const { updateChunkedList, cacheDataListRef } = useUpdateChunkedList({ dataList: childrenData, limit: 100, setDataList: setChildrenData - // callback: (list) => renderChildren?.(list) }); useEffect(() => { @@ -92,7 +92,10 @@ const TableRow: React.FC< > ); } - return renderChildren?.(childrenData, record); + return renderChildren?.(childrenData, { + parent: record, + currentExpanded: currentExpand + }); }; const handlePolling = async () => { @@ -163,6 +166,7 @@ const TableRow: React.FC< const handleRowExpand = async () => { onExpand?.(!expanded, record, record[rowKey]); + setCurrentExpand(!expanded); if (pollTimer.current) { clearInterval(pollTimer.current); diff --git a/src/components/seal-table/styles/row-children.less b/src/components/seal-table/styles/row-children.less index 575bcc45..43fd8f86 100644 --- a/src/components/seal-table/styles/row-children.less +++ b/src/components/seal-table/styles/row-children.less @@ -2,8 +2,7 @@ position: relative; display: flex; align-items: center; - min-height: 54px; - padding-block: 5px; + height: 54px; border-radius: var(--border-radius-mdium); transition: all 0.2s ease; diff --git a/src/components/seal-table/types.ts b/src/components/seal-table/types.ts index 22a09047..58419054 100644 --- a/src/components/seal-table/types.ts +++ b/src/components/seal-table/types.ts @@ -59,7 +59,10 @@ export interface SealTableProps { onSort?: (dataIndex: string, order: 'ascend' | 'descend') => void; onExpand?: (expanded: boolean, record: any, rowKey: any) => void; onExpandAll?: (expanded: boolean) => void; - renderChildren?: (data: any, parent?: any) => React.ReactNode; + renderChildren?: ( + data: any, + options: { parent?: any; [key: string]: any } + ) => React.ReactNode; loadChildren?: (record: any, options?: any) => Promise; loadChildrenAPI?: (record: any) => string; contentRendered?: () => void; diff --git a/src/components/simple-table/header.tsx b/src/components/simple-table/header.tsx index 8ee172b3..793fb71b 100644 --- a/src/components/simple-table/header.tsx +++ b/src/components/simple-table/header.tsx @@ -14,7 +14,7 @@ const TableHeader = ({ columns }: TableHeaderProps) => { {columns.map((column: any, index: number) => { return ( - + {column.locale ? intl.formatMessage({ id: column.title }) : column.title} diff --git a/src/components/simple-table/index.less b/src/components/simple-table/index.less index f6a5fb95..c3d3d82d 100644 --- a/src/components/simple-table/index.less +++ b/src/components/simple-table/index.less @@ -16,7 +16,7 @@ } tr:last-child td { - border-bottom: none; + // border-bottom: none; } } @@ -25,9 +25,17 @@ font-weight: 600; } + td { + color: var(--color-white-quaternary); + } + .cell-span { display: flex; padding: 4px 6px; min-height: 32px; } + + .cell-header { + font-weight: var(--font-weight-bold); + } } diff --git a/src/components/simple-table/index.tsx b/src/components/simple-table/index.tsx index 162afebf..052c4875 100644 --- a/src/components/simple-table/index.tsx +++ b/src/components/simple-table/index.tsx @@ -6,11 +6,31 @@ import TableHeader from './header'; import './index.less'; import TableRow from './row'; -interface ColumnProps { +export interface ColumnProps { title: string; key: string; - render?: (data: { dataIndex: string; row: any }) => any; + render?: (data: { + dataIndex: string; + dataList?: any[]; + row: any; + rowIndex?: number; + colIndex?: number; + }) => any; locale?: boolean; + colSpan?: (params: { + row: any; + rowIndex: number; + colIndex: number; + dataIndex: string; + dataList: any[]; + }) => number; + rowSpan?: (params: { + row: any; + rowIndex: number; + colIndex: number; + dataIndex: string; + dataList: any[]; + }) => number; } interface SimpleTableProps { @@ -42,7 +62,9 @@ const SimpleTabel: React.FC = (props) => { return ( ); diff --git a/src/components/simple-table/row.tsx b/src/components/simple-table/row.tsx index 7424454c..cf59d2b6 100644 --- a/src/components/simple-table/row.tsx +++ b/src/components/simple-table/row.tsx @@ -1,25 +1,88 @@ -import React from 'react'; +import React, { useMemo } from 'react'; interface TableRowProps { row: any; columns: any; + rowIndex: number; + dataList: any[]; } -const TableRow = ({ row, columns }: TableRowProps) => { + +interface TableCellProps { + row: any; + column: any; + rowIndex: number; + colIndex: number; + dataList: any[]; +} +const TableCell: React.FC = (props: TableCellProps) => { + const { row, column, rowIndex, colIndex, dataList } = props; + + const renderContent = useMemo(() => { + return column.render + ? column.render({ + dataIndex: column.key, + dataList: dataList, + row: row, + rowIndex, + colIndex: colIndex + }) + : row[column.key]; + }, [column, row, rowIndex, colIndex, dataList]); + + if (renderContent === null && (column.colSpan || column.rowSpan)) { + return null; + } + + return ( + + + {column.render + ? column.render({ + dataIndex: column.key, + dataList: dataList, + row: row, + rowIndex, + colIndex: colIndex + }) + : row[column.key]} + + + ); +}; + +const TableRow = ({ row, columns, rowIndex, dataList }: TableRowProps) => { return ( {columns.map((column: any, index: number) => { return ( - - - {column.render - ? column.render({ dataIndex: column.key, row: row }) - : row[column.key]} - - + ); })} ); }; -export default React.memo(TableRow); +export default TableRow; diff --git a/src/hooks/use-expanded-row-keys.ts b/src/hooks/use-expanded-row-keys.ts index 0f23298e..90c4658b 100644 --- a/src/hooks/use-expanded-row-keys.ts +++ b/src/hooks/use-expanded-row-keys.ts @@ -3,13 +3,16 @@ import { useCallback, useState } from 'react'; export default function useExpandedRowKeys(defaultKeys: React.Key[] = []) { const [expandedRowKeys, setExpandedRowKeys] = useState(defaultKeys); + const [currentExpand, setCurrentExpand] = useState(null); const handleExpandChange = useCallback( (expanded: boolean, record: any, rowKey: any) => { if (expanded) { setExpandedRowKeys((keys) => [...keys, rowKey]); + setCurrentExpand(rowKey); } else { setExpandedRowKeys((keys) => keys.filter((key) => key !== rowKey)); + setCurrentExpand(null); } }, [] @@ -19,6 +22,7 @@ export default function useExpandedRowKeys(defaultKeys: React.Key[] = []) { (expanded: boolean, keys: React.Key[] = []) => { if (!expanded) { setExpandedRowKeys([]); + setCurrentExpand(null); } if (expanded) { setExpandedRowKeys((prevKeys) => [...new Set([...prevKeys, ...keys])]); @@ -41,10 +45,13 @@ export default function useExpandedRowKeys(defaultKeys: React.Key[] = []) { const clearExpandedRowKeys = () => { setExpandedRowKeys([]); + setCurrentExpand(null); }; return { expandedRowKeys, + currentExpand, + setCurrentExpand, clearExpandedRowKeys, updateExpandedRowKeys, removeExpandedRowKey, diff --git a/src/locales/en-US/models.ts b/src/locales/en-US/models.ts index 19ae8b24..89ff78fd 100644 --- a/src/locales/en-US/models.ts +++ b/src/locales/en-US/models.ts @@ -108,5 +108,7 @@ export default { 'models.table.list.getStart': 'Get started with DeepSeek-R1-Distill-Qwen-1.5B', 'models.table.llamaAcrossworker': 'Llama-box Across Workers', - 'models.table.vllmAcrossworker': 'vLLM Across Workers' + 'models.table.vllmAcrossworker': 'vLLM Across Workers', + 'models.form.releases': 'Releases', + 'models.form.moreparameters': 'More Parameters' }; diff --git a/src/locales/ru-RU/models.ts b/src/locales/ru-RU/models.ts index 7362cb20..eb242ef4 100644 --- a/src/locales/ru-RU/models.ts +++ b/src/locales/ru-RU/models.ts @@ -109,5 +109,8 @@ export default { 'models.table.llamaAcrossworker': 'TODO: Translate key "models.table.llamaAcrossworker"', 'models.table.vllmAcrossworker': - 'TODO: Translate key "models.table.vllmAcrossworker"' + 'TODO: Translate key "models.table.vllmAcrossworker"', + 'models.form.releases': 'TODO: Translate key "models.form.releases"', + 'models.form.moreparameters': + 'TODO: Translate key "models.form.moreparameters"' }; diff --git a/src/locales/zh-CN/models.ts b/src/locales/zh-CN/models.ts index d4a3a604..9d2dcfeb 100644 --- a/src/locales/zh-CN/models.ts +++ b/src/locales/zh-CN/models.ts @@ -104,5 +104,7 @@ export default { 'models.table.list.getStart': '一键部署DeepSeek-R1-Distill-Qwen-1.5B立即使用!', 'models.table.llamaAcrossworker': 'Llama-box 跨节点', - 'models.table.vllmAcrossworker': 'vLLM 跨节点' + 'models.table.vllmAcrossworker': 'vLLM 跨节点', + 'models.form.releases': '版本', + 'models.form.moreparameters': '更多参数' }; diff --git a/src/pages/llmodels/components/advance-config.tsx b/src/pages/llmodels/components/advance-config.tsx index c699ef4a..e5742bbd 100644 --- a/src/pages/llmodels/components/advance-config.tsx +++ b/src/pages/llmodels/components/advance-config.tsx @@ -101,12 +101,14 @@ const AdvanceConfig: React.FC = (props) => { if (backend === backendOptionsMap.llamaBox) { return { backend: 'llama-box', + releases: 'https://github.com/gpustack/llama-box/releases', link: 'https://github.com/gpustack/llama-box?tab=readme-ov-file#usage' }; } if (backend === backendOptionsMap.vllm) { return { backend: 'vLLM', + releases: 'https://github.com/vllm-project/vllm/releases', link: 'https://docs.vllm.ai/en/stable/serving/openai_compatible_server.html#command-line-arguments-for-the-server' }; } @@ -327,6 +329,25 @@ const AdvanceConfig: React.FC = (props) => { description={intl.formatMessage({ id: 'models.form.backendVersion.tips' })} + labelExtra={ + backendParamsTips?.releases && ( + + ( + + {intl.formatMessage({ id: 'models.form.releases' })} + + ) + + ) + } > @@ -346,19 +367,20 @@ const AdvanceConfig: React.FC = (props) => { dataList={form.getFieldValue('backend_parameters') || []} onChange={handleBackendParametersChange} options={paramsConfig} - description={ - backendParamsTips && ( - - {intl.formatMessage( - { id: 'models.form.backend_parameters.vllm.tips' }, - { backend: backendParamsTips.backend || '' } - )}{' '} + labelExtra={ + backendParamsTips?.link && ( + + ( - {intl.formatMessage({ id: 'common.text.here' })} + {intl.formatMessage({ + id: 'models.form.moreparameters' + })} + ) ) } diff --git a/src/pages/llmodels/components/instance-item.tsx b/src/pages/llmodels/components/instance-item.tsx index 838e9cfa..bcfbcc54 100644 --- a/src/pages/llmodels/components/instance-item.tsx +++ b/src/pages/llmodels/components/instance-item.tsx @@ -2,7 +2,7 @@ import AutoTooltip from '@/components/auto-tooltip'; import DropdownButtons from '@/components/drop-down-buttons'; import IconFont from '@/components/icon-font'; import RowChildren from '@/components/seal-table/components/row-children'; -import SimpleTabel from '@/components/simple-table'; +import SimpleTabel, { ColumnProps } from '@/components/simple-table'; import StatusTag from '@/components/status-tag'; import { HandlerOptions } from '@/hooks/use-chunk-fetch'; import useDownloadStream from '@/hooks/use-download-stream'; @@ -12,7 +12,8 @@ import { DeleteOutlined, DownloadOutlined, HddFilled, - InfoCircleOutlined + InfoCircleOutlined, + ThunderboltFilled } from '@ant-design/icons'; import { useIntl } from '@umijs/max'; import { @@ -27,17 +28,48 @@ import { } from 'antd'; import dayjs from 'dayjs'; import _ from 'lodash'; -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useEffect, useMemo } from 'react'; import styled from 'styled-components'; import { MODEL_INSTANCE_API } from '../apis'; import { InstanceStatusMap, InstanceStatusMapValue, status } from '../config'; import { ModelInstanceListItem } from '../config/types'; import '../style/instance-item.less'; +const WorkerInfo = (props: { + title: React.ReactNode; + defaultOpen: boolean; +}) => { + const [open, setOpen] = React.useState(props.defaultOpen); + useEffect(() => { + if (props.defaultOpen) { + setTimeout(() => { + setOpen(false); + }, 1000); + } + }, [props.defaultOpen]); + return ( + + + + + + + + ); +}; interface InstanceItemProps { instanceData: ModelInstanceListItem; workerList: WorkerListItem[]; modelData?: any; + defaultOpenId: string; handleChildSelect: (val: string, item: ModelInstanceListItem) => void; } @@ -76,7 +108,7 @@ const childActionList = [ } ]; -const distributeCols = [ +const distributeCols: ColumnProps[] = [ { title: 'Worker', key: 'worker_name' @@ -84,7 +116,7 @@ const distributeCols = [ { title: 'IP', key: 'worker_ip', - render: ({ row }: { row: ModelInstanceListItem }) => { + render: ({ row }) => { return row.port ? `${row.worker_ip}:${row.port}` : row.worker_ip; } }, @@ -94,9 +126,21 @@ const distributeCols = [ key: 'gpu_index' }, { - title: 'resources.table.memory', + title: 'resources.table.vram', locale: true, - key: 'ram' + key: 'vram', + rowSpan: ({ row, rowIndex, colIndex, dataIndex, dataList }) => { + return rowIndex === 0 ? dataList.length : 0; + }, + render: ({ rowIndex, dataList }) => { + if (rowIndex === 0) { + return convertFileSize( + _.sumBy(dataList, (item: any) => item.vram), + 2 + ); + } + return null; + } } ]; @@ -153,6 +197,7 @@ const InstanceItem: React.FC = ({ instanceData, workerList, modelData, + defaultOpenId, handleChildSelect }) => { const [api, contextHolder] = notification.useNotification({ @@ -224,55 +269,32 @@ const InstanceItem: React.FC = ({ ? `${instanceData.worker_ip}:${instanceData.port}` : instanceData.worker_ip; } - let backend = modelData?.backend || ''; - if (modelData.backend_version) { - backend += ` (${modelData.backend_version})`; - } - const vrams = instanceData.computed_resource_claim?.vram || {}; return (
-
+
{instanceData.worker_name}
+
- {instanceData.worker_name} + {workerIp}
-
- - +
+ + {intl.formatMessage({ id: 'models.table.gpuindex' })}: [ + {_.join(instanceData.gpu_indexes?.sort?.(), ',')}]
-
- { - return ( - - - [{index}] {''} - - {convertFileSize(vrams?.[index], 0)} - - ); - })} - > - +
+ + {intl.formatMessage({ id: 'models.form.backend' })}:{' '} + {modelData?.backend || ''} + {modelData.backend_version ? `(${modelData.backend_version})` : ''}
); }, [modelData, instanceData, intl]); + const calcTotalVram = (vram: Record) => { + return _.sum(_.values(vram)); + }; + const renderDistributedServer = useCallback( (severList: any[]) => { const list = _.map(severList, (item: any) => { @@ -281,20 +303,35 @@ const InstanceItem: React.FC = ({ worker_name: data?.name, worker_ip: data?.ip, port: '', - ram: convertFileSize(item.computed_resource_claim?.ram, 0), - gpu_index: displayGPUs(item.computed_resource_claim?.vram || {}) + vram: calcTotalVram(item.computed_resource_claim?.vram || {}), + gpu_index: _.keys(item.computed_resource_claim?.vram).join(',') }; }); + // const list = [ + // { + // worker_name: 'worker1', + // worker_ip: '192.168.50.23', + // port: '', + // vram: 21555525632, + // gpu_index: '0,1' + // }, + // { + // worker_name: 'worker2', + // worker_ip: '192.168.50.25', + // port: '', + // vram: 21555525632, + // gpu_index: '2,3' + // } + // ]; + const mainWorker = [ { - worker_name: `${instanceData.worker_name} (main)`, + worker_name: `${instanceData.worker_name}`, worker_ip: `${instanceData.worker_ip}`, port: '', - ram: convertFileSize(instanceData.computed_resource_claim?.ram, 0), - gpu_index: displayGPUs( - instanceData.computed_resource_claim?.vram || {} - ) + vram: calcTotalVram(instanceData.computed_resource_claim?.vram || {}), + gpu_index: `${instanceData.gpu_indexes?.join?.(',')}(main)` } ]; @@ -443,18 +480,12 @@ const InstanceItem: React.FC = ({ {instanceData.name} - - - {' '} - {intl.formatMessage({ id: 'common.button.moreInfo' })} - - + {!!instanceData.worker_id && ( + + )} @@ -468,10 +499,9 @@ const InstanceItem: React.FC = ({ > {renderOffloadInfo} {renderDistributionInfo( - instanceData.distributed_servers?.rpc_servers || [] - )} - {renderDistributionInfo( - instanceData.distributed_servers?.ray_actors || [] + instanceData.distributed_servers?.rpc_servers || + instanceData.distributed_servers?.ray_actors || + [] )} diff --git a/src/pages/llmodels/components/instances.tsx b/src/pages/llmodels/components/instances.tsx index fb109435..bc7e76ab 100644 --- a/src/pages/llmodels/components/instances.tsx +++ b/src/pages/llmodels/components/instances.tsx @@ -1,7 +1,7 @@ import { ListItem as WorkerListItem } from '@/pages/resources/config/types'; import { Space } from 'antd'; import _ from 'lodash'; -import React from 'react'; +import React, { useEffect, useMemo } from 'react'; import { ModelInstanceListItem } from '../config/types'; import '../style/instance-item.less'; import InstanceItem from './instance-item'; @@ -10,6 +10,7 @@ interface InstanceItemProps { list: ModelInstanceListItem[]; workerList: WorkerListItem[]; modelData?: any; + currentExpanded?: string; handleChildSelect: (val: string, item: ModelInstanceListItem) => void; } @@ -17,8 +18,26 @@ const Instances: React.FC = ({ list, workerList, modelData, + currentExpanded, handleChildSelect }) => { + const [firstLoad, setFirstLoad] = React.useState(true); + + const defaultOpenId = useMemo(() => { + if (!currentExpanded) { + return ''; + } + const current = _.find( + list, + (item: ModelInstanceListItem) => item.worker_id + ); + return current ? current.name : ''; + }, [currentExpanded, list]); + + useEffect(() => { + setFirstLoad(false); + }, []); + return ( {_.map(list, (item: ModelInstanceListItem, index: number) => { @@ -28,6 +47,7 @@ const Instances: React.FC = ({ modelData={modelData} workerList={workerList} instanceData={item} + defaultOpenId={firstLoad ? defaultOpenId : ''} handleChildSelect={handleChildSelect} > ); diff --git a/src/pages/llmodels/components/table-list.tsx b/src/pages/llmodels/components/table-list.tsx index c4bcad21..a90d9959 100644 --- a/src/pages/llmodels/components/table-list.tsx +++ b/src/pages/llmodels/components/table-list.tsx @@ -32,7 +32,7 @@ import { SyncOutlined } from '@ant-design/icons'; import { PageContainer } from '@ant-design/pro-components'; -import { Access, useAccess, useIntl, useNavigate } from '@umijs/max'; +import { useAccess, useIntl, useNavigate } from '@umijs/max'; import { Button, Dropdown, @@ -68,7 +68,6 @@ import { } from '../config'; import { FormData, ListItem, ModelInstanceListItem } from '../config/types'; import { useGenerateFormEditInitialValues } from '../hooks'; -import DeployDropdown from './deploy-dropdown'; import DeployModal from './deploy-modal'; import Instances from './instances'; import ModelTag from './model-tag'; @@ -120,7 +119,7 @@ const ActionList = [ { label: 'common.button.start', key: 'start', - icon: + icon: }, { label: 'common.button.delete', @@ -132,6 +131,27 @@ const ActionList = [ } ]; +const ButtonList = [ + { + label: 'common.button.start', + key: 'start', + icon: + }, + { + label: 'common.button.stop', + key: 'stop', + icon: + }, + { + label: 'common.button.delete', + key: 'delete', + icon: , + props: { + danger: true + } + } +]; + const generateSource = (record: ListItem) => { if (record.source === modelSourceMap.modelscope_value) { return `${modelSourceMap.modelScope}/${record.model_scope_model_id}`; @@ -327,6 +347,12 @@ const Models: React.FC = ({ }, []); const sourceOptions = [ + { + label: intl.formatMessage({ id: 'menu.models.modelCatalog' }), + value: 'catalog', + key: 'catalog', + icon: + }, { label: 'Hugging Face', value: modelSourceMap.huggingface_value, @@ -345,12 +371,6 @@ const Models: React.FC = ({ key: 'modelscope', icon: }, - { - label: intl.formatMessage({ id: 'menu.models.modelCatalog' }), - value: 'catalog', - key: 'catalog', - icon: - }, { label: intl.formatMessage({ id: 'models.form.localPath' }), value: modelSourceMap.local_path_value, @@ -659,11 +679,12 @@ const Models: React.FC = ({ ); const renderChildren = useCallback( - (list: any, parent?: any) => { + (list: any, options: { parent?: any; [key: string]: any }) => { return ( @@ -739,6 +760,18 @@ const Models: React.FC = ({ }); }; + const handleActionSelect = (val: any) => { + if (val === 'delete') { + handleDeleteBatch(); + } + if (val === 'start') { + handleStartBatch(); + } + if (val === 'stop') { + handleStopBatch(); + } + }; + const columns: SealColumnProps[] = useMemo(() => { return [ { @@ -939,12 +972,6 @@ const Models: React.FC = ({ onClick: handleClickDropdown }} trigger={['hover']} - dropdownRender={() => ( - - )} placement="bottomRight" > - - + */} } > diff --git a/src/pages/resources/components/gpus.tsx b/src/pages/resources/components/gpus.tsx index 3df088cc..5d4c7481 100644 --- a/src/pages/resources/components/gpus.tsx +++ b/src/pages/resources/components/gpus.tsx @@ -1,6 +1,7 @@ import AutoTooltip from '@/components/auto-tooltip'; import PageTools from '@/components/page-tools'; import ProgressBar from '@/components/progress-bar'; +import InfoColumn from '@/components/simple-table/info-column'; import useTableSort from '@/hooks/use-table-sort'; import { convertFileSize } from '@/utils'; import { SyncOutlined } from '@ant-design/icons'; @@ -12,6 +13,33 @@ import { queryGpuDevicesList } from '../apis'; import { GPUDeviceItem } from '../config/types'; const { Column } = Table; +const fieldList = [ + { + label: 'resources.table.total', + key: 'total', + locale: true, + render: (val: any) => { + return convertFileSize(val, 0); + } + }, + { + label: 'resources.table.used', + key: 'used', + locale: true, + render: (val: any) => { + return convertFileSize(val, 0); + } + }, + { + label: 'resources.table.allocated', + key: 'allocated', + locale: true, + render: (val: any) => { + return convertFileSize(val, 0); + } + } +]; + const GPUList: React.FC = () => { console.log('GPUList======'); const intl = useIntl(); @@ -228,19 +256,10 @@ const GPUList: React.FC = () => { ) * 100 } label={ - - - {intl.formatMessage({ id: 'resources.table.total' })}:{' '} - {convertFileSize(record.memory?.total, 0)} - - - {intl.formatMessage({ id: 'resources.table.used' })}:{' '} - {convertFileSize( - record.memory?.used || record.memory?.allocated, - 0 - )} - - + } > );