style: ui for no data in table list
This commit is contained in:
@@ -112,20 +112,23 @@ export default function useTableFetch<T>(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchData = async (params?: { query: any }, polling = false) => {
|
const fetchData = async (
|
||||||
|
params?: { query: Record<string, any>; loadmore?: boolean },
|
||||||
|
polling = false
|
||||||
|
) => {
|
||||||
if (!polling) {
|
if (!polling) {
|
||||||
setDataSource((pre) => {
|
setDataSource((pre) => {
|
||||||
pre.loading = true;
|
pre.loading = true;
|
||||||
return { ...pre };
|
return { ...pre };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { query } = params || {};
|
const { query, loadmore } = params || {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
..._.pickBy(query || queryParams, (val: any) => !!val)
|
..._.pickBy(query || queryParams, (val: any) => !!val)
|
||||||
};
|
};
|
||||||
const res = await fetchAPI(params);
|
const res = await fetchAPI(params);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!res.items.length &&
|
!res.items.length &&
|
||||||
params.page > res.pagination.totalPage &&
|
params.page > res.pagination.totalPage &&
|
||||||
@@ -137,7 +140,9 @@ export default function useTableFetch<T>(
|
|||||||
};
|
};
|
||||||
const newRes = await fetchAPI(newParams);
|
const newRes = await fetchAPI(newParams);
|
||||||
setDataSource({
|
setDataSource({
|
||||||
dataList: newRes.items || [],
|
dataList: loadmore
|
||||||
|
? [...dataSource.dataList, ...(newRes.items || [])]
|
||||||
|
: newRes.items || [],
|
||||||
loading: false,
|
loading: false,
|
||||||
loadend: true,
|
loadend: true,
|
||||||
total: newRes.pagination.total,
|
total: newRes.pagination.total,
|
||||||
@@ -150,7 +155,9 @@ export default function useTableFetch<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
setDataSource({
|
setDataSource({
|
||||||
dataList: res.items || [],
|
dataList: loadmore
|
||||||
|
? [...dataSource.dataList, ...(res.items || [])]
|
||||||
|
: res.items || [],
|
||||||
loading: false,
|
loading: false,
|
||||||
loadend: true,
|
loadend: true,
|
||||||
total: res.pagination.total,
|
total: res.pagination.total,
|
||||||
|
|||||||
@@ -193,5 +193,6 @@ export default {
|
|||||||
'models.accessSettings.authed': 'Authenticated',
|
'models.accessSettings.authed': 'Authenticated',
|
||||||
'models.accessSettings.allowedUsers': 'Allowed users',
|
'models.accessSettings.allowedUsers': 'Allowed users',
|
||||||
'models.accessSettings.public.tips':
|
'models.accessSettings.public.tips':
|
||||||
'When set to public, anyone can access this model without authentication, which may lead to data exposure risks.'
|
'When set to public, anyone can access this model without authentication, which may lead to data exposure risks.',
|
||||||
|
'models.table.button.deploy': 'Deploy Now'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export default {
|
||||||
|
'noresult.button.add': 'Add Now',
|
||||||
|
'noresult.mymodels.title': 'No Accessible Models',
|
||||||
|
'noresult.mymodels.subTitle': 'Please contact the administrator for access.',
|
||||||
|
'noresult.mymodels.nofound': 'No matching models found',
|
||||||
|
'noresult.deployments.title': 'No Deployed Models',
|
||||||
|
'noresult.deployments.subTitle':
|
||||||
|
'You have not deployed any models yet. Click the button below to get started.',
|
||||||
|
'noresult.gpus.title': 'No GPU Devices Detected',
|
||||||
|
'noresult.gpus.subTitle': 'Please check if the Worker status is READY.',
|
||||||
|
'noresult.gpus.nofound': 'No matching GPU devices found.',
|
||||||
|
'noresult.workers.title': 'No Workers',
|
||||||
|
'noresult.workers.subTitle': 'No workers found in any clusters.',
|
||||||
|
'noresult.workers.nofound': 'No matching workers found.',
|
||||||
|
'noresult.workers.button.add': 'Go to Add Worker',
|
||||||
|
'noresult.modelfiles.title': 'No Model Files',
|
||||||
|
'noresult.modelfiles.subTitle': 'No model files have been added yet.',
|
||||||
|
'noresult.modelfiles.nofound': 'No matching model files found.',
|
||||||
|
'noresult.backend.title': 'No Inference Backends',
|
||||||
|
'noresult.backend.subTitle': 'No inference backends have been added yet.',
|
||||||
|
'noresult.backend.nofound': 'No matching inference backends found.',
|
||||||
|
'noresult.cluster.title': 'No Clusters',
|
||||||
|
'noresult.cluster.subTitle': 'No clusters have been added yet.',
|
||||||
|
'noresult.cluster.nofound': 'No matching clusters found.',
|
||||||
|
'noresult.credentials.title': 'No Credentials',
|
||||||
|
'noresult.credentials.subTitle': 'No credentials have been added yet.',
|
||||||
|
'noresult.credentials.nofound': 'No matching credentials found.',
|
||||||
|
'noresult.users.title': 'No Users',
|
||||||
|
'noresult.users.subTitle': 'No users have been added yet.',
|
||||||
|
'noresult.users.nofound': 'No matching users found.',
|
||||||
|
'noresult.keys.title': 'No API Keys',
|
||||||
|
'noresult.keys.subTitle': 'No API keys have been added yet.',
|
||||||
|
'noresult.keys.nofound': 'No matching API keys found.',
|
||||||
|
'noresult.catalog.title': 'No Models',
|
||||||
|
'noresult.catalog.subTitle': 'No models have been configured yet.',
|
||||||
|
'noresult.catalog.nofound': 'No matching models found.'
|
||||||
|
};
|
||||||
@@ -8,7 +8,7 @@ export default {
|
|||||||
'users.table.status': 'Status',
|
'users.table.status': 'Status',
|
||||||
'users.status.active': 'Active',
|
'users.status.active': 'Active',
|
||||||
'users.status.inactive': 'Inactive',
|
'users.status.inactive': 'Inactive',
|
||||||
'users.form.active': 'Active account',
|
'users.form.active': 'Active Account',
|
||||||
'users.form.active.description': 'Enable or disable this user account',
|
'users.form.active.description': 'Enable or disable this user account',
|
||||||
'users.form.fullname': 'Full Name',
|
'users.form.fullname': 'Full Name',
|
||||||
'users.form.source': 'Source',
|
'users.form.source': 'Source',
|
||||||
|
|||||||
@@ -190,7 +190,8 @@ export default {
|
|||||||
'models.accessSettings.authed': 'Authenticated',
|
'models.accessSettings.authed': 'Authenticated',
|
||||||
'models.accessSettings.allowedUsers': 'Allowed users',
|
'models.accessSettings.allowedUsers': 'Allowed users',
|
||||||
'models.accessSettings.public.tips':
|
'models.accessSettings.public.tips':
|
||||||
'When set to public, anyone can access this model without authentication, which may lead to data exposure risks.'
|
'When set to public, anyone can access this model without authentication, which may lead to data exposure risks.',
|
||||||
|
'models.table.button.deploy': 'Deploy Now'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
@@ -222,6 +223,7 @@ export default {
|
|||||||
// 27. 'models.accessSettings.public': 'Public',
|
// 27. 'models.accessSettings.public': 'Public',
|
||||||
// 28. 'models.accessSettings.authed': 'Authenticated',
|
// 28. 'models.accessSettings.authed': 'Authenticated',
|
||||||
// 29. 'models.accessSettings.allowedUsers': 'Allowed users',
|
// 29. 'models.accessSettings.allowedUsers': 'Allowed users',
|
||||||
// 30. 'models.accessSettings.public.tips': 'When set to public, anyone can access this model without authentication, which may lead to data exposure risks.'
|
// 30. 'models.accessSettings.public.tips': 'When set to public, anyone can access this model without authentication, which may lead to data exposure risks.',
|
||||||
|
// 31. 'models.table.button.deploy': 'Deploy Now'
|
||||||
|
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export default {
|
||||||
|
'noresult.button.add': 'Add Now',
|
||||||
|
'noresult.mymodels.title': 'No Accessible Models',
|
||||||
|
'noresult.mymodels.subTitle': 'Please contact the administrator for access.',
|
||||||
|
'noresult.mymodels.nofound': 'No matching models found',
|
||||||
|
'noresult.deployments.title': 'No Deployed Models',
|
||||||
|
'noresult.deployments.subTitle':
|
||||||
|
'You have not deployed any models yet. Click the button below to get started.',
|
||||||
|
'noresult.gpus.title': 'No GPU Devices Detected',
|
||||||
|
'noresult.gpus.subTitle': 'Please check if the Worker status is READY.',
|
||||||
|
'noresult.gpus.nofound': 'No matching GPU devices found.',
|
||||||
|
'noresult.workers.title': 'No Workers',
|
||||||
|
'noresult.workers.subTitle': 'No workers found in any clusters.',
|
||||||
|
'noresult.workers.nofound': 'No matching workers found.',
|
||||||
|
'noresult.workers.button.add': 'Go to Add Worker',
|
||||||
|
'noresult.modelfiles.title': 'No Model Files',
|
||||||
|
'noresult.modelfiles.subTitle': 'No model files have been added yet.',
|
||||||
|
'noresult.modelfiles.nofound': 'No matching model files found.',
|
||||||
|
'noresult.backend.title': 'No Inference Backends',
|
||||||
|
'noresult.backend.subTitle': 'No inference backends have been added yet.',
|
||||||
|
'noresult.backend.nofound': 'No matching inference backends found.',
|
||||||
|
'noresult.cluster.title': 'No Clusters',
|
||||||
|
'noresult.cluster.subTitle': 'No clusters have been added yet.',
|
||||||
|
'noresult.cluster.nofound': 'No matching clusters found.',
|
||||||
|
'noresult.credentials.title': 'No Credentials',
|
||||||
|
'noresult.credentials.subTitle': 'No credentials have been added yet.',
|
||||||
|
'noresult.credentials.nofound': 'No matching credentials found.',
|
||||||
|
'noresult.users.title': 'No Users',
|
||||||
|
'noresult.users.subTitle': 'No users have been added yet.',
|
||||||
|
'noresult.users.nofound': 'No matching users found.',
|
||||||
|
'noresult.keys.title': 'No API Keys',
|
||||||
|
'noresult.keys.subTitle': 'No API keys have been added yet.',
|
||||||
|
'noresult.keys.nofound': 'No matching API keys found.',
|
||||||
|
'noresult.catalog.title': 'No Models',
|
||||||
|
'noresult.catalog.subTitle': 'No models have been configured yet.',
|
||||||
|
'noresult.catalog.nofound': 'No matching models found.'
|
||||||
|
};
|
||||||
@@ -193,7 +193,8 @@ export default {
|
|||||||
'models.accessSettings.authed': 'Authenticated',
|
'models.accessSettings.authed': 'Authenticated',
|
||||||
'models.accessSettings.allowedUsers': 'Allowed users',
|
'models.accessSettings.allowedUsers': 'Allowed users',
|
||||||
'models.accessSettings.public.tips':
|
'models.accessSettings.public.tips':
|
||||||
'When set to public, anyone can access this model without authentication, which may lead to data exposure risks.'
|
'When set to public, anyone can access this model without authentication, which may lead to data exposure risks.',
|
||||||
|
'models.table.button.deploy': 'Deploy Now'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
@@ -217,5 +218,6 @@ export default {
|
|||||||
// 19. 'models.accessSettings.public': 'Public',
|
// 19. 'models.accessSettings.public': 'Public',
|
||||||
// 20. 'models.accessSettings.authed': 'Authenticated',
|
// 20. 'models.accessSettings.authed': 'Authenticated',
|
||||||
// 21. 'models.accessSettings.allowedUsers': 'Allowed users',
|
// 21. 'models.accessSettings.allowedUsers': 'Allowed users',
|
||||||
// 22. 'models.accessSettings.public.tips': 'When set to public, anyone can access this model without authentication, which may lead to data exposure risks.'
|
// 22. 'models.accessSettings.public.tips': 'When set to public, anyone can access this model without authentication, which may lead to data exposure risks.',
|
||||||
|
// 23. 'models.table.button.deploy': 'Deploy Now'
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export default {
|
||||||
|
'noresult.button.add': 'Add Now',
|
||||||
|
'noresult.mymodels.title': 'No Accessible Models',
|
||||||
|
'noresult.mymodels.subTitle': 'Please contact the administrator for access.',
|
||||||
|
'noresult.mymodels.nofound': 'No matching models found',
|
||||||
|
'noresult.deployments.title': 'No Deployed Models',
|
||||||
|
'noresult.deployments.subTitle':
|
||||||
|
'You have not deployed any models yet. Click the button below to get started.',
|
||||||
|
'noresult.gpus.title': 'No GPU Devices Detected',
|
||||||
|
'noresult.gpus.subTitle': 'Please check if the Worker status is READY.',
|
||||||
|
'noresult.gpus.nofound': 'No matching GPU devices found.',
|
||||||
|
'noresult.workers.title': 'No Workers',
|
||||||
|
'noresult.workers.subTitle': 'No workers found in any clusters.',
|
||||||
|
'noresult.workers.nofound': 'No matching workers found.',
|
||||||
|
'noresult.workers.button.add': 'Go to Add Worker',
|
||||||
|
'noresult.modelfiles.title': 'No Model Files',
|
||||||
|
'noresult.modelfiles.subTitle': 'No model files have been added yet.',
|
||||||
|
'noresult.modelfiles.nofound': 'No matching model files found.',
|
||||||
|
'noresult.backend.title': 'No Inference Backends',
|
||||||
|
'noresult.backend.subTitle': 'No inference backends have been added yet.',
|
||||||
|
'noresult.backend.nofound': 'No matching inference backends found.',
|
||||||
|
'noresult.cluster.title': 'No Clusters',
|
||||||
|
'noresult.cluster.subTitle': 'No clusters have been added yet.',
|
||||||
|
'noresult.cluster.nofound': 'No matching clusters found.',
|
||||||
|
'noresult.credentials.title': 'No Credentials',
|
||||||
|
'noresult.credentials.subTitle': 'No credentials have been added yet.',
|
||||||
|
'noresult.credentials.nofound': 'No matching credentials found.',
|
||||||
|
'noresult.users.title': 'No Users',
|
||||||
|
'noresult.users.subTitle': 'No users have been added yet.',
|
||||||
|
'noresult.users.nofound': 'No matching users found.',
|
||||||
|
'noresult.keys.title': 'No API Keys',
|
||||||
|
'noresult.keys.subTitle': 'No API keys have been added yet.',
|
||||||
|
'noresult.keys.nofound': 'No matching API keys found.',
|
||||||
|
'noresult.catalog.title': 'No Models',
|
||||||
|
'noresult.catalog.subTitle': 'No models have been configured yet.',
|
||||||
|
'noresult.catalog.nofound': 'No matching models found.'
|
||||||
|
};
|
||||||
@@ -183,5 +183,6 @@ export default {
|
|||||||
'models.accessSettings.authed': '认证用户',
|
'models.accessSettings.authed': '认证用户',
|
||||||
'models.accessSettings.allowedUsers': '指定用户',
|
'models.accessSettings.allowedUsers': '指定用户',
|
||||||
'models.accessSettings.public.tips':
|
'models.accessSettings.public.tips':
|
||||||
'公开后,任何人无需认证即可访问,可能存在数据泄露风险。'
|
'公开后,任何人无需认证即可访问,可能存在数据泄露风险。',
|
||||||
|
'models.table.button.deploy': '立即部署'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export default {
|
||||||
|
'noresult.button.add': '立即添加',
|
||||||
|
'noresult.mymodels.title': '暂无可访问的模型',
|
||||||
|
'noresult.mymodels.subTitle': '请联系管理员获取访问权限。',
|
||||||
|
'noresult.mymodels.nofound': '未找到匹配的模型',
|
||||||
|
'noresult.deployments.title': '尚未部署模型',
|
||||||
|
'noresult.deployments.subTitle':
|
||||||
|
'您还没有部署任何模型,点击下方按钮即可开始。',
|
||||||
|
'noresult.gpus.title': '当前未检测到 GPU 设备',
|
||||||
|
'noresult.gpus.subTitle': '请确认 Worker 状态是否正常。',
|
||||||
|
'noresult.gpus.nofound': '未找到匹配的 GPU 设备',
|
||||||
|
'noresult.workers.title': '暂无 Worker',
|
||||||
|
'noresult.workers.subTitle': '当前集群中没有任何 Worker。',
|
||||||
|
'noresult.workers.nofound': '未找到匹配的 Worker',
|
||||||
|
'noresult.workers.button.add': '前往添加 Worker',
|
||||||
|
'noresult.modelfiles.title': '暂无模型文件',
|
||||||
|
'noresult.modelfiles.subTitle': '尚未添加任何模型文件。',
|
||||||
|
'noresult.modelfiles.nofound': '未找到匹配的模型文件',
|
||||||
|
'noresult.backend.title': '暂无推理后端',
|
||||||
|
'noresult.backend.subTitle': '尚未添加任何推理后端。',
|
||||||
|
'noresult.backend.nofound': '未找到匹配的推理后端',
|
||||||
|
'noresult.cluster.title': '暂无集群',
|
||||||
|
'noresult.cluster.subTitle': '尚未添加任何集群。',
|
||||||
|
'noresult.cluster.nofound': '未找到匹配的集群',
|
||||||
|
'noresult.credentials.title': '暂无凭据',
|
||||||
|
'noresult.credentials.subTitle': '尚未添加任何凭据。',
|
||||||
|
'noresult.credentials.nofound': '未找到匹配的凭据',
|
||||||
|
'noresult.users.title': '暂无用户',
|
||||||
|
'noresult.users.subTitle': '尚未添加任何用户。',
|
||||||
|
'noresult.users.nofound': '未找到匹配的用户',
|
||||||
|
'noresult.keys.title': '暂无 API 密钥',
|
||||||
|
'noresult.keys.subTitle': '尚未添加任何 API 密钥。',
|
||||||
|
'noresult.keys.nofound': '未找到匹配的 API 密钥',
|
||||||
|
'noresult.catalog.title': '暂无模型',
|
||||||
|
'noresult.catalog.subTitle': '尚未配置任何模型。',
|
||||||
|
'noresult.catalog.nofound': '未找到匹配的模型'
|
||||||
|
};
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { Empty, EmptyProps, Typography } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const StyledEmpty = styled(Empty)`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-block: 60px 32px;
|
||||||
|
.ant-empty-image {
|
||||||
|
margin-bottom: 0;
|
||||||
|
height: auto;
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 42px;
|
||||||
|
.anticon {
|
||||||
|
color: var(--ant-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-empty-footer {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ImageWrapper = styled.div`
|
||||||
|
margin-bottom: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SimpleImageWrapper = styled.div`
|
||||||
|
margin-bottom: 8px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Description = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const NoResult: React.FC<
|
||||||
|
EmptyProps & {
|
||||||
|
title?: React.ReactNode;
|
||||||
|
subTitle?: React.ReactNode;
|
||||||
|
noFoundText?: React.ReactNode;
|
||||||
|
filters?: Record<string, any>;
|
||||||
|
loading?: boolean;
|
||||||
|
loadend?: boolean;
|
||||||
|
dataSource?: any[];
|
||||||
|
}
|
||||||
|
> = (props) => {
|
||||||
|
const { filters, noFoundText, loadend, loading, dataSource } = props;
|
||||||
|
|
||||||
|
const hasFilters = useMemo(() => {
|
||||||
|
const filterValues = _.omit(filters, ['page', 'perPage']);
|
||||||
|
|
||||||
|
return Object.values(filterValues || {}).some((value) => {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!value;
|
||||||
|
});
|
||||||
|
}, [filters]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{!loading && loadend && !dataSource?.length ? (
|
||||||
|
<StyledEmpty
|
||||||
|
image={
|
||||||
|
hasFilters ? (
|
||||||
|
<SimpleImageWrapper>
|
||||||
|
{Empty.PRESENTED_IMAGE_SIMPLE}
|
||||||
|
</SimpleImageWrapper>
|
||||||
|
) : (
|
||||||
|
<ImageWrapper>{props.image}</ImageWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
description={
|
||||||
|
<Description>
|
||||||
|
{!hasFilters && (
|
||||||
|
<Typography.Text style={{ fontSize: '18px', fontWeight: 500 }}>
|
||||||
|
{props.title}
|
||||||
|
</Typography.Text>
|
||||||
|
)}
|
||||||
|
<Typography.Text type="secondary">
|
||||||
|
{hasFilters ? noFoundText : props.subTitle}
|
||||||
|
</Typography.Text>
|
||||||
|
</Description>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{!hasFilters && props.children}
|
||||||
|
</StyledEmpty>
|
||||||
|
) : (
|
||||||
|
<span></span>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NoResult;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import DeleteModal from '@/components/delete-modal';
|
import DeleteModal from '@/components/delete-modal';
|
||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import { FilterBar } from '@/components/page-tools';
|
import { FilterBar } from '@/components/page-tools';
|
||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import type { PageActionType } from '@/config/types';
|
import type { PageActionType } from '@/config/types';
|
||||||
@@ -6,8 +7,9 @@ import useTableFetch from '@/hooks/use-table-fetch';
|
|||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
|
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
|
||||||
import { ConfigProvider, Empty, Table } from 'antd';
|
import { Button, ConfigProvider, Table } from 'antd';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import NoResult from '../_components/no-result';
|
||||||
import { deleteApisKey, queryApisKeysList } from './apis';
|
import { deleteApisKey, queryApisKeysList } from './apis';
|
||||||
import AddAPIKeyModal from './components/add-apikey-modal';
|
import AddAPIKeyModal from './components/add-apikey-modal';
|
||||||
import { ListItem } from './config/types';
|
import { ListItem } from './config/types';
|
||||||
@@ -97,14 +99,24 @@ const APIKeys: React.FC = () => {
|
|||||||
|
|
||||||
const renderEmpty = (type?: string) => {
|
const renderEmpty = (type?: string) => {
|
||||||
if (type !== 'Table') return;
|
if (type !== 'Table') return;
|
||||||
if (
|
return (
|
||||||
!dataSource.loading &&
|
<NoResult
|
||||||
dataSource.loadend &&
|
loading={dataSource.loading}
|
||||||
!dataSource.dataList.length
|
loadend={dataSource.loadend}
|
||||||
) {
|
dataSource={dataSource.dataList}
|
||||||
return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}></Empty>;
|
image={<IconFont type="icon-key" />}
|
||||||
}
|
filters={queryParams}
|
||||||
return <div></div>;
|
noFoundText={intl.formatMessage({
|
||||||
|
id: 'noresult.keys.nofound'
|
||||||
|
})}
|
||||||
|
title={intl.formatMessage({ id: 'noresult.keys.title' })}
|
||||||
|
subTitle={intl.formatMessage({ id: 'noresult.keys.subTitle' })}
|
||||||
|
>
|
||||||
|
<Button type="primary" onClick={handleAddKey}>
|
||||||
|
{intl.formatMessage({ id: 'noresult.button.add' })}
|
||||||
|
</Button>
|
||||||
|
</NoResult>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = useKeysColumns({ handleSelect: onSelect, sortOrder });
|
const columns = useKeysColumns({ handleSelect: onSelect, sortOrder });
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import DeleteModal from '@/components/delete-modal';
|
import DeleteModal from '@/components/delete-modal';
|
||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import { FilterBar } from '@/components/page-tools';
|
import { FilterBar } from '@/components/page-tools';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import useTableFetch from '@/hooks/use-table-fetch';
|
import useTableFetch from '@/hooks/use-table-fetch';
|
||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
|
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
|
||||||
|
import { Button } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { ScrollerContext } from '../_components/infinite-scroller/use-scroller-context';
|
import { ScrollerContext } from '../_components/infinite-scroller/use-scroller-context';
|
||||||
|
import NoResult from '../_components/no-result';
|
||||||
import {
|
import {
|
||||||
createBackend,
|
createBackend,
|
||||||
createBackendFromYAML,
|
createBackendFromYAML,
|
||||||
@@ -154,8 +157,11 @@ const BackendList = () => {
|
|||||||
|
|
||||||
const loadMore = useMemoizedFn((nextPage: number) => {
|
const loadMore = useMemoizedFn((nextPage: number) => {
|
||||||
fetchData({
|
fetchData({
|
||||||
...queryParams,
|
query: {
|
||||||
page: nextPage
|
...queryParams,
|
||||||
|
page: nextPage
|
||||||
|
},
|
||||||
|
loadmore: true
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -204,6 +210,22 @@ const BackendList = () => {
|
|||||||
isFirst={!dataSource.loadend}
|
isFirst={!dataSource.loadend}
|
||||||
onSelect={handleOnSelect}
|
onSelect={handleOnSelect}
|
||||||
></BackendCardList>
|
></BackendCardList>
|
||||||
|
<NoResult
|
||||||
|
loading={dataSource.loading}
|
||||||
|
loadend={dataSource.loadend}
|
||||||
|
dataSource={dataSource.dataList}
|
||||||
|
image={<IconFont type="icon-models" />}
|
||||||
|
filters={queryParams}
|
||||||
|
noFoundText={intl.formatMessage({
|
||||||
|
id: 'noresult.backend.nofound'
|
||||||
|
})}
|
||||||
|
title={intl.formatMessage({ id: 'noresult.backend.title' })}
|
||||||
|
subTitle={intl.formatMessage({ id: 'noresult.backend.subTitle' })}
|
||||||
|
>
|
||||||
|
<Button type="primary" onClick={handleAddBackend}>
|
||||||
|
{intl.formatMessage({ id: 'noresult.button.add' })}
|
||||||
|
</Button>
|
||||||
|
</NoResult>
|
||||||
</ScrollerContext.Provider>
|
</ScrollerContext.Provider>
|
||||||
<AddModal
|
<AddModal
|
||||||
action={openModalStatus.action}
|
action={openModalStatus.action}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { expandKeysAtom } from '@/atoms/clusters';
|
import { expandKeysAtom } from '@/atoms/clusters';
|
||||||
import DeleteModal from '@/components/delete-modal';
|
import DeleteModal from '@/components/delete-modal';
|
||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import { FilterBar } from '@/components/page-tools';
|
import { FilterBar } from '@/components/page-tools';
|
||||||
import SealTable from '@/components/seal-table';
|
import SealTable from '@/components/seal-table';
|
||||||
import TableContext from '@/components/seal-table/table-context';
|
import TableContext from '@/components/seal-table/table-context';
|
||||||
@@ -12,9 +13,10 @@ import AddWorker from '@/pages/cluster-management/components/add-worker';
|
|||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { message } from 'antd';
|
import { Button, message } from 'antd';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import NoResult from '../_components/no-result';
|
||||||
import {
|
import {
|
||||||
CLUSTERS_API,
|
CLUSTERS_API,
|
||||||
createWorkerPool,
|
createWorkerPool,
|
||||||
@@ -39,7 +41,7 @@ import {
|
|||||||
} from './config/types';
|
} from './config/types';
|
||||||
import useClusterColumns from './hooks/use-cluster-columns';
|
import useClusterColumns from './hooks/use-cluster-columns';
|
||||||
|
|
||||||
const Credentials: React.FC = () => {
|
const Clusters: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
dataSource,
|
dataSource,
|
||||||
rowSelection,
|
rowSelection,
|
||||||
@@ -372,6 +374,26 @@ const Credentials: React.FC = () => {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
childParentKey="cluster_id"
|
childParentKey="cluster_id"
|
||||||
expandable={true}
|
expandable={true}
|
||||||
|
empty={
|
||||||
|
<NoResult
|
||||||
|
loading={dataSource.loading}
|
||||||
|
loadend={dataSource.loadend}
|
||||||
|
dataSource={dataSource.dataList}
|
||||||
|
image={<IconFont type="icon-cluster-outline" />}
|
||||||
|
filters={queryParams}
|
||||||
|
noFoundText={intl.formatMessage({
|
||||||
|
id: 'noresult.cluster.nofound'
|
||||||
|
})}
|
||||||
|
title={intl.formatMessage({ id: 'noresult.cluster.title' })}
|
||||||
|
subTitle={intl.formatMessage({
|
||||||
|
id: 'noresult.cluster.subTitle'
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Button type="primary" onClick={handleClickDropdown}>
|
||||||
|
{intl.formatMessage({ id: 'noresult.button.add' })}
|
||||||
|
</Button>
|
||||||
|
</NoResult>
|
||||||
|
}
|
||||||
pagination={{
|
pagination={{
|
||||||
showSizeChanger: true,
|
showSizeChanger: true,
|
||||||
pageSize: queryParams.perPage,
|
pageSize: queryParams.perPage,
|
||||||
@@ -451,4 +473,4 @@ const Credentials: React.FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Credentials;
|
export default Clusters;
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import useTableFetch from '@/hooks/use-table-fetch';
|
|||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
import { useIntl, useNavigate } from '@umijs/max';
|
import { useIntl, useNavigate } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { ConfigProvider, Empty, Table, message } from 'antd';
|
import { Button, ConfigProvider, Table, message } from 'antd';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import NoResult from '../_components/no-result';
|
||||||
import {
|
import {
|
||||||
createCredential,
|
createCredential,
|
||||||
deleteCredential,
|
deleteCredential,
|
||||||
@@ -148,14 +149,29 @@ const Credentials: React.FC = () => {
|
|||||||
|
|
||||||
const renderEmpty = (type?: string) => {
|
const renderEmpty = (type?: string) => {
|
||||||
if (type !== 'Table') return;
|
if (type !== 'Table') return;
|
||||||
if (
|
return (
|
||||||
!dataSource.loading &&
|
<NoResult
|
||||||
dataSource.loadend &&
|
loading={dataSource.loading}
|
||||||
!dataSource.dataList.length
|
loadend={dataSource.loadend}
|
||||||
) {
|
dataSource={[]}
|
||||||
return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}></Empty>;
|
image={<IconFont type="icon-credential-outline" />}
|
||||||
}
|
filters={queryParams}
|
||||||
return <div></div>;
|
noFoundText={intl.formatMessage({
|
||||||
|
id: 'noresult.credentials.nofound'
|
||||||
|
})}
|
||||||
|
title={intl.formatMessage({ id: 'noresult.credentials.title' })}
|
||||||
|
subTitle={intl.formatMessage({
|
||||||
|
id: 'noresult.credentials.subTitle'
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={() => handleAddCredential(addActions[0])}
|
||||||
|
>
|
||||||
|
{intl.formatMessage({ id: 'noresult.button.add' })}
|
||||||
|
</Button>
|
||||||
|
</NoResult>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = useCredentialColumns(sortOrder, handleSelect);
|
const columns = useCredentialColumns(sortOrder, handleSelect);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { request } from '@umijs/max';
|
|||||||
import qs from 'query-string';
|
import qs from 'query-string';
|
||||||
import {
|
import {
|
||||||
AccessControlFormData,
|
AccessControlFormData,
|
||||||
|
BackendItem,
|
||||||
CatalogItem,
|
CatalogItem,
|
||||||
CatalogSpec,
|
CatalogSpec,
|
||||||
EvaluateResult,
|
EvaluateResult,
|
||||||
@@ -405,14 +406,7 @@ export async function evaluationsModelSpec(
|
|||||||
|
|
||||||
export async function queryBackendList(params?: { cluster_id: number }) {
|
export async function queryBackendList(params?: { cluster_id: number }) {
|
||||||
return request<{
|
return request<{
|
||||||
items: {
|
items: BackendItem[];
|
||||||
backend_name: string;
|
|
||||||
backend_show_name: string;
|
|
||||||
from_config: boolean;
|
|
||||||
default_version: string;
|
|
||||||
default_backend_param: string[];
|
|
||||||
versions: string[];
|
|
||||||
}[];
|
|
||||||
}>(BACKEND_LIST_API, {
|
}>(BACKEND_LIST_API, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
params
|
params
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { modelsExpandKeysAtom } from '@/atoms/models';
|
import { modelsExpandKeysAtom } from '@/atoms/models';
|
||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import PageTools from '@/components/page-tools';
|
import PageTools from '@/components/page-tools';
|
||||||
import BaseSelect from '@/components/seal-form/base/select';
|
import BaseSelect from '@/components/seal-form/base/select';
|
||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
@@ -14,6 +15,7 @@ import { useAtom } from 'jotai';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import NoResult from '../_components/no-result';
|
||||||
import { createModel, queryCatalogList } from './apis';
|
import { createModel, queryCatalogList } from './apis';
|
||||||
import CatalogList from './components/catalog-list';
|
import CatalogList from './components/catalog-list';
|
||||||
import DelopyBuiltInModal from './components/deploy-builtin-modal';
|
import DelopyBuiltInModal from './components/deploy-builtin-modal';
|
||||||
@@ -297,6 +299,18 @@ const Catalog: React.FC = () => {
|
|||||||
activeId={-1}
|
activeId={-1}
|
||||||
isFirst={isFirst}
|
isFirst={isFirst}
|
||||||
></CatalogList>
|
></CatalogList>
|
||||||
|
<NoResult
|
||||||
|
loading={dataSource.loading}
|
||||||
|
loadend={!isFirst}
|
||||||
|
dataSource={dataSource.dataList}
|
||||||
|
image={<IconFont type="icon-layers" />}
|
||||||
|
filters={queryParams}
|
||||||
|
noFoundText={intl.formatMessage({
|
||||||
|
id: 'noresult.catalog.nofound'
|
||||||
|
})}
|
||||||
|
title={intl.formatMessage({ id: 'noresult.catalog.title' })}
|
||||||
|
subTitle={intl.formatMessage({ id: 'noresult.catalog.subTitle' })}
|
||||||
|
></NoResult>
|
||||||
</ScrollerContext.Provider>
|
</ScrollerContext.Provider>
|
||||||
<PageWrapper>
|
<PageWrapper>
|
||||||
<Pagination
|
<Pagination
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import CatalogSkelton from '@/components/templates/card-skelton';
|
|||||||
import breakpoints from '@/config/breakpoints';
|
import breakpoints from '@/config/breakpoints';
|
||||||
import InfiniteScroller from '@/pages/_components/infinite-scroller';
|
import InfiniteScroller from '@/pages/_components/infinite-scroller';
|
||||||
import { useScrollerContext } from '@/pages/_components/infinite-scroller/use-scroller-context';
|
import { useScrollerContext } from '@/pages/_components/infinite-scroller/use-scroller-context';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
import { Col, FloatButton, Row, Spin } from 'antd';
|
import { Col, FloatButton, Row, Spin } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import ResizeObserver from 'rc-resize-observer';
|
import ResizeObserver from 'rc-resize-observer';
|
||||||
@@ -55,6 +56,7 @@ const ListSkeleton: React.FC<{
|
|||||||
};
|
};
|
||||||
|
|
||||||
const CatalogList: React.FC<CatalogListProps> = (props) => {
|
const CatalogList: React.FC<CatalogListProps> = (props) => {
|
||||||
|
const intl = useIntl();
|
||||||
const { dataList, loading, activeId, isFirst, onDeploy } = props;
|
const { dataList, loading, activeId, isFirst, onDeploy } = props;
|
||||||
const {
|
const {
|
||||||
total,
|
total,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { modelsExpandKeysAtom } from '@/atoms/models';
|
|||||||
import DeleteModal from '@/components/delete-modal';
|
import DeleteModal from '@/components/delete-modal';
|
||||||
import DropDownActions from '@/components/drop-down-actions';
|
import DropDownActions from '@/components/drop-down-actions';
|
||||||
import DropdownButtons from '@/components/drop-down-buttons';
|
import DropdownButtons from '@/components/drop-down-buttons';
|
||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import { PageSize } from '@/components/logs-viewer/config';
|
import { PageSize } from '@/components/logs-viewer/config';
|
||||||
import PageTools from '@/components/page-tools';
|
import PageTools from '@/components/page-tools';
|
||||||
import BaseSelect from '@/components/seal-form/base/select';
|
import BaseSelect from '@/components/seal-form/base/select';
|
||||||
@@ -12,6 +13,7 @@ import useBodyScroll from '@/hooks/use-body-scroll';
|
|||||||
import useExpandedRowKeys from '@/hooks/use-expanded-row-keys';
|
import useExpandedRowKeys from '@/hooks/use-expanded-row-keys';
|
||||||
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
||||||
import useTableSort from '@/hooks/use-table-sort';
|
import useTableSort from '@/hooks/use-table-sort';
|
||||||
|
import NoResult from '@/pages/_components/no-result';
|
||||||
import { ListItem as WorkerListItem } from '@/pages/resources/config/types';
|
import { ListItem as WorkerListItem } from '@/pages/resources/config/types';
|
||||||
import { handleBatchRequest } from '@/utils';
|
import { handleBatchRequest } from '@/utils';
|
||||||
import { DownOutlined, SearchOutlined, SyncOutlined } from '@ant-design/icons';
|
import { DownOutlined, SearchOutlined, SyncOutlined } from '@ant-design/icons';
|
||||||
@@ -704,6 +706,30 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
loadChildren={getModelInstances}
|
loadChildren={getModelInstances}
|
||||||
loadChildrenAPI={generateChildrenRequestAPI}
|
loadChildrenAPI={generateChildrenRequestAPI}
|
||||||
renderChildren={renderChildren}
|
renderChildren={renderChildren}
|
||||||
|
empty={
|
||||||
|
<NoResult
|
||||||
|
loading={loading}
|
||||||
|
loadend={loadend}
|
||||||
|
dataSource={dataSource}
|
||||||
|
image={<IconFont type="icon-rocket-launch1" />}
|
||||||
|
filters={queryParams}
|
||||||
|
noFoundText={intl.formatMessage({
|
||||||
|
id: 'noresult.mymodels.nofound'
|
||||||
|
})}
|
||||||
|
title={intl.formatMessage({ id: 'noresult.deployments.title' })}
|
||||||
|
subTitle={intl.formatMessage({
|
||||||
|
id: 'noresult.deployments.subTitle'
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
iconPosition="end"
|
||||||
|
onClick={() => handleClickDropdown({ key: 'catalog' })}
|
||||||
|
>
|
||||||
|
{intl?.formatMessage?.({ id: 'models.table.button.deploy' })}
|
||||||
|
</Button>
|
||||||
|
</NoResult>
|
||||||
|
}
|
||||||
pagination={{
|
pagination={{
|
||||||
showSizeChanger: true,
|
showSizeChanger: true,
|
||||||
pageSize: queryParams.perPage,
|
pageSize: queryParams.perPage,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import vllmParameters from './vllm-parameters';
|
|||||||
export const backendOptionsMap = {
|
export const backendOptionsMap = {
|
||||||
llamaBox: 'llama-box',
|
llamaBox: 'llama-box',
|
||||||
vllm: 'vLLM',
|
vllm: 'vLLM',
|
||||||
voxBox: 'vox-box',
|
voxBox: 'VoxBox',
|
||||||
ascendMindie: 'MindIE',
|
ascendMindie: 'MindIE',
|
||||||
custom: 'Custom'
|
custom: 'Custom'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,12 +13,6 @@ export const modalConfig: Record<
|
|||||||
width: 'calc(100vw - 220px)',
|
width: 'calc(100vw - 220px)',
|
||||||
source: modelSourceMap.huggingface_value
|
source: modelSourceMap.huggingface_value
|
||||||
},
|
},
|
||||||
ollama_library: {
|
|
||||||
show: true,
|
|
||||||
width: 600,
|
|
||||||
isGGUF: true,
|
|
||||||
source: modelSourceMap.ollama_library_value
|
|
||||||
},
|
|
||||||
modelscope: {
|
modelscope: {
|
||||||
show: true,
|
show: true,
|
||||||
width: 'calc(100vw - 220px)',
|
width: 'calc(100vw - 220px)',
|
||||||
|
|||||||
@@ -264,3 +264,14 @@ export interface AccessControlFormData {
|
|||||||
access_policy: 'public' | 'authed' | 'allowed_users';
|
access_policy: 'public' | 'authed' | 'allowed_users';
|
||||||
users: { id: number }[];
|
users: { id: number }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BackendItem {
|
||||||
|
backend_name: string;
|
||||||
|
from_config: boolean;
|
||||||
|
default_version: string;
|
||||||
|
default_backend_param: string[];
|
||||||
|
versions: {
|
||||||
|
version: string;
|
||||||
|
is_deprecated: boolean;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ export default function useQueryBackends() {
|
|||||||
const list = res?.items?.map((item) => {
|
const list = res?.items?.map((item) => {
|
||||||
return {
|
return {
|
||||||
value: item.backend_name,
|
value: item.backend_name,
|
||||||
label: item.backend_show_name,
|
label: item.backend_name,
|
||||||
default_backend_param: item.default_backend_param || [],
|
default_backend_param: item.default_backend_param || [],
|
||||||
default_version: item.default_version,
|
default_version: item.default_version,
|
||||||
versions: (item.versions || []).map((version) => ({
|
versions: (item.versions || []).map((vItem) => ({
|
||||||
label: version,
|
label: vItem.version,
|
||||||
value: version
|
value: vItem.version
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ const Models: React.FC = () => {
|
|||||||
page: 1,
|
page: 1,
|
||||||
perPage: 10,
|
perPage: 10,
|
||||||
search: '',
|
search: '',
|
||||||
|
cluster_id: 0,
|
||||||
categories: []
|
categories: []
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -191,7 +192,11 @@ const Models: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createModelsChunkRequest = useCallback(
|
const createModelsChunkRequest = useCallback(
|
||||||
async (params?: { search: string; categories: any[] }) => {
|
async (params?: {
|
||||||
|
search: string;
|
||||||
|
categories: any[];
|
||||||
|
cluster_id: number;
|
||||||
|
}) => {
|
||||||
const search = params?.search || queryParams.search;
|
const search = params?.search || queryParams.search;
|
||||||
const categories = params?.categories || queryParams.categories;
|
const categories = params?.categories || queryParams.categories;
|
||||||
chunkRequedtRef.current?.current?.cancel?.();
|
chunkRequedtRef.current?.current?.cancel?.();
|
||||||
@@ -266,7 +271,8 @@ const Models: React.FC = () => {
|
|||||||
});
|
});
|
||||||
createModelsChunkRequest({
|
createModelsChunkRequest({
|
||||||
search: e.target.value,
|
search: e.target.value,
|
||||||
categories: queryParams.categories
|
categories: queryParams.categories,
|
||||||
|
cluster_id: queryParams.cluster_id || 0
|
||||||
});
|
});
|
||||||
}, 350);
|
}, 350);
|
||||||
|
|
||||||
@@ -279,17 +285,19 @@ const Models: React.FC = () => {
|
|||||||
});
|
});
|
||||||
createModelsChunkRequest({
|
createModelsChunkRequest({
|
||||||
search: queryParams.search,
|
search: queryParams.search,
|
||||||
|
cluster_id: queryParams.cluster_id || 0,
|
||||||
categories: value
|
categories: value
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClusterChange = async (value: any) => {
|
const handleClusterChange = async (value: number) => {
|
||||||
handleQueryChange({
|
handleQueryChange({
|
||||||
page: 1,
|
page: 1,
|
||||||
cluster_id: value
|
cluster_id: value
|
||||||
});
|
});
|
||||||
createModelsChunkRequest({
|
createModelsChunkRequest({
|
||||||
search: queryParams.search,
|
search: queryParams.search,
|
||||||
|
categories: queryParams.categories,
|
||||||
cluster_id: value
|
cluster_id: value
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import PageTools from '@/components/page-tools';
|
import PageTools from '@/components/page-tools';
|
||||||
import BaseSelect from '@/components/seal-form/base/select';
|
import BaseSelect from '@/components/seal-form/base/select';
|
||||||
import CardList from '@/components/templates/card-list';
|
import CardList from '@/components/templates/card-list';
|
||||||
@@ -10,6 +11,7 @@ import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
|
|||||||
import { Button, Input, Space } from 'antd';
|
import { Button, Input, Space } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ScrollerContext } from '../_components/infinite-scroller/use-scroller-context';
|
import { ScrollerContext } from '../_components/infinite-scroller/use-scroller-context';
|
||||||
|
import NoResult from '../_components/no-result';
|
||||||
import { MY_MODELS_API, queryMyModels } from './apis';
|
import { MY_MODELS_API, queryMyModels } from './apis';
|
||||||
import ModelItem from './components/model-item';
|
import ModelItem from './components/model-item';
|
||||||
import { categoryOptions, modelCategoriesMap } from './config';
|
import { categoryOptions, modelCategoriesMap } from './config';
|
||||||
@@ -67,8 +69,11 @@ const UserModels: React.FC = () => {
|
|||||||
|
|
||||||
const loadMore = useMemoizedFn((nextPage: number) => {
|
const loadMore = useMemoizedFn((nextPage: number) => {
|
||||||
fetchData({
|
fetchData({
|
||||||
...queryParams,
|
query: {
|
||||||
page: nextPage
|
...queryParams,
|
||||||
|
page: nextPage
|
||||||
|
},
|
||||||
|
loadmore: true
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -137,6 +142,18 @@ const UserModels: React.FC = () => {
|
|||||||
Skeleton={CardSkeleton}
|
Skeleton={CardSkeleton}
|
||||||
renderItem={renderCard}
|
renderItem={renderCard}
|
||||||
></CardList>
|
></CardList>
|
||||||
|
<NoResult
|
||||||
|
loading={dataSource.loading}
|
||||||
|
loadend={dataSource.loadend}
|
||||||
|
dataSource={dataSource.dataList}
|
||||||
|
image={<IconFont type="icon-models" />}
|
||||||
|
filters={queryParams}
|
||||||
|
noFoundText={intl.formatMessage({
|
||||||
|
id: 'noresult.mymodels.nofound'
|
||||||
|
})}
|
||||||
|
title={intl.formatMessage({ id: 'noresult.mymodels.title' })}
|
||||||
|
subTitle={intl.formatMessage({ id: 'noresult.mymodels.subTitle' })}
|
||||||
|
></NoResult>
|
||||||
</ScrollerContext.Provider>
|
</ScrollerContext.Provider>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import { FilterBar } from '@/components/page-tools';
|
import { FilterBar } from '@/components/page-tools';
|
||||||
import useTableFetch from '@/hooks/use-table-fetch';
|
import useTableFetch from '@/hooks/use-table-fetch';
|
||||||
|
import NoResult from '@/pages/_components/no-result';
|
||||||
import { queryClusterList } from '@/pages/cluster-management/apis';
|
import { queryClusterList } from '@/pages/cluster-management/apis';
|
||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { ConfigProvider, Empty, Table } from 'antd';
|
import { ConfigProvider, Table } from 'antd';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { GPU_DEVICES_API, queryGpuDevicesList } from '../apis';
|
import { GPU_DEVICES_API, queryGpuDevicesList } from '../apis';
|
||||||
import { GPUDeviceItem } from '../config/types';
|
import { GPUDeviceItem } from '../config/types';
|
||||||
@@ -44,14 +46,18 @@ const GPUList: React.FC = () => {
|
|||||||
|
|
||||||
const renderEmpty = (type?: string) => {
|
const renderEmpty = (type?: string) => {
|
||||||
if (type !== 'Table') return;
|
if (type !== 'Table') return;
|
||||||
if (
|
return (
|
||||||
!dataSource.loading &&
|
<NoResult
|
||||||
dataSource.loadend &&
|
loading={dataSource.loading}
|
||||||
!dataSource.dataList.length
|
loadend={dataSource.loadend}
|
||||||
) {
|
dataSource={dataSource.dataList}
|
||||||
return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}></Empty>;
|
image={<IconFont type="icon-gpu1" />}
|
||||||
}
|
filters={queryParams}
|
||||||
return <div></div>;
|
noFoundText={intl.formatMessage({ id: 'noresult.gpus.nofound' })}
|
||||||
|
title={intl.formatMessage({ id: 'noresult.gpus.title' })}
|
||||||
|
subTitle={intl.formatMessage({ id: 'noresult.gpus.subTitle' })}
|
||||||
|
></NoResult>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = useGPUColumns({
|
const columns = useGPUColumns({
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { modelsExpandKeysAtom } from '@/atoms/models';
|
import { modelsExpandKeysAtom } from '@/atoms/models';
|
||||||
import DeleteModal from '@/components/delete-modal';
|
import DeleteModal from '@/components/delete-modal';
|
||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import { FilterBar } from '@/components/page-tools';
|
import { FilterBar } from '@/components/page-tools';
|
||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import useAppUtils from '@/hooks/use-app-utils';
|
import useAppUtils from '@/hooks/use-app-utils';
|
||||||
import useBodyScroll from '@/hooks/use-body-scroll';
|
import useBodyScroll from '@/hooks/use-body-scroll';
|
||||||
import useTableFetch from '@/hooks/use-table-fetch';
|
import useTableFetch from '@/hooks/use-table-fetch';
|
||||||
|
import NoResult from '@/pages/_components/no-result';
|
||||||
import { createModel } from '@/pages/llmodels/apis';
|
import { createModel } from '@/pages/llmodels/apis';
|
||||||
import DeployModal from '@/pages/llmodels/components/deploy-modal';
|
import DeployModal from '@/pages/llmodels/components/deploy-modal';
|
||||||
import { modelSourceMap } from '@/pages/llmodels/config';
|
import { modelSourceMap } from '@/pages/llmodels/config';
|
||||||
@@ -21,7 +23,7 @@ import useRecognizeAudio from '@/pages/llmodels/hooks/use-recognize-audio';
|
|||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
import { useIntl, useNavigate } from '@umijs/max';
|
import { useIntl, useNavigate } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { ConfigProvider, Empty, Table, message } from 'antd';
|
import { ConfigProvider, Table, message } from 'antd';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
@@ -190,18 +192,6 @@ const ModelFiles = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderEmpty = (type?: string) => {
|
|
||||||
if (type !== 'Table') return;
|
|
||||||
if (
|
|
||||||
!dataSource.loading &&
|
|
||||||
dataSource.loadend &&
|
|
||||||
!dataSource.dataList.length
|
|
||||||
) {
|
|
||||||
return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}></Empty>;
|
|
||||||
}
|
|
||||||
return <div></div>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClickDropdown = (item: any) => {
|
const handleClickDropdown = (item: any) => {
|
||||||
const config = modalConfig[item.key];
|
const config = modalConfig[item.key];
|
||||||
const hasLinuxWorker = workersList.some(
|
const hasLinuxWorker = workersList.some(
|
||||||
@@ -212,6 +202,22 @@ const ModelFiles = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderEmpty = (type?: string) => {
|
||||||
|
if (type !== 'Table') return;
|
||||||
|
return (
|
||||||
|
<NoResult
|
||||||
|
loading={dataSource.loading}
|
||||||
|
loadend={dataSource.loadend}
|
||||||
|
dataSource={dataSource.dataList}
|
||||||
|
image={<IconFont type="icon-files" />}
|
||||||
|
filters={queryParams}
|
||||||
|
noFoundText={intl.formatMessage({ id: 'noresult.modelfiles.nofound' })}
|
||||||
|
title={intl.formatMessage({ id: 'noresult.modelfiles.title' })}
|
||||||
|
subTitle={intl.formatMessage({ id: 'noresult.modelfiles.subTitle' })}
|
||||||
|
></NoResult>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const handleDownloadCancel = () => {
|
const handleDownloadCancel = () => {
|
||||||
setDownlaodMoalStatus({
|
setDownlaodMoalStatus({
|
||||||
...downloadModalStatus,
|
...downloadModalStatus,
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import DeleteModal from '@/components/delete-modal';
|
import DeleteModal from '@/components/delete-modal';
|
||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import { FilterBar } from '@/components/page-tools';
|
import { FilterBar } from '@/components/page-tools';
|
||||||
import useTableFetch from '@/hooks/use-table-fetch';
|
import useTableFetch from '@/hooks/use-table-fetch';
|
||||||
import { queryClusterList } from '@/pages/cluster-management/apis';
|
import { queryClusterList } from '@/pages/cluster-management/apis';
|
||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl, useNavigate } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { ConfigProvider, Empty, Table, message } from 'antd';
|
import { Button, ConfigProvider, Table, message } from 'antd';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import NoResult from '../../_components/no-result';
|
||||||
import TerminalTabs from '../../_components/terminal-tabs';
|
import TerminalTabs from '../../_components/terminal-tabs';
|
||||||
import {
|
import {
|
||||||
WORKERS_API,
|
WORKERS_API,
|
||||||
@@ -43,6 +45,7 @@ const Workers: React.FC = () => {
|
|||||||
API: WORKERS_API
|
API: WORKERS_API
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [updateLabelsData, setUpdateLabelsData] = useState<{
|
const [updateLabelsData, setUpdateLabelsData] = useState<{
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@@ -175,16 +178,28 @@ const Workers: React.FC = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleAddWorker = () => {
|
||||||
|
navigate('/cluster-management/clusters/list');
|
||||||
|
};
|
||||||
|
|
||||||
const renderEmpty = (type?: string) => {
|
const renderEmpty = (type?: string) => {
|
||||||
if (type !== 'Table') return;
|
if (type !== 'Table') return;
|
||||||
if (
|
return (
|
||||||
!dataSource.loading &&
|
<NoResult
|
||||||
dataSource.loadend &&
|
loading={dataSource.loading}
|
||||||
!dataSource.dataList.length
|
loadend={dataSource.loadend}
|
||||||
) {
|
dataSource={dataSource.dataList}
|
||||||
return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}></Empty>;
|
image={<IconFont type="icon-resources" />}
|
||||||
}
|
filters={queryParams}
|
||||||
return <div></div>;
|
noFoundText={intl.formatMessage({ id: 'noresult.workers.nofound' })}
|
||||||
|
title={intl.formatMessage({ id: 'noresult.workers.title' })}
|
||||||
|
subTitle={intl.formatMessage({ id: 'noresult.workers.subTitle' })}
|
||||||
|
>
|
||||||
|
<Button type="primary" onClick={handleAddWorker}>
|
||||||
|
{intl.formatMessage({ id: 'noresult.workers.button.add' })}
|
||||||
|
</Button>
|
||||||
|
</NoResult>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClusterChange = (value: number) => {
|
const handleClusterChange = (value: number) => {
|
||||||
|
|||||||
+21
-17
@@ -1,4 +1,5 @@
|
|||||||
import DeleteModal from '@/components/delete-modal';
|
import DeleteModal from '@/components/delete-modal';
|
||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import { FilterBar } from '@/components/page-tools';
|
import { FilterBar } from '@/components/page-tools';
|
||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import type { PageActionType } from '@/config/types';
|
import type { PageActionType } from '@/config/types';
|
||||||
@@ -6,21 +7,14 @@ import useTableFetch from '@/hooks/use-table-fetch';
|
|||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { ConfigProvider, Empty, message, Switch, Table } from 'antd';
|
import { Button, ConfigProvider, message, Table } from 'antd';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import NoResult from '../_components/no-result';
|
||||||
import { createUser, deleteUser, queryUsersList, updateUser } from './apis';
|
import { createUser, deleteUser, queryUsersList, updateUser } from './apis';
|
||||||
import AddModal from './components/add-modal';
|
import AddModal from './components/add-modal';
|
||||||
import { FormData, ListItem } from './config/types';
|
import { FormData, ListItem } from './config/types';
|
||||||
import useUsersColumns from './hooks/use-users-columns';
|
import useUsersColumns from './hooks/use-users-columns';
|
||||||
|
|
||||||
const StyledSwitch = styled(Switch)`
|
|
||||||
.ant-switch-handle::before {
|
|
||||||
inset-inline-end: 0 !important;
|
|
||||||
inset-inline-start: 0 !important;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Users: React.FC = () => {
|
const Users: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
dataSource,
|
dataSource,
|
||||||
@@ -136,14 +130,24 @@ const Users: React.FC = () => {
|
|||||||
|
|
||||||
const renderEmpty = (type?: string) => {
|
const renderEmpty = (type?: string) => {
|
||||||
if (type !== 'Table') return;
|
if (type !== 'Table') return;
|
||||||
if (
|
return (
|
||||||
!dataSource.loading &&
|
<NoResult
|
||||||
dataSource.loadend &&
|
loading={dataSource.loading}
|
||||||
!dataSource.dataList.length
|
loadend={dataSource.loadend}
|
||||||
) {
|
dataSource={dataSource.dataList}
|
||||||
return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE}></Empty>;
|
image={<IconFont type="icon-users" />}
|
||||||
}
|
filters={queryParams}
|
||||||
return <div></div>;
|
noFoundText={intl.formatMessage({
|
||||||
|
id: 'noresult.users.nofound'
|
||||||
|
})}
|
||||||
|
title={intl.formatMessage({ id: 'noresult.users.title' })}
|
||||||
|
subTitle={intl.formatMessage({ id: 'noresult.users.subTitle' })}
|
||||||
|
>
|
||||||
|
<Button type="primary" onClick={handleAddUser}>
|
||||||
|
{intl.formatMessage({ id: 'noresult.button.add' })}
|
||||||
|
</Button>
|
||||||
|
</NoResult>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = useUsersColumns({
|
const columns = useUsersColumns({
|
||||||
|
|||||||
Reference in New Issue
Block a user