feat: cluster_count on dashboard
This commit is contained in:
@@ -154,7 +154,10 @@ const LineChart: React.FC<ChartProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!seriesData.length ? (
|
{!seriesData.length ? (
|
||||||
<EmptyData height={height} title={title}></EmptyData>
|
<EmptyData
|
||||||
|
height={height}
|
||||||
|
title={_.get(title, 'text', title || '')}
|
||||||
|
></EmptyData>
|
||||||
) : (
|
) : (
|
||||||
<Chart
|
<Chart
|
||||||
height={height}
|
height={height}
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ export const DASHBOARD_API = '/dashboard';
|
|||||||
export const DASHBOARD_USAGE_API = `${DASHBOARD_API}/usage`;
|
export const DASHBOARD_USAGE_API = `${DASHBOARD_API}/usage`;
|
||||||
export const DASHBOARD_STATS_API = `${DASHBOARD_API}/usage/stats`;
|
export const DASHBOARD_STATS_API = `${DASHBOARD_API}/usage/stats`;
|
||||||
|
|
||||||
export async function queryDashboardData() {
|
export async function queryDashboardData(params?: { cluster_id?: number }) {
|
||||||
return request(DASHBOARD_API);
|
return request(DASHBOARD_API, {
|
||||||
|
params
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function queryDashboardUsageData<T>(
|
export async function queryDashboardUsageData<T>(
|
||||||
|
|||||||
@@ -1,39 +1,17 @@
|
|||||||
import { memo, useCallback, useEffect, useState } from 'react';
|
|
||||||
import { queryDashboardData } from '../apis';
|
|
||||||
import DashboardContext from '../config/dashboard-context';
|
|
||||||
import { DashboardProps } from '../config/types';
|
|
||||||
import ActiveTable from './active-table';
|
import ActiveTable from './active-table';
|
||||||
import Overview from './over-view';
|
import Overview from './over-view';
|
||||||
import SystemLoad from './system-load';
|
import SystemLoad from './system-load';
|
||||||
import Usage from './usage';
|
import Usage from './usage';
|
||||||
|
|
||||||
const Dashboard: React.FC<{ setLoading: (loading: boolean) => void }> = ({
|
const Dashboard: React.FC = () => {
|
||||||
setLoading
|
|
||||||
}) => {
|
|
||||||
const [data, setData] = useState<DashboardProps>({} as DashboardProps);
|
|
||||||
|
|
||||||
const getDashboardData = useCallback(async () => {
|
|
||||||
try {
|
|
||||||
setLoading(true);
|
|
||||||
const res = await queryDashboardData();
|
|
||||||
setData(res);
|
|
||||||
setLoading(false);
|
|
||||||
} catch (error) {
|
|
||||||
setLoading(false);
|
|
||||||
setData({} as DashboardProps);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
useEffect(() => {
|
|
||||||
getDashboardData();
|
|
||||||
}, []);
|
|
||||||
return (
|
return (
|
||||||
<DashboardContext.Provider value={{ ...data, fetchData: getDashboardData }}>
|
<>
|
||||||
<Overview></Overview>
|
<Overview></Overview>
|
||||||
<SystemLoad></SystemLoad>
|
<SystemLoad></SystemLoad>
|
||||||
<Usage></Usage>
|
<Usage></Usage>
|
||||||
<ActiveTable></ActiveTable>
|
<ActiveTable></ActiveTable>
|
||||||
</DashboardContext.Provider>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(Dashboard);
|
export default Dashboard;
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import LineChart from '@/components/echarts/line-chart';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { memo, useContext, useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import { DashboardContext } from '../config/dashboard-context';
|
|
||||||
|
|
||||||
const TypeKeyMap = {
|
const TypeKeyMap = {
|
||||||
cpu: {
|
cpu: {
|
||||||
@@ -32,9 +31,27 @@ const TypeKeyMap = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const UtilizationOvertime: React.FC = () => {
|
const UtilizationOvertime: React.FC<{
|
||||||
|
data: {
|
||||||
|
cpu: {
|
||||||
|
timestamp: number;
|
||||||
|
value: number;
|
||||||
|
}[];
|
||||||
|
ram: {
|
||||||
|
timestamp: number;
|
||||||
|
value: number;
|
||||||
|
}[];
|
||||||
|
gpu: {
|
||||||
|
timestamp: number;
|
||||||
|
value: number;
|
||||||
|
}[];
|
||||||
|
vram: {
|
||||||
|
timestamp: number;
|
||||||
|
value: number;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}> = ({ data }) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const data = useContext(DashboardContext)?.system_load?.history || {};
|
|
||||||
|
|
||||||
const typeList = ['gpu', 'cpu', 'ram', 'vram'];
|
const typeList = ['gpu', 'cpu', 'ram', 'vram'];
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import CardWrapper from '@/components/card-wrapper';
|
import CardWrapper from '@/components/card-wrapper';
|
||||||
import GaugeChart from '@/components/echarts/gauge';
|
import GaugeChart from '@/components/echarts/gauge';
|
||||||
import PageTools from '@/components/page-tools';
|
import PageTools from '@/components/page-tools';
|
||||||
|
import BaseSelect from '@/components/seal-form/base/select';
|
||||||
|
import { queryClusterList } from '@/pages/cluster-management/apis';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Col, Row } from 'antd';
|
import { Col, Row } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { memo, useContext, useMemo } from 'react';
|
import { useContext, useEffect, useMemo, useState } from 'react';
|
||||||
import { DashboardContext } from '../config/dashboard-context';
|
import { DashboardContext } from '../config/dashboard-context';
|
||||||
import ResourceUtilization from './resource-utilization';
|
import ResourceUtilization from './resource-utilization';
|
||||||
|
|
||||||
@@ -14,9 +16,14 @@ const resourceChartHeight = 400;
|
|||||||
|
|
||||||
const SystemLoad = () => {
|
const SystemLoad = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const data = useContext(DashboardContext)?.system_load?.current || {};
|
const { system_load, fetchData } = useContext(DashboardContext);
|
||||||
|
const [systemLoadData, setSystemLoadData] = useState<any>(system_load || {});
|
||||||
|
const [clusterList, setClusterList] = useState<Global.BaseOption<number>[]>(
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const chartData = useMemo(() => {
|
const chartData = useMemo(() => {
|
||||||
|
const data = systemLoadData?.current || {};
|
||||||
return {
|
return {
|
||||||
gpu: {
|
gpu: {
|
||||||
data: _.round(data.gpu || 0, 1)
|
data: _.round(data.gpu || 0, 1)
|
||||||
@@ -31,7 +38,36 @@ const SystemLoad = () => {
|
|||||||
data: _.round(data.ram || 0, 1)
|
data: _.round(data.ram || 0, 1)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [data]);
|
}, [systemLoadData?.current]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSystemLoadData(system_load || {});
|
||||||
|
}, [system_load]);
|
||||||
|
|
||||||
|
const handleClusterChange = async (value: number) => {
|
||||||
|
try {
|
||||||
|
const res: any = await fetchData({ cluster_id: value });
|
||||||
|
setSystemLoadData(res.system_load || {});
|
||||||
|
} catch (error) {
|
||||||
|
setSystemLoadData({});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchClusters = async () => {
|
||||||
|
try {
|
||||||
|
const res = await queryClusterList({ page: 1, perPage: 100 });
|
||||||
|
const options = res.items.map((cluster) => ({
|
||||||
|
label: cluster.name,
|
||||||
|
value: cluster.id
|
||||||
|
}));
|
||||||
|
setClusterList(options);
|
||||||
|
} catch (error) {
|
||||||
|
setClusterList([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchClusters();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -43,11 +79,22 @@ const SystemLoad = () => {
|
|||||||
{intl.formatMessage({ id: 'dashboard.systemload' })}
|
{intl.formatMessage({ id: 'dashboard.systemload' })}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
right={
|
||||||
|
<BaseSelect
|
||||||
|
allowClear
|
||||||
|
onChange={handleClusterChange}
|
||||||
|
style={{ width: 360 }}
|
||||||
|
options={clusterList}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: 'clusters.filterBy.cluster'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<Row gutter={[20, 20]}>
|
<Row gutter={[20, 20]}>
|
||||||
<Col xs={24} sm={24} md={24} lg={24} xl={16}>
|
<Col xs={24} sm={24} md={24} lg={24} xl={16}>
|
||||||
<CardWrapper style={{ height: resourceChartHeight }}>
|
<CardWrapper style={{ height: resourceChartHeight }}>
|
||||||
<ResourceUtilization />
|
<ResourceUtilization data={systemLoadData?.history} />
|
||||||
</CardWrapper>
|
</CardWrapper>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} sm={24} md={24} lg={24} xl={8}>
|
<Col xs={24} sm={24} md={24} lg={24} xl={8}>
|
||||||
@@ -55,7 +102,6 @@ const SystemLoad = () => {
|
|||||||
<Row style={{ height: largeChartHeight }}>
|
<Row style={{ height: largeChartHeight }}>
|
||||||
<Col span={12} style={{ height: smallChartHeight }}>
|
<Col span={12} style={{ height: smallChartHeight }}>
|
||||||
<GaugeChart
|
<GaugeChart
|
||||||
name="GPU"
|
|
||||||
height={smallChartHeight}
|
height={smallChartHeight}
|
||||||
value={chartData.gpu.data}
|
value={chartData.gpu.data}
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
@@ -65,7 +111,6 @@ const SystemLoad = () => {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={12} style={{ height: smallChartHeight }}>
|
<Col span={12} style={{ height: smallChartHeight }}>
|
||||||
<GaugeChart
|
<GaugeChart
|
||||||
name="VRAM"
|
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
id: 'dashboard.vramutilization'
|
id: 'dashboard.vramutilization'
|
||||||
})}
|
})}
|
||||||
@@ -75,7 +120,6 @@ const SystemLoad = () => {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={12} style={{ height: smallChartHeight }}>
|
<Col span={12} style={{ height: smallChartHeight }}>
|
||||||
<GaugeChart
|
<GaugeChart
|
||||||
name="CPU"
|
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
id: 'dashboard.cpuutilization'
|
id: 'dashboard.cpuutilization'
|
||||||
})}
|
})}
|
||||||
@@ -85,7 +129,6 @@ const SystemLoad = () => {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={12} style={{ height: smallChartHeight }}>
|
<Col span={12} style={{ height: smallChartHeight }}>
|
||||||
<GaugeChart
|
<GaugeChart
|
||||||
name="RAM"
|
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
id: 'dashboard.memoryutilization'
|
id: 'dashboard.memoryutilization'
|
||||||
})}
|
})}
|
||||||
@@ -102,4 +145,4 @@ const SystemLoad = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(SystemLoad);
|
export default SystemLoad;
|
||||||
|
|||||||
@@ -2,7 +2,13 @@ import { createContext } from 'react';
|
|||||||
import { DashboardProps } from './types';
|
import { DashboardProps } from './types';
|
||||||
|
|
||||||
export const DashboardContext = createContext<
|
export const DashboardContext = createContext<
|
||||||
DashboardProps & { fetchData: () => Promise<void> }
|
DashboardProps & {
|
||||||
>({} as DashboardProps & { fetchData: () => Promise<void> });
|
fetchData: (params?: { [key: string]: any }) => Promise<void>;
|
||||||
|
}
|
||||||
|
>(
|
||||||
|
{} as DashboardProps & {
|
||||||
|
fetchData: (params?: { [key: string]: any }) => Promise<void>;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export default DashboardContext;
|
export default DashboardContext;
|
||||||
|
|||||||
@@ -1,19 +1,42 @@
|
|||||||
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import PageBox from '../_components/page-box';
|
import PageBox from '../_components/page-box';
|
||||||
|
import { queryDashboardData } from './apis';
|
||||||
import DashboardInner from './components/dahboard-inner';
|
import DashboardInner from './components/dahboard-inner';
|
||||||
|
import DashboardContext from './config/dashboard-context';
|
||||||
|
import { DashboardProps } from './config/types';
|
||||||
|
|
||||||
const Dashboard: React.FC = () => {
|
const Dashboard: React.FC = () => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [data, setData] = useState<DashboardProps>({} as DashboardProps);
|
||||||
|
|
||||||
|
const getDashboardData = useMemoizedFn(async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const res = await queryDashboardData();
|
||||||
|
setData(res);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false);
|
||||||
|
setData({} as DashboardProps);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getDashboardData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DashboardContext.Provider
|
||||||
|
value={{ ...data, fetchData: queryDashboardData }}
|
||||||
|
>
|
||||||
<PageBox>
|
<PageBox>
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
<DashboardInner setLoading={setLoading} />
|
<DashboardInner />
|
||||||
</Spin>
|
</Spin>
|
||||||
</PageBox>
|
</PageBox>
|
||||||
</>
|
</DashboardContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import SealSelect from '@/components/seal-form/seal-select';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import { useMemo } from 'react';
|
||||||
import { DeployFormKeyMap, modelCategories } from '../config';
|
import { DeployFormKeyMap, modelCategories } from '../config';
|
||||||
import { backendOptionsMap } from '../config/backend-parameters';
|
import { backendOptionsMap } from '../config/backend-parameters';
|
||||||
import { useFormContext } from '../config/form-context';
|
import { useFormContext } from '../config/form-context';
|
||||||
@@ -17,7 +18,11 @@ const AdvanceConfig = () => {
|
|||||||
const form = Form.useFormInstance();
|
const form = Form.useFormInstance();
|
||||||
const EnviromentVars = Form.useWatch('env', form);
|
const EnviromentVars = Form.useWatch('env', form);
|
||||||
const backend = Form.useWatch('backend', form);
|
const backend = Form.useWatch('backend', form);
|
||||||
const { onValuesChange, formKey } = useFormContext();
|
const { onValuesChange, backendOptions, formKey } = useFormContext();
|
||||||
|
|
||||||
|
const currentBackendOptions = useMemo(() => {
|
||||||
|
return backendOptions?.find((item) => item.value === backend);
|
||||||
|
}, [backend, backendOptions]);
|
||||||
|
|
||||||
const handleEnviromentVarsChange = (labels: Record<string, any>) => {
|
const handleEnviromentVarsChange = (labels: Record<string, any>) => {
|
||||||
console.log('handleEnviromentVarsChange', labels);
|
console.log('handleEnviromentVarsChange', labels);
|
||||||
@@ -80,7 +85,23 @@ const AdvanceConfig = () => {
|
|||||||
onChange={handleEnviromentVarsChange}
|
onChange={handleEnviromentVarsChange}
|
||||||
></LabelSelector>
|
></LabelSelector>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
{(backend === backendOptionsMap.custom ||
|
||||||
|
!currentBackendOptions?.isBuiltIn) && (
|
||||||
|
<Form.Item<FormData>
|
||||||
|
name="cpu_offloading"
|
||||||
|
valuePropName="checked"
|
||||||
|
style={{ marginBottom: 8 }}
|
||||||
|
>
|
||||||
|
<CheckboxField
|
||||||
|
description={intl.formatMessage({
|
||||||
|
id: 'models.form.partialoffload.tips'
|
||||||
|
})}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'resources.form.enablePartialOffload'
|
||||||
|
})}
|
||||||
|
></CheckboxField>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
{[backendOptionsMap.vllm, backendOptionsMap.ascendMindie].includes(
|
{[backendOptionsMap.vllm, backendOptionsMap.ascendMindie].includes(
|
||||||
backend
|
backend
|
||||||
) && (
|
) && (
|
||||||
|
|||||||
@@ -366,7 +366,6 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
replicas: 1,
|
replicas: 1,
|
||||||
source: props.source,
|
source: props.source,
|
||||||
placement_strategy: 'spread',
|
placement_strategy: 'spread',
|
||||||
cpu_offloading: true,
|
|
||||||
scheduleType: ScheduleValueMap.Auto,
|
scheduleType: ScheduleValueMap.Auto,
|
||||||
categories: null,
|
categories: null,
|
||||||
restart_on_error: true,
|
restart_on_error: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user