import { systemConfigAtom } from '@/atoms/system'; import { GPUStackVersionAtom } from '@/atoms/user'; import { tableSorter } from '@/config/settings'; import { convertFileSize } from '@/utils'; import { DeleteOutlined, DownloadOutlined, EditOutlined, InfoCircleOutlined, SafetyOutlined, ToolOutlined } from '@ant-design/icons'; import { AutoTooltip, DropdownButtons, GrafanaIcon, IconFont, InfoColumn, LabelCell, ProgressBar, StatusTag } from '@gpustack/core-ui'; import { useIntl } from '@umijs/max'; import { Tooltip } from 'antd'; import { ColumnsType } from 'antd/lib/table'; import { useAtom, useAtomValue } from 'jotai'; import _ from 'lodash'; import { useMemo } from 'react'; import semverCoerce from 'semver/functions/coerce'; import semverGt from 'semver/functions/gt'; import { status, WorkerStatusMap, WorkerStatusMapValue } from '../config'; import { Filesystem, GPUDeviceItem, ListItem } from '../config/types'; import workerCss from '../styles/worker.less'; const ActionList = [ { label: 'common.button.edit', key: 'edit', icon: }, { label: 'resources.metrics.details', key: 'metrics', icon: ( ) }, // { // label: 'common.button.detail', // key: 'details', // icon: // }, { label: 'resources.worker.download.privatekey', key: 'download_ssh_key', icon: }, { label: 'resources.worker.maintenance.enable', key: 'star_maintenance', icon: }, { label: 'resources.worker.maintenance.disable', key: 'stop_maintenance', icon: }, // { // label: 'common.button.logs', // locale: false, // key: 'logs', // icon: // }, // { label: 'common.button.terminal', key: 'terminal', icon: }, { label: 'common.button.delete', key: 'delete', props: { danger: true }, icon: } ]; const fieldList = [ { label: 'resources.table.total', key: 'total', locale: true, render: (val: any) => convertFileSize(val, 0) }, { label: 'resources.table.used', key: 'used', locale: true, render: (val: any) => convertFileSize(val, 0) }, { label: 'resources.table.allocated', key: 'allocated', locale: true, render: (val: any) => convertFileSize(val, 0) } ]; const showUpgrade = ( workerVersion: string, currentVersion: string ): boolean => { const w_ver = semverCoerce(workerVersion); const c_ver = semverCoerce(currentVersion); return !!w_ver && !!c_ver && semverGt(c_ver, w_ver); }; const formateUtilization = (val1: number, val2: number): number => val1 && val2 ? _.round((val1 / val2) * 100, 0) : 0; const calcStorage = (files: Filesystem[]) => { const mountRoot = _.find( files, (item: Filesystem) => item.mount_point === '/' ); return mountRoot ? formateUtilization(mountRoot.used, mountRoot.total) : 0; }; const GPUCell = ({ devices }: { devices: GPUDeviceItem[] }) => ( {_.map( _.sortBy(devices || [], ['index']), (item: GPUDeviceItem, index: number) => ( [{item.index}] {item.core ? ( ) : ( '-' )} ) )} ); const VRAMCell = ({ devices, intl, rIndex, loadend, firstLoad }: { devices: GPUDeviceItem[]; intl: any; rIndex: number; loadend: boolean; firstLoad: boolean; }) => ( {_.map( _.sortBy(devices || [], ['index']), (item: GPUDeviceItem, index: number) => ( [{item.index}] } /> {item.memory.is_unified_memory && ( )} ) )} ); const StorageCell = ({ files }: { files: Filesystem[] }) => { const mountRoot = _.find( files, (item: Filesystem) => item.mount_point === '/' ); return ( f.key !== 'allocated')} data={mountRoot} /> ) : ( 0 ) } /> ); }; const statusAvailable = (record: ListItem) => { return ( WorkerStatusMap.initializing !== record.state && WorkerStatusMap.provisioning !== record.state && record.status ); }; const HolderStatus = () => { return N/A; }; const useWorkerColumns = ({ clusterData, loadend, firstLoad, sortOrder, handleSelect }: { clusterData: { list: Global.BaseOption[]; data: Record; }; loadend: boolean; firstLoad: boolean; sortOrder: string[]; handleSelect: (action: string, record: ListItem) => void; }): ColumnsType => { const intl = useIntl(); const systemConfig = useAtomValue(systemConfigAtom); const [version] = useAtom(GPUStackVersionAtom); console.log('version in useWorkerColumns', version); const renderIP = (text: string, record: ListItem) => { if (record.advertise_address === record.ip) { return {record.ip}; } if ( record.advertise_address !== record.ip && record.advertise_address && record.ip ) { return ( {record.ip} {`(${intl.formatMessage({ id: 'clusters.table.ip.internal' })})`} {record.advertise_address} {`(${intl.formatMessage({ id: 'clusters.table.ip.external' })})`} ); } return ( {record.ip || record.advertise_address || ''} ); }; const setActions = (row: ListItem) => { return ActionList.filter((action) => { if (action.key === 'download_ssh_key') { return !!row.ssh_key_id; } if (action.key === 'star_maintenance') { return !row.maintenance?.enabled; } if (action.key === 'stop_maintenance') { return row.maintenance?.enabled; } if (action.key === 'metrics') { return systemConfig.showMonitoring; } return true; }); }; const renderVersionInfo = (record: ListItem) => { const shouldUpgrade = showUpgrade(record.worker_version, version.version); const defaultVersionInfo = ( {intl.formatMessage( { id: 'resources.worker.version' }, { version: version.version } )} ); const upgradeVersionInfo = ( {intl.formatMessage( { id: 'resources.worker.version' }, { version: record.worker_version } )} {intl.formatMessage( { id: 'resources.server.version' }, { version: version.version } )} ); return ( {shouldUpgrade && ( {intl.formatMessage({ id: 'resoureces.worker.upgrade.tips' })} )} {shouldUpgrade ? upgradeVersionInfo : defaultVersionInfo} {intl.formatMessage( { id: 'resources.driver.version' }, { version: _.get( record, 'status.gpu_devices[0].driver_version' ) } )} } > {shouldUpgrade ? ( ) : ( )} ); }; return useMemo>( () => [ { title: intl.formatMessage({ id: 'common.table.name' }), dataIndex: 'name', width: 140, sorter: tableSorter(1), render: (text: string, record: ListItem) => ( {text} {renderVersionInfo(record)} ) }, { title: intl.formatMessage({ id: 'resources.table.labels' }), dataIndex: 'labels', width: 200, render: (_, record) => }, { title: intl.formatMessage({ id: 'clusters.title' }), dataIndex: 'cluster_id', render: (id: number) => ( {_.get(clusterData.data, id, '')} ) }, { title: intl.formatMessage({ id: 'common.table.status' }), dataIndex: 'state', sorter: tableSorter(2), render: (_, record) => ( ) }, { title: 'IP', dataIndex: 'ip', sorter: tableSorter(3), render: (text: string, record) => ( {renderIP(text, record)} ) }, { title: 'CPU', dataIndex: 'status.cpu.utilization_rate', sorter: tableSorter(4), 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) ? ( } /> ) : ( )} ) }, { title: 'GPU', dataIndex: 'gpu', render: (_, record) => statusAvailable(record) ? ( ) : ( ) }, { title: intl.formatMessage({ id: 'resources.table.vram' }), dataIndex: 'vram', render: (_, record, rIndex) => statusAvailable(record) ? ( ) : ( ) }, { title: intl.formatMessage({ id: 'resources.table.disk' }), dataIndex: 'storage', render: (_, record) => ( {statusAvailable(record) ? ( ) : ( )} ) }, { title: intl.formatMessage({ id: 'common.table.operation' }), key: 'operation', render: (_, record) => ( handleSelect(val, record)} /> ) } ], [intl, sortOrder, clusterData, loadend, firstLoad, handleSelect] ); }; export default useWorkerColumns;