style: dashboard style
This commit is contained in:
@@ -1,8 +1,5 @@
|
|||||||
import { defineConfig } from '@umijs/max';
|
import { defineConfig } from '@umijs/max';
|
||||||
const path = require('path');
|
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
||||||
const CompressionWebpackPlugin = require('compression-webpack-plugin');
|
const CompressionWebpackPlugin = require('compression-webpack-plugin');
|
||||||
const DeleteCssPlugin = require('./plugins/delete-css-plugin');
|
|
||||||
|
|
||||||
import proxy from './proxy';
|
import proxy from './proxy';
|
||||||
import routes from './routes';
|
import routes from './routes';
|
||||||
@@ -17,23 +14,6 @@ export default defineConfig({
|
|||||||
base: process.env.npm_config_base || '/',
|
base: process.env.npm_config_base || '/',
|
||||||
...(isProduction
|
...(isProduction
|
||||||
? {
|
? {
|
||||||
// extraBabelPlugins: [
|
|
||||||
// [
|
|
||||||
// 'babel-plugin-named-asset-import',
|
|
||||||
// {
|
|
||||||
// loaderMap: {
|
|
||||||
// css: {
|
|
||||||
// loader: 'css-loader',
|
|
||||||
// options: {
|
|
||||||
// modules: {
|
|
||||||
// localIdentName: 'css/[name]__[local]___[hash:base64:5]'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// ],
|
|
||||||
scripts: [
|
scripts: [
|
||||||
{
|
{
|
||||||
src: `/js/umi.${t}.js`
|
src: `/js/umi.${t}.js`
|
||||||
|
|||||||
+7
-7
@@ -7,14 +7,14 @@ export default [
|
|||||||
redirect: '/dashboard'
|
redirect: '/dashboard'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'dashboard',
|
name: 'Dashboard',
|
||||||
path: '/dashboard',
|
path: '/dashboard',
|
||||||
key: 'dashboard',
|
key: 'dashboard',
|
||||||
icon: 'home',
|
icon: 'home',
|
||||||
component: './dashboard'
|
component: './dashboard'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'playground',
|
name: 'Playground',
|
||||||
title: 'Playground',
|
title: 'Playground',
|
||||||
path: '/playground',
|
path: '/playground',
|
||||||
key: 'playground',
|
key: 'playground',
|
||||||
@@ -22,14 +22,14 @@ export default [
|
|||||||
component: './playground'
|
component: './playground'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'models',
|
name: 'Models',
|
||||||
path: '/models',
|
path: '/models',
|
||||||
key: 'models',
|
key: 'models',
|
||||||
icon: 'Block',
|
icon: 'Block',
|
||||||
component: './llmodels'
|
component: './llmodels'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'resources',
|
name: 'Resources',
|
||||||
path: '/resources',
|
path: '/resources',
|
||||||
key: 'resources',
|
key: 'resources',
|
||||||
icon: 'CloudServer',
|
icon: 'CloudServer',
|
||||||
@@ -43,14 +43,14 @@ export default [
|
|||||||
component: './api-keys'
|
component: './api-keys'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'users',
|
name: 'Users',
|
||||||
path: '/users',
|
path: '/users',
|
||||||
key: 'users',
|
key: 'users',
|
||||||
icon: 'Team',
|
icon: 'Team',
|
||||||
component: './users'
|
component: './users'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'profile',
|
name: 'Profile',
|
||||||
path: '/profile',
|
path: '/profile',
|
||||||
key: 'profile',
|
key: 'profile',
|
||||||
hideInMenu: true,
|
hideInMenu: true,
|
||||||
@@ -58,7 +58,7 @@ export default [
|
|||||||
icon: 'User'
|
icon: 'User'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'login',
|
name: 'Login',
|
||||||
path: '/login',
|
path: '/login',
|
||||||
key: 'login',
|
key: 'login',
|
||||||
layout: false,
|
layout: false,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
.ant-pro-layout {
|
.ant-pro-layout {
|
||||||
.ant-pro-sider {
|
.ant-pro-sider {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
&.ant-layout-sider {
|
// &.ant-layout-sider {
|
||||||
background: var(--color-white-1);
|
// background: var(--color-white-1);
|
||||||
}
|
// }
|
||||||
.ant-layout-sider-children {
|
.ant-layout-sider-children {
|
||||||
background-color: var(--color-fill-1);
|
background-color: var(--color-fill-1);
|
||||||
border-inline: none;
|
border-inline: none;
|
||||||
@@ -11,12 +11,15 @@
|
|||||||
padding-inline: 16px;
|
padding-inline: 16px;
|
||||||
padding-block-end: 12px;
|
padding-block-end: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-right {
|
.umi-plugin-layout-right {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.umi-plugin-layout-action {
|
.umi-plugin-layout-action {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: var(--menu-border-radius-base);
|
border-radius: var(--menu-border-radius-base);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-white-1);
|
background-color: var(--color-white-1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,14 +29,18 @@ const GaugeChart: React.FC<GaugeChartProps> = (props) => {
|
|||||||
range: rangColor
|
range: rangColor
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
startAngle: Math.PI,
|
||||||
|
endAngle: 0,
|
||||||
title: {
|
title: {
|
||||||
// title,
|
title,
|
||||||
|
size: 0,
|
||||||
titleFontSize: 14,
|
titleFontSize: 14,
|
||||||
style: {
|
style: {
|
||||||
align: 'center'
|
align: 'center'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
|
arcShape: 'round',
|
||||||
textContent: (target: number, total: number) => {
|
textContent: (target: number, total: number) => {
|
||||||
return `${(target / total) * 100}%`;
|
return `${(target / total) * 100}%`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { Pie } from '@ant-design/plots';
|
||||||
|
import numeral from 'numeral';
|
||||||
|
|
||||||
|
interface PieChartProps {
|
||||||
|
data: { label: string; value: number }[];
|
||||||
|
height?: number;
|
||||||
|
radius?: number;
|
||||||
|
}
|
||||||
|
const PieChart: React.FC<PieChartProps> = (props) => {
|
||||||
|
const { data, height = 340, radius = 0.9 } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Pie
|
||||||
|
height={height}
|
||||||
|
radius={radius}
|
||||||
|
angleField="value"
|
||||||
|
colorField="label"
|
||||||
|
data={data}
|
||||||
|
legend={{
|
||||||
|
color: {
|
||||||
|
position: 'bottom',
|
||||||
|
layout: {
|
||||||
|
justifyContent: 'center'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
label={{
|
||||||
|
position: 'outside',
|
||||||
|
text: (item: { label: number; value: number }) => {
|
||||||
|
return `${item.label}: ${numeral(item.value).format('0,0')}`;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PieChart;
|
||||||
@@ -6,17 +6,27 @@ type PageToolsProps = {
|
|||||||
right?: React.ReactNode;
|
right?: React.ReactNode;
|
||||||
marginBottom?: number;
|
marginBottom?: number;
|
||||||
marginTop?: number;
|
marginTop?: number;
|
||||||
|
style?: React.CSSProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PageTools: React.FC<PageToolsProps> = (props) => {
|
const PageTools: React.FC<PageToolsProps> = (props) => {
|
||||||
const { left, right, marginBottom = 0, marginTop = 70 } = props;
|
const {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
marginBottom = 0,
|
||||||
|
marginTop = 70,
|
||||||
|
style: pageStyle
|
||||||
|
} = props;
|
||||||
|
|
||||||
const newStyle: Record<string, string> = useMemo(() => {
|
const newStyle: React.CSSProperties = useMemo(() => {
|
||||||
const style: Record<string, string> = {};
|
const style: React.CSSProperties = {};
|
||||||
style.marginBottom = `${marginBottom}px`;
|
style.marginBottom = `${marginBottom}px`;
|
||||||
style.marginTop = `${marginTop}px`;
|
style.marginTop = `${marginTop}px`;
|
||||||
|
if (pageStyle) {
|
||||||
|
Object.assign(style, pageStyle);
|
||||||
|
}
|
||||||
return style;
|
return style;
|
||||||
}, [marginBottom, marginTop]);
|
}, [marginBottom, marginTop, pageStyle]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page-tools" style={newStyle}>
|
<div className="page-tools" style={newStyle}>
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
font-size: var(--font-size-base);
|
font-size: var(--font-size-base);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
|
&.download {
|
||||||
|
background-color: rgb(47 191 133 / 30%);
|
||||||
|
}
|
||||||
|
|
||||||
.download {
|
.download {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@@ -48,7 +48,9 @@ const StatusTag: React.FC<StatusTagProps> = ({ statusValue, download }) => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className={classNames('status-tag')}
|
className={classNames('status-tag', {
|
||||||
|
download: download?.percent
|
||||||
|
})}
|
||||||
style={
|
style={
|
||||||
download
|
download
|
||||||
? {
|
? {
|
||||||
|
|||||||
+25
-4
@@ -31,8 +31,6 @@ html {
|
|||||||
--color-chart-red: #ff7875;
|
--color-chart-red: #ff7875;
|
||||||
--color-chart-green: #54cc98;
|
--color-chart-green: #54cc98;
|
||||||
--color-chart-glod: #ffd666;
|
--color-chart-glod: #ffd666;
|
||||||
// --color-text-1: #000;
|
|
||||||
|
|
||||||
--seal-transition-func: cubic-bezier(0, 0, 1, 1);
|
--seal-transition-func: cubic-bezier(0, 0, 1, 1);
|
||||||
// ======== input ============
|
// ======== input ============
|
||||||
--ant-input-active-shadow: 0 0 0 2px rgba(5, 255, 105, 6%);
|
--ant-input-active-shadow: 0 0 0 2px rgba(5, 255, 105, 6%);
|
||||||
@@ -129,8 +127,10 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// table
|
// table
|
||||||
.ant-table-wrapper .ant-table-selection-column {
|
.ant-table-wrapper {
|
||||||
padding-inline-start: 16px !important;
|
.ant-table-selection-column {
|
||||||
|
padding-inline-start: 16px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-table-container .ant-table-content table {
|
.ant-table-container .ant-table-content table {
|
||||||
@@ -245,6 +245,10 @@ body {
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-pro-layout-bg-list {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
.ant-pro-layout-container {
|
.ant-pro-layout-container {
|
||||||
background-color: var(--color-fill-2);
|
background-color: var(--color-fill-2);
|
||||||
}
|
}
|
||||||
@@ -271,6 +275,23 @@ body {
|
|||||||
.monaco-editor {
|
.monaco-editor {
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
}
|
}
|
||||||
|
// .background {
|
||||||
|
// position: fixed;
|
||||||
|
// top: 0;
|
||||||
|
// left: 0;
|
||||||
|
// bottom: 0;
|
||||||
|
// right: 0;
|
||||||
|
// background: radial-gradient(
|
||||||
|
// circle,
|
||||||
|
// rgba(47, 191, 133, 0.02),
|
||||||
|
// rgba(55, 125, 184, 0.2)
|
||||||
|
// );
|
||||||
|
// filter: blur(100px);
|
||||||
|
// height: 100%;
|
||||||
|
// }
|
||||||
|
.ant-pro-page-container {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes skeleton-loading {
|
@keyframes skeleton-loading {
|
||||||
0% {
|
0% {
|
||||||
|
|||||||
+88
-87
@@ -1,7 +1,5 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
|
||||||
/// <reference types="@ant-design/pro-components" />
|
|
||||||
|
|
||||||
import { useAccessMarkedRoutes } from '@@/plugin-access';
|
import { useAccessMarkedRoutes } from '@@/plugin-access';
|
||||||
import { useModel } from '@@/plugin-model';
|
import { useModel } from '@@/plugin-model';
|
||||||
import { ProLayout } from '@ant-design/pro-components';
|
import { ProLayout } from '@ant-design/pro-components';
|
||||||
@@ -141,97 +139,100 @@ export default (props: any) => {
|
|||||||
);
|
);
|
||||||
console.log('route===========', route);
|
console.log('route===========', route);
|
||||||
return (
|
return (
|
||||||
<ProLayout
|
<div>
|
||||||
route={route}
|
<div className="background"></div>
|
||||||
location={location}
|
<ProLayout
|
||||||
title={userConfig.title}
|
route={route}
|
||||||
navTheme="light"
|
location={location}
|
||||||
siderWidth={270}
|
title={userConfig.title}
|
||||||
onMenuHeaderClick={(e) => {
|
navTheme="light"
|
||||||
e.stopPropagation();
|
siderWidth={270}
|
||||||
e.preventDefault();
|
onMenuHeaderClick={(e) => {
|
||||||
navigate('/');
|
e.stopPropagation();
|
||||||
}}
|
e.preventDefault();
|
||||||
onPageChange={(route) => {
|
navigate('/');
|
||||||
console.log('onRouteChange', route);
|
}}
|
||||||
const { location } = history;
|
onPageChange={(route) => {
|
||||||
// 如果没有登录,重定向到 login
|
console.log('onRouteChange', route);
|
||||||
// if (!initialState?.currentUser && location.pathname !== loginPath) {
|
const { location } = history;
|
||||||
// history.push(loginPath);
|
// 如果没有登录,重定向到 login
|
||||||
// }
|
// if (!initialState?.currentUser && location.pathname !== loginPath) {
|
||||||
}}
|
// history.push(loginPath);
|
||||||
formatMessage={userConfig.formatMessage || formatMessage}
|
// }
|
||||||
menu={{ locale: userConfig.locale }}
|
}}
|
||||||
logo={Logo}
|
formatMessage={userConfig.formatMessage || formatMessage}
|
||||||
menuItemRender={(menuItemProps, defaultDom) => {
|
menu={{ locale: userConfig.locale }}
|
||||||
console.log('meurender=========', { defaultDom });
|
logo={Logo}
|
||||||
if (menuItemProps.isUrl || menuItemProps.children) {
|
menuItemRender={(menuItemProps, defaultDom) => {
|
||||||
return defaultDom;
|
console.log('meurender=========', { defaultDom });
|
||||||
}
|
if (menuItemProps.isUrl || menuItemProps.children) {
|
||||||
if (menuItemProps.path && location.pathname !== menuItemProps.path) {
|
return defaultDom;
|
||||||
return (
|
|
||||||
// handle wildcard route path, for example /slave/* from qiankun
|
|
||||||
<Link
|
|
||||||
to={menuItemProps.path.replace('/*', '')}
|
|
||||||
target={menuItemProps.target}
|
|
||||||
>
|
|
||||||
{defaultDom}
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <>{defaultDom}</>;
|
|
||||||
}}
|
|
||||||
itemRender={(route, _, routes) => {
|
|
||||||
const { breadcrumbName, title, path } = route;
|
|
||||||
const label = title || breadcrumbName;
|
|
||||||
const last = routes[routes.length - 1];
|
|
||||||
if (last) {
|
|
||||||
if (last.path === path || last.linkPath === path) {
|
|
||||||
return <span>{label}</span>;
|
|
||||||
}
|
}
|
||||||
}
|
if (menuItemProps.path && location.pathname !== menuItemProps.path) {
|
||||||
return <Link to={path}>{label}</Link>;
|
return (
|
||||||
}}
|
// handle wildcard route path, for example /slave/* from qiankun
|
||||||
disableContentMargin
|
<Link
|
||||||
fixSiderbar
|
to={menuItemProps.path.replace('/*', '')}
|
||||||
fixedHeader
|
target={menuItemProps.target}
|
||||||
{...runtimeConfig}
|
>
|
||||||
rightContentRender={
|
{defaultDom}
|
||||||
runtimeConfig.rightContentRender !== false &&
|
</Link>
|
||||||
((layoutProps) => {
|
);
|
||||||
const dom = getRightRenderContent({
|
}
|
||||||
runtimeConfig,
|
return <>{defaultDom}</>;
|
||||||
loading,
|
}}
|
||||||
initialState,
|
itemRender={(route, _, routes) => {
|
||||||
setInitialState
|
const { breadcrumbName, title, path } = route;
|
||||||
});
|
const label = title || breadcrumbName;
|
||||||
if (runtimeConfig.rightContentRender) {
|
const last = routes[routes.length - 1];
|
||||||
return runtimeConfig.rightContentRender(layoutProps, dom, {
|
if (last) {
|
||||||
// BREAK CHANGE userConfig > runtimeConfig
|
if (last.path === path || last.linkPath === path) {
|
||||||
userConfig,
|
return <span>{label}</span>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return <Link to={path}>{label}</Link>;
|
||||||
|
}}
|
||||||
|
disableContentMargin
|
||||||
|
fixSiderbar
|
||||||
|
fixedHeader
|
||||||
|
{...runtimeConfig}
|
||||||
|
rightContentRender={
|
||||||
|
runtimeConfig.rightContentRender !== false &&
|
||||||
|
((layoutProps) => {
|
||||||
|
const dom = getRightRenderContent({
|
||||||
runtimeConfig,
|
runtimeConfig,
|
||||||
loading,
|
loading,
|
||||||
initialState,
|
initialState,
|
||||||
setInitialState
|
setInitialState
|
||||||
});
|
});
|
||||||
}
|
if (runtimeConfig.rightContentRender) {
|
||||||
return dom;
|
return runtimeConfig.rightContentRender(layoutProps, dom, {
|
||||||
})
|
// BREAK CHANGE userConfig > runtimeConfig
|
||||||
}
|
userConfig,
|
||||||
>
|
runtimeConfig,
|
||||||
<Exception
|
loading,
|
||||||
route={matchedRoute}
|
initialState,
|
||||||
noFound={runtimeConfig?.noFound}
|
setInitialState
|
||||||
notFound={runtimeConfig?.notFound}
|
});
|
||||||
unAccessible={runtimeConfig?.unAccessible}
|
}
|
||||||
noAccessible={runtimeConfig?.noAccessible}
|
return dom;
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{runtimeConfig.childrenRender ? (
|
<Exception
|
||||||
runtimeConfig.childrenRender(<Outlet />, props)
|
route={matchedRoute}
|
||||||
) : (
|
noFound={runtimeConfig?.noFound}
|
||||||
<Outlet />
|
notFound={runtimeConfig?.notFound}
|
||||||
)}
|
unAccessible={runtimeConfig?.unAccessible}
|
||||||
</Exception>
|
noAccessible={runtimeConfig?.noAccessible}
|
||||||
</ProLayout>
|
>
|
||||||
|
{runtimeConfig.childrenRender ? (
|
||||||
|
runtimeConfig.childrenRender(<Outlet />, props)
|
||||||
|
) : (
|
||||||
|
<Outlet />
|
||||||
|
)}
|
||||||
|
</Exception>
|
||||||
|
</ProLayout>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ const Models: React.FC = () => {
|
|||||||
left={
|
left={
|
||||||
<Space>
|
<Space>
|
||||||
<Input
|
<Input
|
||||||
placeholder="按名称查询"
|
placeholder="名称查询"
|
||||||
style={{ width: 300 }}
|
style={{ width: 300 }}
|
||||||
onChange={handleNameChange}
|
onChange={handleNameChange}
|
||||||
></Input>
|
></Input>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import ContentWrapper from '@/components/content-wrapper';
|
import ContentWrapper from '@/components/content-wrapper';
|
||||||
|
import PageTools from '@/components/page-tools';
|
||||||
import { Col, Row, Table } from 'antd';
|
import { Col, Row, Table } from 'antd';
|
||||||
|
|
||||||
const modelColumns = [
|
const modelColumns = [
|
||||||
@@ -132,10 +133,18 @@ const ActiveTable = () => {
|
|||||||
return (
|
return (
|
||||||
<Row>
|
<Row>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<ContentWrapper
|
<PageTools
|
||||||
contentStyle={{ paddingRight: 0 }}
|
style={{ margin: '32px 40px' }}
|
||||||
title={<span style={{ lineHeight: '48px' }}>Active Models</span>}
|
left={
|
||||||
>
|
<span
|
||||||
|
style={{ fontSize: 'var(--font-size-large)', padding: '9px 0' }}
|
||||||
|
>
|
||||||
|
Active Models
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
right={false}
|
||||||
|
/>
|
||||||
|
<ContentWrapper contentStyle={{ paddingRight: 0 }} title={false}>
|
||||||
<Table
|
<Table
|
||||||
columns={modelColumns}
|
columns={modelColumns}
|
||||||
dataSource={modelData}
|
dataSource={modelData}
|
||||||
@@ -145,9 +154,18 @@ const ActiveTable = () => {
|
|||||||
</ContentWrapper>
|
</ContentWrapper>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<ContentWrapper
|
<PageTools
|
||||||
title={<span style={{ lineHeight: '48px' }}>Active Projects</span>}
|
style={{ margin: '32px 40px' }}
|
||||||
>
|
left={
|
||||||
|
<span
|
||||||
|
style={{ fontSize: 'var(--font-size-large)', padding: '9px 0' }}
|
||||||
|
>
|
||||||
|
Active Projects
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
right={false}
|
||||||
|
/>
|
||||||
|
<ContentWrapper title={false}>
|
||||||
<Table
|
<Table
|
||||||
columns={projectColumns}
|
columns={projectColumns}
|
||||||
dataSource={projectData}
|
dataSource={projectData}
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
:local(.card-body) {
|
:local(.card-body) {
|
||||||
:global(.ant-card-body) {
|
:global(.ant-card-body) {
|
||||||
height: 100px;
|
height: 110px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:local(.row) {
|
:local(.row) {
|
||||||
:global(.ant-col-5) {
|
:global(.ant-col-5) {
|
||||||
flex: 0 0 20%;
|
flex: 0 0 20%;
|
||||||
max-width: 20%;
|
max-width: 20%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PageContainer } from '@ant-design/pro-components';
|
import ContentWrapper from '@/components/content-wrapper';
|
||||||
import { Card, Col, Row, Space } from 'antd';
|
import { Card, Col, Row, Space } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { overviewConfigs } from '../config';
|
import { overviewConfigs } from '../config';
|
||||||
@@ -55,7 +55,7 @@ const Overview: React.FC = (props) => {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Space className="value-box">
|
<Space className="value-box" size={20}>
|
||||||
<span className={'value-healthy'}>{value.healthy}</span>
|
<span className={'value-healthy'}>{value.healthy}</span>
|
||||||
<span className={'value-warning'}>{value.warning}</span>
|
<span className={'value-warning'}>{value.warning}</span>
|
||||||
<span className={'value-error'}>{value.error}</span>
|
<span className={'value-error'}>{value.error}</span>
|
||||||
@@ -63,8 +63,8 @@ const Overview: React.FC = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<PageContainer ghost title={false}>
|
<ContentWrapper contentStyle={{ paddingBlockStart: '32px' }} title={false}>
|
||||||
<Row gutter={[20, 20]} className={styles.row}>
|
<Row gutter={[24, 20]} className={styles.row}>
|
||||||
{overviewConfigs.map((config, index) => (
|
{overviewConfigs.map((config, index) => (
|
||||||
<Col span={5} key={config.key}>
|
<Col span={5} key={config.key}>
|
||||||
{renderCardItem({
|
{renderCardItem({
|
||||||
@@ -75,7 +75,7 @@ const Overview: React.FC = (props) => {
|
|||||||
</Col>
|
</Col>
|
||||||
))}
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
</PageContainer>
|
</ContentWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,13 +26,6 @@ const mockData = {
|
|||||||
};
|
};
|
||||||
const UtilizationOvertime: React.FC = () => {
|
const UtilizationOvertime: React.FC = () => {
|
||||||
const timeList = [
|
const timeList = [
|
||||||
// '01:00:00',
|
|
||||||
// '02:00:00',
|
|
||||||
// '03:00:00',
|
|
||||||
// '04:00:00',
|
|
||||||
// '05:00:00',
|
|
||||||
// '06:00:00',
|
|
||||||
// '07:00:00',
|
|
||||||
'08:00:00',
|
'08:00:00',
|
||||||
'09:00:00',
|
'09:00:00',
|
||||||
'10:00:00',
|
'10:00:00',
|
||||||
@@ -67,7 +60,6 @@ const UtilizationOvertime: React.FC = () => {
|
|||||||
};
|
};
|
||||||
const data = generateData();
|
const data = generateData();
|
||||||
|
|
||||||
// <DatePicker onChange={handleSelectDate} style={{ width: 300 }} />
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<LineChart height={400} data={data} />
|
<LineChart height={400} data={data} />
|
||||||
|
|||||||
@@ -10,19 +10,23 @@ const SystemLoad = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer ghost title="System Load">
|
<PageContainer ghost title={false}>
|
||||||
<div className="system-load">
|
<div className="system-load">
|
||||||
<PageTools
|
<PageTools
|
||||||
marginBottom={10}
|
marginBottom={10}
|
||||||
marginTop={0}
|
marginTop={0}
|
||||||
left={false}
|
left={
|
||||||
|
<span style={{ fontSize: 'var(--font-size-large)' }}>
|
||||||
|
System Load
|
||||||
|
</span>
|
||||||
|
}
|
||||||
right={
|
right={
|
||||||
<DatePicker onChange={handleSelectDate} style={{ width: 300 }} />
|
<DatePicker onChange={handleSelectDate} style={{ width: 300 }} />
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ResourceUtilization />
|
<ResourceUtilization />
|
||||||
<Row style={{ width: '100%' }}>
|
<Row style={{ width: '100%', marginTop: '32px' }}>
|
||||||
<Col span={6}>
|
<Col xs={24} sm={24} md={12} lg={6} xl={6}>
|
||||||
<GaugeChart
|
<GaugeChart
|
||||||
title="GPU Compute Utilization"
|
title="GPU Compute Utilization"
|
||||||
total={100}
|
total={100}
|
||||||
@@ -32,7 +36,7 @@ const SystemLoad = () => {
|
|||||||
rangColor={['#54cc98', '#ffd666', '#ff7875']}
|
rangColor={['#54cc98', '#ffd666', '#ff7875']}
|
||||||
></GaugeChart>
|
></GaugeChart>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6}>
|
<Col xs={24} sm={24} md={12} lg={6} xl={6}>
|
||||||
<GaugeChart
|
<GaugeChart
|
||||||
title="GPU Memory Utilization"
|
title="GPU Memory Utilization"
|
||||||
total={100}
|
total={100}
|
||||||
@@ -42,7 +46,7 @@ const SystemLoad = () => {
|
|||||||
rangColor={['#54cc98', '#ffd666', '#ff7875']}
|
rangColor={['#54cc98', '#ffd666', '#ff7875']}
|
||||||
></GaugeChart>
|
></GaugeChart>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6}>
|
<Col xs={24} sm={24} md={12} lg={6} xl={6}>
|
||||||
<GaugeChart
|
<GaugeChart
|
||||||
title="CPU Compute Utilization"
|
title="CPU Compute Utilization"
|
||||||
total={100}
|
total={100}
|
||||||
@@ -52,7 +56,7 @@ const SystemLoad = () => {
|
|||||||
rangColor={['#54cc98', '#ffd666', '#ff7875']}
|
rangColor={['#54cc98', '#ffd666', '#ff7875']}
|
||||||
></GaugeChart>
|
></GaugeChart>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6}>
|
<Col xs={24} sm={24} md={12} lg={6} xl={6}>
|
||||||
<GaugeChart
|
<GaugeChart
|
||||||
title="CPU Memory Utilization"
|
title="CPU Memory Utilization"
|
||||||
total={100}
|
total={100}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import ColumnBar from '@/components/charts/column-bar';
|
import ColumnBar from '@/components/charts/column-bar';
|
||||||
import HBar from '@/components/charts/h-bar';
|
import HBar from '@/components/charts/h-bar';
|
||||||
|
import ContentWrapper from '@/components/content-wrapper';
|
||||||
import PageTools from '@/components/page-tools';
|
import PageTools from '@/components/page-tools';
|
||||||
import { generateRandomArray } from '@/utils';
|
import { generateRandomArray } from '@/utils';
|
||||||
import { PageContainer } from '@ant-design/pro-components';
|
|
||||||
import { Col, DatePicker, Row } from 'antd';
|
import { Col, DatePicker, Row } from 'antd';
|
||||||
|
|
||||||
const times = [
|
const times = [
|
||||||
@@ -91,19 +91,16 @@ const Usage = () => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageContainer ghost title="Usage">
|
<PageTools
|
||||||
<PageTools
|
style={{ margin: '32px 40px' }}
|
||||||
marginBottom={10}
|
left={<span style={{ fontSize: 'var(--font-size-large)' }}>Usage</span>}
|
||||||
marginTop={0}
|
right={
|
||||||
left={false}
|
<DatePicker onChange={handleSelectDate} style={{ width: 300 }} />
|
||||||
right={
|
}
|
||||||
<DatePicker onChange={handleSelectDate} style={{ width: 300 }} />
|
/>
|
||||||
}
|
<Row style={{ width: '100%' }} gutter={[20, 0]}>
|
||||||
/>
|
|
||||||
</PageContainer>
|
|
||||||
<Row style={{ width: '100%' }}>
|
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<PageContainer title={false}>
|
<ContentWrapper title={false} contentStyle={{ paddingRight: 0 }}>
|
||||||
<ColumnBar
|
<ColumnBar
|
||||||
title="API Request"
|
title="API Request"
|
||||||
data={dataList}
|
data={dataList}
|
||||||
@@ -111,10 +108,10 @@ const Usage = () => {
|
|||||||
yField="value"
|
yField="value"
|
||||||
height={360}
|
height={360}
|
||||||
></ColumnBar>
|
></ColumnBar>
|
||||||
</PageContainer>
|
</ContentWrapper>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<PageContainer title={false}>
|
<ContentWrapper title={false} contentStyle={{ paddingLeft: 0 }}>
|
||||||
<ColumnBar
|
<ColumnBar
|
||||||
title="Tokens"
|
title="Tokens"
|
||||||
data={tokenUsage}
|
data={tokenUsage}
|
||||||
@@ -122,12 +119,12 @@ const Usage = () => {
|
|||||||
yField="value"
|
yField="value"
|
||||||
height={360}
|
height={360}
|
||||||
></ColumnBar>
|
></ColumnBar>
|
||||||
</PageContainer>
|
</ContentWrapper>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row style={{ width: '100%' }}>
|
<Row style={{ width: '100%' }} gutter={[20, 0]}>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<PageContainer title={false}>
|
<ContentWrapper title={false} contentStyle={{ paddingRight: 0 }}>
|
||||||
<HBar
|
<HBar
|
||||||
title="Top Users"
|
title="Top Users"
|
||||||
data={userDataList}
|
data={userDataList}
|
||||||
@@ -135,10 +132,10 @@ const Usage = () => {
|
|||||||
yField="value"
|
yField="value"
|
||||||
height={400}
|
height={400}
|
||||||
></HBar>
|
></HBar>
|
||||||
</PageContainer>
|
</ContentWrapper>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<PageContainer title={false}>
|
<ContentWrapper title={false} contentStyle={{ paddingLeft: 0 }}>
|
||||||
<HBar
|
<HBar
|
||||||
title="Top Projects"
|
title="Top Projects"
|
||||||
data={projectDataList}
|
data={projectDataList}
|
||||||
@@ -146,7 +143,7 @@ const Usage = () => {
|
|||||||
yField="value"
|
yField="value"
|
||||||
height={400}
|
height={400}
|
||||||
></HBar>
|
></HBar>
|
||||||
</PageContainer>
|
</ContentWrapper>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -3,30 +3,30 @@ export const overviewConfigs = [
|
|||||||
key: 'workers',
|
key: 'workers',
|
||||||
label: 'Workers',
|
label: 'Workers',
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
'linear-gradient(180deg, rgba(0,188,203,.2) 0%, rgba(40,207,181,.2) 100%)'
|
'linear-gradient(180deg, rgb(0 139 188 / 20%) 0%, rgba(40,207,181,.2) 100%)'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'gpus',
|
key: 'gpus',
|
||||||
label: 'Total GPUs',
|
label: 'Total GPUs',
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
'linear-gradient(180deg, rgba(0,188,203,.2) 0%, rgba(40,207,181,.2) 100%)'
|
'linear-gradient(180deg, rgb(0 139 188 / 20%) 0%, rgba(40,207,181,.2) 100%)'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'allocatedGpus',
|
key: 'allocatedGpus',
|
||||||
label: 'Allocated GPUs',
|
label: 'Allocated GPUs',
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
'linear-gradient(180deg, rgba(0,188,203,.2) 0%, rgba(40,207,181,.2) 100%)'
|
'linear-gradient(180deg, rgb(0 139 188 / 20%) 0%, rgba(40,207,181,.2) 100%)'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'models',
|
key: 'models',
|
||||||
label: 'Models',
|
label: 'Models',
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
'linear-gradient(180deg, rgba(0,188,203,.2) 0%, rgba(40,207,181,.2) 100%)'
|
'linear-gradient(180deg, rgb(0 139 188 / 20%) 0%, rgba(40,207,181,.2) 100%)'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'instances',
|
key: 'instances',
|
||||||
label: 'Instances',
|
label: 'Instances',
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
'linear-gradient(180deg, rgba(0,188,203,.2) 0%, rgba(40,207,181,.2) 100%)'
|
'linear-gradient(180deg, rgb(0 139 188 / 20%) 0%, rgba(40,207,181,.2) 100%)'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
color: var(--ant-gold-6);
|
color: var(--ant-gold-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.value-danger {
|
.value-error {
|
||||||
color: var(--ant-red-6);
|
color: var(--ant-red-6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import SealSelect from '@/components/seal-form/seal-select';
|
|||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { convertFileSize } from '@/utils';
|
import { convertFileSize } from '@/utils';
|
||||||
import { Form, Modal } from 'antd';
|
import { Form, Input, Modal } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
@@ -130,7 +130,9 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
onSearch={debounceSearch}
|
onSearch={debounceSearch}
|
||||||
options={repoOptions}
|
options={repoOptions}
|
||||||
description="Only .gguf format is supported"
|
description="Only .gguf format is supported"
|
||||||
></SealAutoComplete>
|
>
|
||||||
|
<Input.Search style={{ width: '520px' }}></Input.Search>
|
||||||
|
</SealAutoComplete>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="huggingface_filename"
|
name="huggingface_filename"
|
||||||
|
|||||||
@@ -382,7 +382,7 @@ const Models: React.FC = () => {
|
|||||||
left={
|
left={
|
||||||
<Space>
|
<Space>
|
||||||
<Input
|
<Input
|
||||||
placeholder="按名称查询"
|
placeholder="名称查询"
|
||||||
style={{ width: 300 }}
|
style={{ width: 300 }}
|
||||||
allowClear
|
allowClear
|
||||||
onChange={handleNameChange}
|
onChange={handleNameChange}
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ const Models: React.FC = () => {
|
|||||||
left={
|
left={
|
||||||
<Space>
|
<Space>
|
||||||
<Input
|
<Input
|
||||||
placeholder="按名称查询"
|
placeholder="名称查询"
|
||||||
style={{ width: 300 }}
|
style={{ width: 300 }}
|
||||||
onChange={handleNameChange}
|
onChange={handleNameChange}
|
||||||
></Input>
|
></Input>
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ const Models: React.FC = () => {
|
|||||||
left={
|
left={
|
||||||
<Space>
|
<Space>
|
||||||
<Input
|
<Input
|
||||||
placeholder="按名称查询"
|
placeholder="名称查询"
|
||||||
style={{ width: 300 }}
|
style={{ width: 300 }}
|
||||||
onChange={handleNameChange}
|
onChange={handleNameChange}
|
||||||
></Input>
|
></Input>
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ const Models: React.FC = () => {
|
|||||||
left={
|
left={
|
||||||
<Space>
|
<Space>
|
||||||
<Input
|
<Input
|
||||||
placeholder="按名称查询"
|
placeholder="名称查询"
|
||||||
style={{ width: 300 }}
|
style={{ width: 300 }}
|
||||||
onChange={handleNameChange}
|
onChange={handleNameChange}
|
||||||
></Input>
|
></Input>
|
||||||
|
|||||||
Reference in New Issue
Block a user