chore: add models and gpus in cluster detail page

This commit is contained in:
jialin
2026-01-12 20:30:24 +08:00
parent 42943a33fe
commit 0cde6f7dbc
11 changed files with 134 additions and 90 deletions
@@ -1,7 +1,11 @@
import { clusterDetailAtom } from '@/atoms/clusters';
import IconFont from '@/components/icon-font';
import Deployments from '@/pages/llmodels/index';
import GPUList from '@/pages/resources/components/gpus';
import WorkerList from '@/pages/resources/components/workers';
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
import { Tabs } from 'antd';
import { useAtomValue } from 'jotai';
import { PageContainerInner } from '../_components/page-box';
import PageBreadcrumb from '../_components/page-breadcrumb';
import ClusterBasic from './components/detail/cluster-basic';
@@ -13,6 +17,7 @@ const ClusterDetailModal = () => {
const [searchParams] = useSearchParams();
const id = searchParams.get('id');
const clusterName = searchParams.get('name');
const clusterDetailData = useAtomValue(clusterDetailAtom);
const breadcrumbItems = [
{
@@ -39,7 +44,7 @@ const ClusterDetailModal = () => {
items={[
{
key: 'workers',
label: 'Workers',
label: `Workers (${clusterDetailData?.workers ?? 0})`,
icon: <IconFont type="icon-resources" />,
children: (
<WorkerList
@@ -53,15 +58,15 @@ const ClusterDetailModal = () => {
},
{
key: 'deployments',
label: 'Deployments',
label: `Deployments (${clusterDetailData?.models ?? 0})`,
icon: <IconFont type="icon-rocket-launch1" />,
children: <div>Deployments Content</div>
children: <Deployments clusterId={Number(id)}></Deployments>
},
{
key: 'gpus',
label: 'GPUs',
label: `GPUs (${clusterDetailData?.gpus ?? 0})`,
icon: <IconFont type="icon-gpu1" />,
children: <div>GPUs Content</div>
children: <GPUList clusterId={Number(id)} widths={{ input: 360 }} />
}
]}
/>
+1 -1
View File
@@ -254,7 +254,7 @@ const Clusters: React.FC = () => {
const handleOnCell = useMemoizedFn((record: ClusterListItem, dataIndex) => {
if (dataIndex === 'name') {
navigate(
`/cluster-management/clusters/detail?id=${record.id}&name=${record.name}`
`/cluster-management/clusters/detail?id=${record.id}&name=${record.name}&page=clusters`
);
}
});
@@ -1,5 +1,5 @@
import CardWrapper from '@/components/card-wrapper';
import { Col, Progress, Row } from 'antd';
import { Col, Progress, Row, Tag } from 'antd';
import { round } from 'lodash';
import React, { useEffect } from 'react';
import styled from 'styled-components';
@@ -11,9 +11,12 @@ const Container = styled.div`
height: 86px;
gap: 16px;
.title {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
font-weight: 500;
color: var(--ant-color-text-secondary);
color: var(--ant-color-text-tertiary);
}
.value-wrapper {
@@ -42,26 +45,30 @@ const ClusterSystemLoad: React.FC<{ clusterId: number }> = ({ clusterId }) => {
}
}, [clusterId]);
const renderStepsProgress = (percent: number) => {
const renderStepsProgress = (
percent: number,
tag: { color: string; text: string }
) => {
return (
<Progress
percent={percent}
size={{
height: 8
}}
styles={{
root: {
width: '100%'
},
track: {
flex: 1
},
body: {
display: 'flex',
width: '100%'
}
}}
showInfo={false}
type="circle"
size={50}
strokeWidth={8}
showInfo={true}
format={() => (
<Tag
color={tag?.color || 'blue'}
style={{
fontSize: 11,
borderRadius: 12,
backgroundColor: 'unset',
fontWeight: 500
}}
>
{tag?.text || ''}
</Tag>
)}
></Progress>
);
};
@@ -73,11 +80,18 @@ const ClusterSystemLoad: React.FC<{ clusterId: number }> = ({ clusterId }) => {
<Col span={6}>
<CardWrapper style={{ padding: '16px', height: 120 }}>
<Container>
<div className="title">GPU Utilization</div>
<div className="title">
<span>GPU Utilization</span>
</div>
<div className="value-wrapper">
<div className="value">
<span>{`${round(systemLoad.current.gpu, 1)}%`}</span>
{renderStepsProgress(round(systemLoad.current.gpu, 1))}
</div>
<div className="chart">
{renderStepsProgress(round(systemLoad.current.gpu, 1), {
color: 'magenta',
text: 'GPU'
})}
</div>
</div>
</Container>
@@ -86,17 +100,16 @@ const ClusterSystemLoad: React.FC<{ clusterId: number }> = ({ clusterId }) => {
<Col span={6}>
<CardWrapper style={{ padding: '16px', height: 120 }}>
<Container>
<div className="title">VRAM Utilization</div>
<div className="title">
<span>VRAM Utilization</span>
</div>
<div className="value-wrapper">
<div className="value">{`${round(systemLoad.current.vram, 1)}%`}</div>
<div className="chart">
<Progress
percent={round(systemLoad.current.vram, 1)}
type="circle"
size={50}
strokeWidth={8}
showInfo={false}
></Progress>
{renderStepsProgress(round(systemLoad.current.vram, 1), {
color: 'purple',
text: 'VRAM'
})}
</div>
</div>
</Container>
@@ -105,11 +118,18 @@ const ClusterSystemLoad: React.FC<{ clusterId: number }> = ({ clusterId }) => {
<Col span={6}>
<CardWrapper style={{ padding: '16px', height: 120 }}>
<Container>
<div className="title">CPU Utilization</div>
<div className="title">
<span>CPU Utilization</span>
</div>
<div className="value-wrapper">
<div className="value">
<span>{`${round(systemLoad.current.cpu, 1)}%`}</span>
{renderStepsProgress(round(systemLoad.current.cpu, 1))}
</div>
<div className="chart">
{renderStepsProgress(round(systemLoad.current.cpu, 1), {
color: 'cyan',
text: 'CPU'
})}
</div>
</div>
</Container>
@@ -118,19 +138,18 @@ const ClusterSystemLoad: React.FC<{ clusterId: number }> = ({ clusterId }) => {
<Col span={6}>
<CardWrapper style={{ padding: '16px', height: 120 }}>
<Container>
<div className="title">Memo Utilization</div>
<div className="title">
<span>Memo Utilization</span>
</div>
<div className="value-wrapper">
<div className="value">
<span>{`${round(systemLoad.current.ram, 1)}%`}</span>
</div>
<div className="chart">
<Progress
percent={round(systemLoad.current.ram, 1)}
type="circle"
size={50}
strokeWidth={8}
showInfo={false}
></Progress>
{renderStepsProgress(round(systemLoad.current.ram, 1), {
color: 'green',
text: 'RAM'
})}
</div>
</div>
</Container>
@@ -6,7 +6,7 @@ import StatusTag from '@/components/status-tag';
import { tableSorter } from '@/config/settings';
import { StarFilled } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Tooltip } from 'antd';
import { Tooltip, Typography } from 'antd';
import dayjs from 'dayjs';
import { useMemo } from 'react';
import {
@@ -42,10 +42,9 @@ const useClusterColumns = (
render: (text: string, record: ClusterListItem) => (
<>
<AutoTooltip ghost title={text}>
{/* <Typography.Link onClick={() => onCellClick?.(record, 'name')}>
<Typography.Link onClick={() => onCellClick?.(record, 'name')}>
{record.name}
</Typography.Link> */}
{record.name}
</Typography.Link>
</AutoTooltip>
{record.is_default && (
<Tooltip
@@ -101,11 +100,12 @@ const useClusterColumns = (
title: intl.formatMessage({ id: 'common.table.status' }),
dataIndex: 'state',
span: 3,
render: (value: number) => (
render: (value: number, record: ClusterListItem) => (
<StatusTag
statusValue={{
status: ClusterStatus[value],
text: ClusterStatusLabelMap[value]
text: ClusterStatusLabelMap[value],
message: record.state_message || undefined
}}
/>
)
@@ -1,6 +1,8 @@
import { clusterDetailAtom } from '@/atoms/clusters';
import { createAxiosToken } from '@/hooks/use-chunk-request';
import { useRequest } from 'ahooks';
import { CancelTokenSource } from 'axios';
import { useAtom } from 'jotai';
import { useEffect, useRef, useState } from 'react';
import { queryClusterDetail, queryClusterItem } from '../apis';
import { ClusterListItem } from '../config/types';
@@ -79,6 +81,7 @@ export const useClusterDetail = () => {
const [clusterDetail, setClusterDetail] = useState<ClusterListItem>(
{} as ClusterListItem
);
const [, setClusterDetailAtom] = useAtom(clusterDetailAtom);
const {
run: fetchClusterDetail,
@@ -96,9 +99,11 @@ export const useClusterDetail = () => {
manual: true,
onSuccess: (response) => {
setClusterDetail(response);
setClusterDetailAtom(response);
},
onError: () => {
setClusterDetail({} as ClusterListItem);
setClusterDetailAtom(null);
}
}
);