diff --git a/config/config.ts b/config/config.ts index a90446cb..3e9ad485 100644 --- a/config/config.ts +++ b/config/config.ts @@ -7,7 +7,7 @@ const DeleteCssPlugin = require('./plugins/delete-css-plugin'); import proxy from './proxy'; import routes from './routes'; const env = process.env.NODE_ENV; -const isProduction = env === 'production'; +const isProduction = env === 'production1'; export default defineConfig({ proxy: { @@ -48,11 +48,11 @@ export default defineConfig({ ignoreOrder: true } ]); - config.plugin('delete-css').use(DeleteCssPlugin, [ - { - outputPath: path.resolve(__dirname, '../', 'dist') - } - ]); + // config.plugin('delete-css').use(DeleteCssPlugin, [ + // { + // outputPath: path.resolve(__dirname, '../', 'dist') + // } + // ]); config.output .filename('js/[name].[contenthash:8].js') .chunkFilename('js/[name].[contenthash:8].chunk.js'); diff --git a/src/components/bar-chart/index.tsx b/src/components/charts/column-bar.tsx similarity index 90% rename from src/components/bar-chart/index.tsx rename to src/components/charts/column-bar.tsx index dab03052..cee60d98 100644 --- a/src/components/bar-chart/index.tsx +++ b/src/components/charts/column-bar.tsx @@ -13,7 +13,6 @@ const BarChart: React.FC = (props) => { data, xField, yField, - title, // colorField: 'name', direction: 'vertical', height, @@ -31,7 +30,12 @@ const BarChart: React.FC = (props) => { xAxis: true } }, - + title: { + title, + style: { + align: 'center' + } + }, split: { type: 'line', line: { @@ -44,7 +48,7 @@ const BarChart: React.FC = (props) => { }, style: { - fill: '#2fbf85', + fill: '#54cc98', radiusTopLeft: 8, radiusTopRight: 8, width: 30 diff --git a/src/components/charts/gauge.tsx b/src/components/charts/gauge.tsx new file mode 100644 index 00000000..5790cc9c --- /dev/null +++ b/src/components/charts/gauge.tsx @@ -0,0 +1,47 @@ +import { Gauge } from '@ant-design/plots'; +import React from 'react'; + +interface GaugeChartProps { + target: number; + total: number; + width?: number; + height?: number; + title?: string; + thresholds: number[]; + rangColor: string[]; +} + +const GaugeChart: React.FC = (props) => { + const { target, total, width, height, thresholds, rangColor, title } = props; + const config = { + width, + height, + autoFit: true, + data: { + target, + total, + name: 'score', + thresholds + }, + legend: false, + scale: { + color: { + range: rangColor + } + }, + title: { + titleFontSize: 14, + style: { + align: 'center' + } + }, + style: { + textContent: (target: number, total: number) => { + return `${(target / total) * 100}%`; + } + } + }; + return ; +}; + +export default GaugeChart; diff --git a/src/components/bar-chart/h-bar.tsx b/src/components/charts/h-bar.tsx similarity index 90% rename from src/components/bar-chart/h-bar.tsx rename to src/components/charts/h-bar.tsx index d7d1e229..12edd9fc 100644 --- a/src/components/bar-chart/h-bar.tsx +++ b/src/components/charts/h-bar.tsx @@ -13,7 +13,6 @@ const BarChart: React.FC = (props) => { data, xField, yField, - title, // colorField: 'name', direction: 'vertical', height, @@ -31,7 +30,12 @@ const BarChart: React.FC = (props) => { xAxis: true } }, - + title: { + title, + style: { + align: 'center' + } + }, split: { type: 'line', line: { @@ -44,7 +48,7 @@ const BarChart: React.FC = (props) => { }, style: { - fill: '#2fbf85', + fill: '#54cc98', radiusTopLeft: 8, radiusTopRight: 8, height: 30 diff --git a/src/components/charts/line-chart.tsx b/src/components/charts/line-chart.tsx new file mode 100644 index 00000000..aea2ec27 --- /dev/null +++ b/src/components/charts/line-chart.tsx @@ -0,0 +1,58 @@ +import { Line } from '@ant-design/plots'; + +interface LineChartProps { + title?: string; + height?: number; + data: any[]; + color?: string[]; + xField?: string; + yField?: string; + slider?: boolean; +} +const LineChart: React.FC = (props) => { + const { data, title, color, xField, yField, slider, height } = props; + const config = { + title, + height, + xField: xField || 'time', + yField: yField || 'value', + color: color || ['red', 'blue', 'green'], + colorField: 'type', + autoFit: true, + slider, + shapeField: 'smooth', + axis: { + x: { + textStyle: { + autoRoate: true + } + } + }, + point: { + shapeField: 'circle', + sizeField: 2 + }, + style: { + lineWidth: 1.5 + }, + legend: { + itemMarker: { + symbol: 'circle' + }, + color: { + layout: { justifyContent: 'center' } + } + }, + tooltip: { + title: 'time', + items: [{ channel: 'y' }] + } + }; + return ( + <> + + + ); +}; + +export default LineChart; diff --git a/src/global.less b/src/global.less index 034edd0a..43407303 100644 --- a/src/global.less +++ b/src/global.less @@ -26,6 +26,9 @@ html { --ant-table-row-selected-bg: #f0fff6; --ant-table-row-selected-hover-bg: #d8f2e4; --ant-table-row-hover-bg: #e6e6e6; + --color-chart-red: #ff7875; + --color-chart-green: #54cc98; + --color-chart-glod: #ffd666; // --color-text-1: #000; --seal-transition-func: cubic-bezier(0, 0, 1, 1); diff --git a/src/pages/dashboard/components/active-table.tsx b/src/pages/dashboard/components/active-table.tsx new file mode 100644 index 00000000..0a94be9e --- /dev/null +++ b/src/pages/dashboard/components/active-table.tsx @@ -0,0 +1,161 @@ +import ContentWrapper from '@/components/content-wrapper'; +import { Col, Row, Table } from 'antd'; + +const modelColumns = [ + { + title: 'Name', + dataIndex: 'name', + key: 'name' + }, + { + title: 'Allocated GPUs', + dataIndex: 'allocated', + key: 'allocated', + render: (text: any, record: any) => {record.gpu.allocated} + }, + { + title: 'GPU Utilization', + dataIndex: 'utilization', + key: 'utilization', + render: (text: any, record: any) => {record.gpu.utilization} + }, + { + title: 'Running Instances', + dataIndex: 'running', + key: 'running', + render: (text: any, record: any) => {record.instances.running} + }, + { + title: 'Pending Instances', + dataIndex: 'pending', + key: 'pending', + render: (text: any, record: any) => {record.instances.pending} + } +]; + +const projectColumns = [ + { + title: 'Name', + dataIndex: 'name', + key: 'name' + }, + { + title: 'Token Quota', + dataIndex: 'quota', + key: 'quota' + }, + { + title: 'Token Utilization', + dataIndex: 'utilization', + key: 'utilization' + }, + { + title: 'Members', + dataIndex: 'members', + key: 'members' + } +]; + +const modelData = [ + { + id: 1, + name: 'qwen2', + gpu: { allocated: 4, utilization: '50%' }, + instances: { running: 1, pending: 0 } + }, + { + id: 2, + name: 'llama3:70b', + gpu: { allocated: 3, utilization: '70%' }, + instances: { running: 1, pending: 0 } + }, + { + id: 3, + name: 'llama3', + gpu: { allocated: 5, utilization: '20%' }, + instances: { running: 1, pending: 0 } + }, + { + id: 4, + name: 'gemma', + gpu: { allocated: 1, utilization: '25%' }, + instances: { running: 1, pending: 0 } + }, + { + id: 5, + name: 'phi3', + gpu: { allocated: 2, utilization: '46%' }, + instances: { running: 1, pending: 0 } + } +]; + +const projectData = [ + { + id: 1, + name: 'copilot-dev', + quota: 100, + utilization: 50, + members: 4 + }, + { + id: 2, + name: 'rag-wiki', + quota: 200, + utilization: 70, + members: 3 + }, + { + id: 3, + name: 'smart-auto-agent', + quota: 100, + utilization: 20, + members: 5 + }, + { + id: 4, + name: 'office-auto-docs', + quota: 100, + utilization: 25, + members: 1 + }, + { + id: 5, + name: 'smart-customer-service', + quota: 100, + utilization: 46, + members: 2 + } +]; +const ActiveTable = () => { + return ( + + + Active Models} + > + + + + + Active Projects} + > +
+ + + + ); +}; + +export default ActiveTable; diff --git a/src/pages/dashboard/components/utilization-overtime.tsx b/src/pages/dashboard/components/resource-utilization.tsx similarity index 53% rename from src/pages/dashboard/components/utilization-overtime.tsx rename to src/pages/dashboard/components/resource-utilization.tsx index 078e0ae6..fd5bb50c 100644 --- a/src/pages/dashboard/components/utilization-overtime.tsx +++ b/src/pages/dashboard/components/resource-utilization.tsx @@ -1,6 +1,5 @@ -import PageTools from '@/components/page-tools'; +import LineChart from '@/components/charts/line-chart'; import { generateRandomArray } from '@/utils'; -import { Line } from '@ant-design/plots'; import _ from 'lodash'; const mockData = { @@ -43,50 +42,10 @@ const UtilizationOvertime: React.FC = () => { }; const data = generateData(); - const handleSelectDate = (date: string) => { - console.log('dateString============', date); - }; - const config = { - // title: 'Resource Utilization', - xField: 'time', - yField: 'value', - color: ['red', 'blue', 'green'], - colorField: 'type', - autoFit: true, - slider: false, - shapeField: 'smooth', - axis: { - x: { - textStyle: { - autoRoate: true - } - } - }, - point: { - shapeField: 'circle', - sizeField: 2 - }, - style: { - lineWidth: 1.4 - }, - legend: { - color: { - layout: { justifyContent: 'center' } - } - }, - tooltip: { - title: 'time', - items: [{ channel: 'y' }] - } - // label: { - // autoRotate: true - // } - }; // return ( <> - - + ); }; diff --git a/src/pages/dashboard/components/system-load.tsx b/src/pages/dashboard/components/system-load.tsx new file mode 100644 index 00000000..69e955b9 --- /dev/null +++ b/src/pages/dashboard/components/system-load.tsx @@ -0,0 +1,68 @@ +import GaugeChart from '@/components/charts/gauge'; +import PageTools from '@/components/page-tools'; +import { Col, DatePicker, Row } from 'antd'; +import ResourceUtilization from './resource-utilization'; + +const SystemLoad = () => { + const handleSelectDate = (date: string) => { + console.log('dateString============', date); + }; + + return ( +
+ + } + /> + + +
+ + + + + + + + + + + + + + ); +}; + +export default SystemLoad; diff --git a/src/pages/dashboard/components/usage.tsx b/src/pages/dashboard/components/usage.tsx new file mode 100644 index 00000000..567e0989 --- /dev/null +++ b/src/pages/dashboard/components/usage.tsx @@ -0,0 +1,156 @@ +import ColumnBar from '@/components/charts/column-bar'; +import HBar from '@/components/charts/h-bar'; +import PageTools from '@/components/page-tools'; +import { generateRandomArray } from '@/utils'; +import { PageContainer } from '@ant-design/pro-components'; +import { Col, DatePicker, Row } from 'antd'; + +const times = [ + 'june 1', + 'june 2', + 'june 3', + 'june 4', + 'june 5', + 'june 6', + 'june 7' +]; + +const users = ['Jim', 'Lucy', 'Lily', 'Tom', 'Jack', 'Rose', 'Jerry']; +const projects = [ + 'copilot-dev', + 'rag-wiki', + 'smart-auto-agent', + 'office-auto-docs', + 'smart-customer-service' +]; + +const APIRequestData = generateRandomArray({ + length: times.length, + max: 100, + min: 0, + offset: 10 +}); + +const TokensData = generateRandomArray({ + length: times.length, + max: 2000, + min: 200, + offset: 200 +}); + +const usersData = generateRandomArray({ + length: users.length, + max: 100, + min: 0, + offset: 10 +}); + +const projectsData = generateRandomArray({ + length: projects.length, + max: 100, + min: 0, + offset: 10 +}); + +const userDataList = usersData + .map((val, i) => { + return { + time: users[i], + value: val + }; + }) + .sort((a, b) => b.value - a.value); + +const projectDataList = projectsData + .map((val, i) => { + return { + time: projects[i], + value: val + }; + }) + .sort((a, b) => b.value - a.value); + +const dataList = APIRequestData.map((val, i) => { + console.log('val', val); + return { + time: times[i], + value: val + }; +}); +const tokenUsage = TokensData.map((val, i) => { + console.log('val', val); + return { + time: times[i], + value: val + }; +}); + +const Usage = () => { + const handleSelectDate = (dateString: string) => { + console.log('dateString============', dateString); + }; + return ( + <> + + + } + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Usage; diff --git a/src/pages/dashboard/index.tsx b/src/pages/dashboard/index.tsx index fc29d0dd..1c062c6a 100644 --- a/src/pages/dashboard/index.tsx +++ b/src/pages/dashboard/index.tsx @@ -1,94 +1,10 @@ -import BarChart from '@/components/bar-chart'; -import HBar from '@/components/bar-chart/h-bar'; -import ContentWrapper from '@/components/content-wrapper'; import DividerLine from '@/components/divider-line'; -import PageTools from '@/components/page-tools'; -import { generateRandomArray } from '@/utils'; import { PageContainer } from '@ant-design/pro-components'; -import { Col, Row } from 'antd'; -import GPUUtilization from './components/gpu-utilization'; +import ActiveTable from './components/active-table'; import Overview from './components/over-view'; -import UtilizationOvertime from './components/utilization-overtime'; +import SystemLoad from './components/system-load'; +import Usage from './components/usage'; -const times = [ - 'june 1', - 'june 2', - 'june 3', - 'june 4', - 'june 5', - 'june 6', - 'june 7' -]; - -const users = ['Jim', 'Lucy', 'Lily', 'Tom', 'Jack', 'Rose', 'Jerry']; -const projects = [ - 'copilot-dev', - 'rag-wiki', - 'smart-auto-agent', - 'office-auto-docs', - 'smart-customer-service' -]; - -const APIRequestData = generateRandomArray({ - length: times.length, - max: 100, - min: 0, - offset: 10 -}); - -const TokensData = generateRandomArray({ - length: times.length, - max: 2000, - min: 200, - offset: 200 -}); - -const usersData = generateRandomArray({ - length: users.length, - max: 100, - min: 0, - offset: 10 -}); - -const projectsData = generateRandomArray({ - length: projects.length, - max: 100, - min: 0, - offset: 10 -}); - -const userDataList = usersData - .map((val, i) => { - return { - time: users[i], - value: val - }; - }) - .sort((a, b) => b.value - a.value); - -const projectDataList = projectsData - .map((val, i) => { - return { - time: projects[i], - value: val - }; - }) - .sort((a, b) => b.value - a.value); - -const dataList = APIRequestData.map((val, i) => { - console.log('val', val); - return { - time: times[i], - value: val - }; -}); -const tokenUsage = TokensData.map((val, i) => { - console.log('val', val); - return { - time: times[i], - value: val - }; -}); const Dashboard: React.FC = () => { return ( <> @@ -97,97 +13,12 @@ const Dashboard: React.FC = () => { - + - - - - - VRAM - - } - > - - - - - GPU Utilization - - } - > - - - - + - - - API Request} - > - - - - - Tokens} - > - - - - - - - Top Users} - > - - - - - Top Projects} - > - - - - + ); };