fix(style): cluster state do not display
This commit is contained in:
+10
-11
@@ -104,17 +104,6 @@ export default [
|
|||||||
defaultIcon: 'icon-models',
|
defaultIcon: 'icon-models',
|
||||||
access: 'canSeeUser',
|
access: 'canSeeUser',
|
||||||
component: './llmodels/user-models'
|
component: './llmodels/user-models'
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'backendsList',
|
|
||||||
path: '/models/backends/list',
|
|
||||||
key: 'backendsList',
|
|
||||||
icon: 'icon-backend',
|
|
||||||
selectedIcon: 'icon-backend-filled',
|
|
||||||
defaultIcon: 'icon-backend',
|
|
||||||
access: 'canSeeAdmin',
|
|
||||||
subMenu: ['/models/backends/create'],
|
|
||||||
component: './backends/index'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -154,6 +143,16 @@ export default [
|
|||||||
selectedIcon: 'icon-files-filled',
|
selectedIcon: 'icon-files-filled',
|
||||||
defaultIcon: 'icon-files',
|
defaultIcon: 'icon-files',
|
||||||
component: './resources/components/model-files'
|
component: './resources/components/model-files'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'backendsList',
|
||||||
|
path: '/resources/backends',
|
||||||
|
key: 'backendsList',
|
||||||
|
icon: 'icon-backend',
|
||||||
|
selectedIcon: 'icon-backend-filled',
|
||||||
|
defaultIcon: 'icon-backend',
|
||||||
|
access: 'canSeeAdmin',
|
||||||
|
component: './backends/index'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ const icons = {
|
|||||||
Yaml: React.createElement(IconFont, { type: 'icon-code_block' }),
|
Yaml: React.createElement(IconFont, { type: 'icon-code_block' }),
|
||||||
Version: React.createElement(IconFont, { type: 'icon-version' }),
|
Version: React.createElement(IconFont, { type: 'icon-version' }),
|
||||||
Parameter: React.createElement(IconFont, { type: 'icon-parameters' }),
|
Parameter: React.createElement(IconFont, { type: 'icon-parameters' }),
|
||||||
Private: React.createElement(IconFont, { type: 'icon-private' })
|
Private: React.createElement(IconFont, { type: 'icon-private' }),
|
||||||
|
AWS: React.createElement(IconFont, { type: 'icon-aws' })
|
||||||
};
|
};
|
||||||
|
|
||||||
export default icons;
|
export default icons;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons';
|
|||||||
// import './iconfont/iconfont.js';
|
// import './iconfont/iconfont.js';
|
||||||
|
|
||||||
const IconFont = createFromIconfontCN({
|
const IconFont = createFromIconfontCN({
|
||||||
scriptUrl: '//at.alicdn.com/t/c/font_4613488_lg2z989p7f.js'
|
scriptUrl: '//at.alicdn.com/t/c/font_4613488_ab78o2vlum.js'
|
||||||
});
|
});
|
||||||
|
|
||||||
export default IconFont;
|
export default IconFont;
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import React from 'react';
|
|||||||
|
|
||||||
interface CatalogSkeltonProps {
|
interface CatalogSkeltonProps {
|
||||||
span: number;
|
span: number;
|
||||||
|
skeletonProps?: any;
|
||||||
|
skeletonStyle?: React.CSSProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CardSkelton: React.FC<CatalogSkeltonProps> = (props) => {
|
const CardSkelton: React.FC<CatalogSkeltonProps> = (props) => {
|
||||||
@@ -21,8 +23,10 @@ const CardSkelton: React.FC<CatalogSkeltonProps> = (props) => {
|
|||||||
style={{
|
style={{
|
||||||
border: '1px solid var(--ant-color-border)',
|
border: '1px solid var(--ant-color-border)',
|
||||||
borderRadius: 'var(--border-radius-base)',
|
borderRadius: 'var(--border-radius-base)',
|
||||||
padding: '16px 16px'
|
padding: '16px 16px',
|
||||||
|
...props.skeletonStyle
|
||||||
}}
|
}}
|
||||||
|
{...(props.skeletonProps || {})}
|
||||||
></Skeleton>
|
></Skeleton>
|
||||||
</Col>
|
</Col>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export default function useTableFetch<T>(
|
|||||||
defaultData?: any[];
|
defaultData?: any[];
|
||||||
events?: EventsType[];
|
events?: EventsType[];
|
||||||
defaultQueryParams?: Record<string, any>;
|
defaultQueryParams?: Record<string, any>;
|
||||||
|
isInfiniteScroll?: boolean;
|
||||||
} & WatchConfig
|
} & WatchConfig
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
@@ -33,7 +34,8 @@ export default function useTableFetch<T>(
|
|||||||
watch,
|
watch,
|
||||||
defaultData = [],
|
defaultData = [],
|
||||||
events = ['UPDATE', 'DELETE'],
|
events = ['UPDATE', 'DELETE'],
|
||||||
defaultQueryParams = {}
|
defaultQueryParams = {},
|
||||||
|
isInfiniteScroll = false
|
||||||
} = options;
|
} = options;
|
||||||
const pollingRef = useRef<any>(null);
|
const pollingRef = useRef<any>(null);
|
||||||
const chunkRequedtRef = useRef<any>(null);
|
const chunkRequedtRef = useRef<any>(null);
|
||||||
@@ -141,6 +143,9 @@ export default function useTableFetch<T>(
|
|||||||
total: newRes.pagination.total,
|
total: newRes.pagination.total,
|
||||||
totalPage: newRes.pagination.totalPage
|
totalPage: newRes.pagination.totalPage
|
||||||
});
|
});
|
||||||
|
if (isInfiniteScroll) {
|
||||||
|
setQueryParams(newParams);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,6 +156,12 @@ export default function useTableFetch<T>(
|
|||||||
total: res.pagination.total,
|
total: res.pagination.total,
|
||||||
totalPage: res.pagination.totalPage
|
totalPage: res.pagination.totalPage
|
||||||
});
|
});
|
||||||
|
if (isInfiniteScroll && query?.page) {
|
||||||
|
setQueryParams({
|
||||||
|
...queryParams,
|
||||||
|
...query
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('error', error);
|
console.log('error', error);
|
||||||
setDataSource({
|
setDataSource({
|
||||||
|
|||||||
@@ -32,5 +32,5 @@ export default {
|
|||||||
'menu.clusterManagement.credentials': 'Cloud Credentials',
|
'menu.clusterManagement.credentials': 'Cloud Credentials',
|
||||||
'menu.clusterManagement.clusterDetail': 'Cluster Detail',
|
'menu.clusterManagement.clusterDetail': 'Cluster Detail',
|
||||||
'menu.clusterManagement.clusterCreate': 'Create Cluster',
|
'menu.clusterManagement.clusterCreate': 'Create Cluster',
|
||||||
'menu.models.backendsList': 'Inference Backends'
|
'menu.resources.backendsList': 'Inference Backends'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default {
|
|||||||
'menu.models.userModels': 'My Models',
|
'menu.models.userModels': 'My Models',
|
||||||
'menu.clusterManagement.clusterDetail': 'Cluster Detail',
|
'menu.clusterManagement.clusterDetail': 'Cluster Detail',
|
||||||
'menu.clusterManagement.clusterCreate': 'Create Cluster',
|
'menu.clusterManagement.clusterCreate': 'Create Cluster',
|
||||||
'menu.models.backendsList': 'Inference Backends'
|
'menu.resources.backendsList': 'Inference Backends'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
@@ -49,5 +49,5 @@ export default {
|
|||||||
// 11. 'menu.models.userModels': 'My Models'
|
// 11. 'menu.models.userModels': 'My Models'
|
||||||
// 12. 'menu.clusterManagement.clusterDetail': 'Cluster Detail',
|
// 12. 'menu.clusterManagement.clusterDetail': 'Cluster Detail',
|
||||||
// 13. 'menu.clusterManagement.clusterCreate': 'Create Cluster',
|
// 13. 'menu.clusterManagement.clusterCreate': 'Create Cluster',
|
||||||
// 14. 'menu.models.backendsList': 'Inference Backends'
|
// 14. 'menu.resources.backendsList': 'Inference Backends'
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ export default {
|
|||||||
'menu.models.userModels': 'Мои модели',
|
'menu.models.userModels': 'Мои модели',
|
||||||
'menu.clusterManagement.clusterDetail': 'Детали кластера',
|
'menu.clusterManagement.clusterDetail': 'Детали кластера',
|
||||||
'menu.clusterManagement.clusterCreate': 'Создать кластер',
|
'menu.clusterManagement.clusterCreate': 'Создать кластер',
|
||||||
'menu.models.backendsList': 'Inference Backends'
|
'menu.resources.backendsList': 'Inference Backends'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
// 14. 'menu.models.backendsList': 'Inference Backends'
|
// 14. 'menu.resources.backendsList': 'Inference Backends'
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -32,5 +32,5 @@ export default {
|
|||||||
'menu.clusterManagement.credentials': '云凭证',
|
'menu.clusterManagement.credentials': '云凭证',
|
||||||
'menu.clusterManagement.clusterDetail': '集群详情',
|
'menu.clusterManagement.clusterDetail': '集群详情',
|
||||||
'menu.clusterManagement.clusterCreate': '创建集群',
|
'menu.clusterManagement.clusterCreate': '创建集群',
|
||||||
'menu.models.backendsList': '推理后端'
|
'menu.resources.backendsList': '推理后端'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ const BackendCard: React.FC<BackendCardProps> = ({ data, onSelect }) => {
|
|||||||
color="geekblue"
|
color="geekblue"
|
||||||
className="font-400"
|
className="font-400"
|
||||||
bordered={false}
|
bordered={false}
|
||||||
style={{ borderRadius: 'var(--ant-border-radius)' }}
|
style={{ borderRadius: 'var(--ant-border-radius)', margin: 0 }}
|
||||||
>
|
>
|
||||||
{intl.formatMessage({ id: 'backend.builtin' })}
|
{intl.formatMessage({ id: 'backend.builtin' })}
|
||||||
</Tag>
|
</Tag>
|
||||||
|
|||||||
@@ -24,6 +24,20 @@ const SpinWrapper = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const SkeletonWrapper = styled.div`
|
||||||
|
.ant-skeleton-content {
|
||||||
|
.ant-skeleton-paragraph {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
li {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface BackendListProps {
|
interface BackendListProps {
|
||||||
defaultSpan?: number;
|
defaultSpan?: number;
|
||||||
resizable?: boolean;
|
resizable?: boolean;
|
||||||
@@ -34,12 +48,6 @@ interface BackendListProps {
|
|||||||
onSelect?: (item: any) => void;
|
onSelect?: (item: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InnerSkeleton: React.FC<{
|
|
||||||
span: number;
|
|
||||||
}> = (props) => {
|
|
||||||
return <CardSkeleton {...props} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ListSkeleton: React.FC<{
|
const ListSkeleton: React.FC<{
|
||||||
span: number;
|
span: number;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@@ -56,7 +64,21 @@ const ListSkeleton: React.FC<{
|
|||||||
}}
|
}}
|
||||||
wrapperClassName="skelton-wrapper"
|
wrapperClassName="skelton-wrapper"
|
||||||
>
|
>
|
||||||
{isFirst && <InnerSkeleton span={span}></InnerSkeleton>}
|
{isFirst && (
|
||||||
|
<SkeletonWrapper>
|
||||||
|
<CardSkeleton
|
||||||
|
span={span}
|
||||||
|
skeletonProps={{
|
||||||
|
title: false
|
||||||
|
}}
|
||||||
|
skeletonStyle={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: 26
|
||||||
|
}}
|
||||||
|
></CardSkeleton>
|
||||||
|
</SkeletonWrapper>
|
||||||
|
)}
|
||||||
</Spin>
|
</Spin>
|
||||||
</SpinWrapper>
|
</SpinWrapper>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import CollapsibleContainer from '@/components/collapse-container';
|
import CollapsibleContainer from '@/components/collapse-container';
|
||||||
|
import BaseSelect from '@/components/seal-form/base/select';
|
||||||
import SealInput from '@/components/seal-form/seal-input';
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
import SealSelect from '@/components/seal-form/seal-select';
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import useAppUtils from '@/hooks/use-app-utils';
|
import useAppUtils from '@/hooks/use-app-utils';
|
||||||
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
|
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Empty, Form, Select, Tag } from 'antd';
|
import { Button, Empty, Form, Tag } from 'antd';
|
||||||
import React, { useEffect, useMemo } from 'react';
|
import React, { useEffect, useMemo } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { frameworks } from '../config';
|
import { frameworks } from '../config';
|
||||||
@@ -163,7 +164,7 @@ const VersionsForm: React.FC<AddModalProps> = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
{!currentData?.is_built_in && (
|
{!currentData?.is_built_in && (
|
||||||
<Select
|
<BaseSelect
|
||||||
prefix={
|
prefix={
|
||||||
<span style={{ color: 'var(--ant-color-text-tertiary)' }}>
|
<span style={{ color: 'var(--ant-color-text-tertiary)' }}>
|
||||||
{intl.formatMessage({ id: 'backend.isDefault' })}:
|
{intl.formatMessage({ id: 'backend.isDefault' })}:
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ const BackendList = () => {
|
|||||||
deleteAPI: deleteBackend,
|
deleteAPI: deleteBackend,
|
||||||
API: INFERENCE_BACKEND_API,
|
API: INFERENCE_BACKEND_API,
|
||||||
watch: false,
|
watch: false,
|
||||||
|
isInfiniteScroll: true,
|
||||||
contentForDelete: 'backends.title',
|
contentForDelete: 'backends.title',
|
||||||
defaultQueryParams: {
|
defaultQueryParams: {
|
||||||
perPage: 100
|
perPage: 100
|
||||||
@@ -154,7 +155,7 @@ const BackendList = () => {
|
|||||||
<PageContainer
|
<PageContainer
|
||||||
ghost
|
ghost
|
||||||
header={{
|
header={{
|
||||||
title: intl.formatMessage({ id: 'menu.models.backendsList' }),
|
title: intl.formatMessage({ id: 'menu.resources.backendsList' }),
|
||||||
style: {
|
style: {
|
||||||
paddingInline: 'var(--layout-content-header-inlinepadding)'
|
paddingInline: 'var(--layout-content-header-inlinepadding)'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ const Title = styled.div`
|
|||||||
height: 40px;
|
height: 40px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
// background-color: var(--ant-color-fill-secondary);
|
|
||||||
border-radius: var(--ant-border-radius);
|
border-radius: var(--ant-border-radius);
|
||||||
margin-bottom: 22px;
|
margin-bottom: 22px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import icons from '@/components/icon-font/icons';
|
import icons from '@/components/icon-font/icons';
|
||||||
import { StatusMaps } from '@/config';
|
import { StatusMaps } from '@/config';
|
||||||
import { StatusType } from '@/config/types';
|
import { StatusType } from '@/config/types';
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
export const ClusterStatusValueMap = {
|
export const ClusterStatusValueMap = {
|
||||||
Provisioning: 0,
|
Provisioning: 'provisioning',
|
||||||
Ready: 3,
|
Ready: 'ready',
|
||||||
Provisioned: 1
|
Provisioned: 'provisioned'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ClusterStatusLabelMap = {
|
export const ClusterStatusLabelMap = {
|
||||||
@@ -26,8 +25,9 @@ export const ProviderValueMap = {
|
|||||||
DigitalOcean: 'DigitalOcean',
|
DigitalOcean: 'DigitalOcean',
|
||||||
Docker: 'Docker',
|
Docker: 'Docker',
|
||||||
HuaweiCloud: 'HuaweiCloud',
|
HuaweiCloud: 'HuaweiCloud',
|
||||||
AliCloud: 'AliCloud',
|
AliCloud: 'AlibabaCloud',
|
||||||
TencentCloud: 'TencentCloud'
|
TencentCloud: 'TencentCloud',
|
||||||
|
AWS: 'AWS'
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProviderType = keyof typeof ProviderValueMap | null | undefined;
|
export type ProviderType = keyof typeof ProviderValueMap | null | undefined;
|
||||||
@@ -68,71 +68,6 @@ export const vendorIconMap = {
|
|||||||
fedora: 'icon-fedora'
|
fedora: 'icon-fedora'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const providerList = [
|
|
||||||
{
|
|
||||||
label: 'clusters.provider.custom',
|
|
||||||
locale: true,
|
|
||||||
value: ProviderValueMap.Docker,
|
|
||||||
key: ProviderValueMap.Docker,
|
|
||||||
icon: React.cloneElement(icons.Docker, {
|
|
||||||
style: { color: 'var(--ant-color-primary)' }
|
|
||||||
}),
|
|
||||||
group: 'Self-Managed'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Kubernetes',
|
|
||||||
locale: false,
|
|
||||||
value: ProviderValueMap.Kubernetes,
|
|
||||||
key: ProviderValueMap.Kubernetes,
|
|
||||||
icon: React.cloneElement(icons.KubernetesOutlined, {
|
|
||||||
style: { color: 'var(--ant-color-primary)' }
|
|
||||||
}),
|
|
||||||
group: 'Self-Managed'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'DigitalOcean',
|
|
||||||
locale: false,
|
|
||||||
value: ProviderValueMap.DigitalOcean,
|
|
||||||
key: ProviderValueMap.DigitalOcean,
|
|
||||||
icon: React.cloneElement(icons.DigitalOcean, {
|
|
||||||
style: {
|
|
||||||
color: 'var(--ant-color-primary)'
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
group: 'Cloud Provider'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Huawei Cloud',
|
|
||||||
locale: false,
|
|
||||||
disabled: true,
|
|
||||||
value: ProviderValueMap.HuaweiCloud,
|
|
||||||
key: ProviderValueMap.HuaweiCloud,
|
|
||||||
icon: icons.HuaweiCloud,
|
|
||||||
description: 'Comming soon',
|
|
||||||
group: 'Cloud Provider'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Ali Cloud',
|
|
||||||
locale: false,
|
|
||||||
disabled: true,
|
|
||||||
value: ProviderValueMap.AliCloud,
|
|
||||||
key: ProviderValueMap.AliCloud,
|
|
||||||
icon: icons.AliCloud,
|
|
||||||
description: 'Comming soon',
|
|
||||||
group: 'Cloud Provider'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Tencent Cloud',
|
|
||||||
locale: false,
|
|
||||||
disabled: true,
|
|
||||||
value: ProviderValueMap.TencentCloud,
|
|
||||||
key: ProviderValueMap.TencentCloud,
|
|
||||||
icon: icons.TencentCloud,
|
|
||||||
description: 'Comming soon',
|
|
||||||
group: 'Cloud Provider'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
export const credentialActionList = [
|
export const credentialActionList = [
|
||||||
{
|
{
|
||||||
key: 'edit',
|
key: 'edit',
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default [
|
|||||||
value: ProviderValueMap.Docker,
|
value: ProviderValueMap.Docker,
|
||||||
key: ProviderValueMap.Docker,
|
key: ProviderValueMap.Docker,
|
||||||
icon: React.cloneElement(icons.DockerOutlined, {
|
icon: React.cloneElement(icons.DockerOutlined, {
|
||||||
style: { color: 'var(--ant-color-primary)' }
|
style: { color: 'var(--ant-blue-6)' }
|
||||||
}),
|
}),
|
||||||
group: 'clusters.create.provider.self'
|
group: 'clusters.create.provider.self'
|
||||||
},
|
},
|
||||||
@@ -19,7 +19,7 @@ export default [
|
|||||||
value: ProviderValueMap.Kubernetes,
|
value: ProviderValueMap.Kubernetes,
|
||||||
key: ProviderValueMap.Kubernetes,
|
key: ProviderValueMap.Kubernetes,
|
||||||
icon: React.cloneElement(icons.KubernetesFilled, {
|
icon: React.cloneElement(icons.KubernetesFilled, {
|
||||||
style: { color: 'var(--ant-color-primary)' }
|
style: { color: 'var(--ant-blue-6)' }
|
||||||
}),
|
}),
|
||||||
group: 'clusters.create.provider.self'
|
group: 'clusters.create.provider.self'
|
||||||
},
|
},
|
||||||
@@ -30,13 +30,13 @@ export default [
|
|||||||
key: ProviderValueMap.DigitalOcean,
|
key: ProviderValueMap.DigitalOcean,
|
||||||
icon: React.cloneElement(icons.DigitalOcean, {
|
icon: React.cloneElement(icons.DigitalOcean, {
|
||||||
style: {
|
style: {
|
||||||
color: 'var(--ant-color-primary)'
|
color: 'var(--ant-blue-6)'
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
group: 'clusters.create.provider.cloud'
|
group: 'clusters.create.provider.cloud'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Ali Cloud',
|
label: 'Alibaba Cloud',
|
||||||
locale: false,
|
locale: false,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
value: ProviderValueMap.AliCloud,
|
value: ProviderValueMap.AliCloud,
|
||||||
@@ -54,5 +54,15 @@ export default [
|
|||||||
icon: icons.TencentCloud,
|
icon: icons.TencentCloud,
|
||||||
description: 'Coming soon',
|
description: 'Coming soon',
|
||||||
group: 'clusters.create.provider.cloud'
|
group: 'clusters.create.provider.cloud'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'AWS',
|
||||||
|
locale: false,
|
||||||
|
disabled: true,
|
||||||
|
value: ProviderValueMap.AWS,
|
||||||
|
key: ProviderValueMap.AWS,
|
||||||
|
icon: icons.AWS,
|
||||||
|
description: 'Comming soon',
|
||||||
|
group: 'clusters.create.provider.cloud'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -31,7 +31,12 @@ const addActions = [
|
|||||||
locale: false,
|
locale: false,
|
||||||
key: ProviderValueMap.DigitalOcean,
|
key: ProviderValueMap.DigitalOcean,
|
||||||
value: ProviderValueMap.DigitalOcean,
|
value: ProviderValueMap.DigitalOcean,
|
||||||
icon: <IconFont type="icon-digitalocean" />
|
icon: (
|
||||||
|
<IconFont
|
||||||
|
type="icon-digitalocean"
|
||||||
|
style={{ color: 'var(--ant-blue-6)' }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -59,29 +59,6 @@ const Catalog: React.FC = () => {
|
|||||||
|
|
||||||
const categoryOptions = [...modelCategories.filter((item) => item.value)];
|
const categoryOptions = [...modelCategories.filter((item) => item.value)];
|
||||||
|
|
||||||
const filterData = useCallback(
|
|
||||||
(data: { search: string; categories: string }) => {
|
|
||||||
const { search, categories } = data;
|
|
||||||
const dataList = cacheData.current.filter((item) => {
|
|
||||||
if (search && categories) {
|
|
||||||
return (
|
|
||||||
_.toLower(item.name).includes(search) &&
|
|
||||||
item.categories.includes(categories)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (search) {
|
|
||||||
return _.toLower(item.name).includes(_.toLower(search));
|
|
||||||
}
|
|
||||||
if (categories) {
|
|
||||||
return item.categories.includes(categories);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
return dataList;
|
|
||||||
},
|
|
||||||
[cacheData.current]
|
|
||||||
);
|
|
||||||
|
|
||||||
const fetchData = useCallback(
|
const fetchData = useCallback(
|
||||||
async (query?: any) => {
|
async (query?: any) => {
|
||||||
const searchQuery = {
|
const searchQuery = {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import IconFont from '@/components/icon-font';
|
import IconFont from '@/components/icon-font';
|
||||||
import hotkeys from '@/config/hotkeys';
|
import hotkeys from '@/config/hotkeys';
|
||||||
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Input } from 'antd';
|
import { Input } from 'antd';
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
@@ -61,6 +62,12 @@ const SearchInput: React.FC<{
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
allowClear
|
allowClear
|
||||||
|
suffix={
|
||||||
|
<SearchOutlined
|
||||||
|
className="font-size-16"
|
||||||
|
style={{ color: 'var(--ant-color-text-placeholder)' }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
prefix={
|
prefix={
|
||||||
<IconFont
|
<IconFont
|
||||||
className="font-size-16"
|
className="font-size-16"
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ interface SearchInputProps {
|
|||||||
modelSource: string;
|
modelSource: string;
|
||||||
isDownload?: boolean;
|
isDownload?: boolean;
|
||||||
gpuOptions?: any[];
|
gpuOptions?: any[];
|
||||||
clusterId: number;
|
clusterId?: number;
|
||||||
setLoadingModel?: (flag: boolean) => void;
|
setLoadingModel?: (flag: boolean) => void;
|
||||||
onSourceChange?: (source: string) => void;
|
onSourceChange?: (source: string) => void;
|
||||||
onSelectModel: (model: any, manul?: boolean) => void;
|
onSelectModel: (model: any, manul?: boolean) => void;
|
||||||
@@ -547,7 +547,7 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
options={filterOptions}
|
options={filterOptions}
|
||||||
size="middle"
|
size="middle"
|
||||||
placeholder={intl.formatMessage({ id: 'common.input.type' })}
|
placeholder={intl.formatMessage({ id: 'common.input.type' })}
|
||||||
style={{ width: 150 }}
|
style={{ width: 120 }}
|
||||||
></BaseSelect>
|
></BaseSelect>
|
||||||
</span>
|
</span>
|
||||||
<PaginationMain
|
<PaginationMain
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { ProviderValueMap } from '@/pages/cluster-management/config';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
import ColumnWrapper from '../../_components/column-wrapper';
|
import ColumnWrapper from '../../_components/column-wrapper';
|
||||||
import CompatibilityAlert from '../components/compatible-alert';
|
import CompatibilityAlert from '../components/compatible-alert';
|
||||||
import ModelCard from '../components/model-card';
|
import ModelCard from '../components/model-card';
|
||||||
@@ -25,6 +26,18 @@ type AddModalProps = {
|
|||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ColWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
max-width: 33.33%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const FormWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
maxwidth: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
const DownloadModel: React.FC<AddModalProps> = (props) => {
|
const DownloadModel: React.FC<AddModalProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
@@ -155,31 +168,17 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
|
|||||||
<div style={{ display: 'flex', height: '100%' }}>
|
<div style={{ display: 'flex', height: '100%' }}>
|
||||||
{SEARCH_SOURCE.includes(props.source) && (
|
{SEARCH_SOURCE.includes(props.source) && (
|
||||||
<>
|
<>
|
||||||
<div
|
<ColWrapper>
|
||||||
style={{
|
<SearchModel
|
||||||
display: 'flex',
|
hasLinuxWorker={hasLinuxWorker}
|
||||||
flex: 1,
|
modelSource={props.source}
|
||||||
maxWidth: '33.33%'
|
onSelectModel={handleOnSelectModel}
|
||||||
}}
|
isDownload={true}
|
||||||
>
|
></SearchModel>
|
||||||
<ColumnWrapper>
|
|
||||||
<SearchModel
|
|
||||||
hasLinuxWorker={hasLinuxWorker}
|
|
||||||
modelSource={props.source}
|
|
||||||
onSelectModel={handleOnSelectModel}
|
|
||||||
isDownload={true}
|
|
||||||
></SearchModel>
|
|
||||||
</ColumnWrapper>
|
|
||||||
<Separator></Separator>
|
<Separator></Separator>
|
||||||
</div>
|
</ColWrapper>
|
||||||
<div
|
<ColWrapper>
|
||||||
style={{
|
<ColumnWrapper styles={{ container: { paddingTop: 0 } }}>
|
||||||
display: 'flex',
|
|
||||||
flex: 1,
|
|
||||||
maxWidth: '33.33%'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ColumnWrapper>
|
|
||||||
<ModelCard
|
<ModelCard
|
||||||
selectedModel={selectedModel}
|
selectedModel={selectedModel}
|
||||||
onCollapse={setCollapsed}
|
onCollapse={setCollapsed}
|
||||||
@@ -189,12 +188,15 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
|
|||||||
></ModelCard>
|
></ModelCard>
|
||||||
</ColumnWrapper>
|
</ColumnWrapper>
|
||||||
<Separator></Separator>
|
<Separator></Separator>
|
||||||
</div>
|
</ColWrapper>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div style={{ display: 'flex', flex: 1, maxWidth: '100%' }}>
|
<FormWrapper>
|
||||||
<ColumnWrapper
|
<ColumnWrapper
|
||||||
paddingBottom={50}
|
paddingBottom={50}
|
||||||
|
styles={{
|
||||||
|
container: { paddingTop: 0 }
|
||||||
|
}}
|
||||||
footer={
|
footer={
|
||||||
<>
|
<>
|
||||||
<CompatibilityAlert
|
<CompatibilityAlert
|
||||||
@@ -238,7 +240,7 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
|
|||||||
></TargetForm>
|
></TargetForm>
|
||||||
</>
|
</>
|
||||||
</ColumnWrapper>
|
</ColumnWrapper>
|
||||||
</div>
|
</FormWrapper>
|
||||||
</div>
|
</div>
|
||||||
</GSDrawer>
|
</GSDrawer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import SealInput from '@/components/seal-form/seal-input';
|
|||||||
import SealSelect from '@/components/seal-form/seal-select';
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
import TooltipList from '@/components/tooltip-list';
|
import TooltipList from '@/components/tooltip-list';
|
||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
|
import useAppUtils from '@/hooks/use-app-utils';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form, Typography } from 'antd';
|
import { Form, Typography } from 'antd';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
@@ -19,6 +20,7 @@ import { FormData } from '../config/types';
|
|||||||
|
|
||||||
const BackendFields: React.FC = () => {
|
const BackendFields: React.FC = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const { getRuleMessage } = useAppUtils();
|
||||||
const form = Form.useFormInstance();
|
const form = Form.useFormInstance();
|
||||||
const {
|
const {
|
||||||
isGGUF,
|
isGGUF,
|
||||||
@@ -51,7 +53,15 @@ const BackendFields: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form.Item name="backend" rules={[{ required: true }]}>
|
<Form.Item
|
||||||
|
name="backend"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: getRuleMessage('select', 'models.form.backend')
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SealSelect
|
<SealSelect
|
||||||
required
|
required
|
||||||
onChange={onBackendChange}
|
onChange={onBackendChange}
|
||||||
@@ -109,7 +119,15 @@ const BackendFields: React.FC = () => {
|
|||||||
)}
|
)}
|
||||||
{backend === backendOptionsMap.custom && (
|
{backend === backendOptionsMap.custom && (
|
||||||
<>
|
<>
|
||||||
<Form.Item<FormData> name="image_name" rules={[{ required: true }]}>
|
<Form.Item<FormData>
|
||||||
|
name="image_name"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: getRuleMessage('input', 'backend.imageName')
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SealInput.Input
|
<SealInput.Input
|
||||||
required
|
required
|
||||||
allowClear
|
allowClear
|
||||||
@@ -117,7 +135,15 @@ const BackendFields: React.FC = () => {
|
|||||||
label={intl.formatMessage({ id: 'backend.imageName' })}
|
label={intl.formatMessage({ id: 'backend.imageName' })}
|
||||||
></SealInput.Input>
|
></SealInput.Input>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<FormData> name="run_command" rules={[{ required: true }]}>
|
<Form.Item<FormData>
|
||||||
|
name="run_command"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: getRuleMessage('input', 'backend.runCommand')
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SealInput.TextArea
|
<SealInput.TextArea
|
||||||
required
|
required
|
||||||
scaleSize={true}
|
scaleSize={true}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [activeKey, setActiveKey] = React.useState<string[]>([]);
|
const [activeKey, setActiveKey] = React.useState<string[]>([]);
|
||||||
|
const scheduleType = Form.useWatch('scheduleType', form);
|
||||||
|
|
||||||
const handleSumit = () => {
|
const handleSumit = () => {
|
||||||
form.submit();
|
form.submit();
|
||||||
@@ -112,6 +113,11 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
const handleClusterChange = (value: number) => {
|
const handleClusterChange = (value: number) => {
|
||||||
getGPUOptionList({ clusterId: value });
|
getGPUOptionList({ clusterId: value });
|
||||||
getBackendOptions({ cluster_id: value });
|
getBackendOptions({ cluster_id: value });
|
||||||
|
if (scheduleType === ScheduleValueMap.Manual) {
|
||||||
|
form.setFieldsValue({
|
||||||
|
gpu_selector: { gpu_ids: [] }
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnValuesChange = async (changedValues: any, allValues: any) => {
|
const handleOnValuesChange = async (changedValues: any, allValues: any) => {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import SealCascader from '@/components/seal-form/seal-cascader';
|
import SealCascader from '@/components/seal-form/seal-cascader';
|
||||||
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
import SealSelect from '@/components/seal-form/seal-select';
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
import TooltipList from '@/components/tooltip-list';
|
import TooltipList from '@/components/tooltip-list';
|
||||||
import useAppUtils from '@/hooks/use-app-utils';
|
import useAppUtils from '@/hooks/use-app-utils';
|
||||||
@@ -9,6 +10,7 @@ import GPUCard from '../components/gpu-card';
|
|||||||
import { scheduleList, ScheduleValueMap } from '../config';
|
import { scheduleList, ScheduleValueMap } from '../config';
|
||||||
import { backendOptionsMap } from '../config/backend-parameters';
|
import { backendOptionsMap } from '../config/backend-parameters';
|
||||||
import { useCatalogFormContext, useFormContext } from '../config/form-context';
|
import { useCatalogFormContext, useFormContext } from '../config/form-context';
|
||||||
|
import { FormData } from '../config/types';
|
||||||
|
|
||||||
const scheduleTypeTips = [
|
const scheduleTypeTips = [
|
||||||
{
|
{
|
||||||
@@ -54,6 +56,28 @@ const Performance: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Form.Item<FormData>
|
||||||
|
name="replicas"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: getRuleMessage('input', 'models.form.replicas')
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<SealInput.Number
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'models.form.replicas'
|
||||||
|
})}
|
||||||
|
required
|
||||||
|
description={intl.formatMessage(
|
||||||
|
{ id: 'models.form.replicas.tips' },
|
||||||
|
{ api: `${window.location.origin}/v1` }
|
||||||
|
)}
|
||||||
|
min={0}
|
||||||
|
></SealInput.Number>
|
||||||
|
</Form.Item>
|
||||||
<Form.Item name="scheduleType">
|
<Form.Item name="scheduleType">
|
||||||
<SealSelect
|
<SealSelect
|
||||||
onChange={handleScheduleTypeChange}
|
onChange={handleScheduleTypeChange}
|
||||||
@@ -73,24 +97,7 @@ const Performance: React.FC = () => {
|
|||||||
<Form.Item name={['gpu_selector', 'gpu_count']}>
|
<Form.Item name={['gpu_selector', 'gpu_count']}>
|
||||||
<SealSelect
|
<SealSelect
|
||||||
label={intl.formatMessage({ id: 'models.form.gpuCount' })}
|
label={intl.formatMessage({ id: 'models.form.gpuCount' })}
|
||||||
options={[
|
options={[]}
|
||||||
{
|
|
||||||
label: 'Auto',
|
|
||||||
value: 'auto'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '1',
|
|
||||||
value: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '2',
|
|
||||||
value: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '4',
|
|
||||||
value: 4
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
></SealSelect>
|
></SealSelect>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@padding: 16px 24px;
|
@padding: 16px 0px;
|
||||||
|
|
||||||
.h3 {
|
.h3 {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ const UserModels: React.FC = () => {
|
|||||||
} = useTableFetch<any>({
|
} = useTableFetch<any>({
|
||||||
fetchAPI: queryMyModels,
|
fetchAPI: queryMyModels,
|
||||||
API: MY_MODELS_API,
|
API: MY_MODELS_API,
|
||||||
watch: false
|
watch: false,
|
||||||
|
isInfiniteScroll: true
|
||||||
});
|
});
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,3 @@
|
|||||||
.ant-pro-footer-bar {
|
|
||||||
padding-block: 20px;
|
|
||||||
padding-bottom: 30px;
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
.ant-pro-footer-bar-right {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.messageInput {
|
.messageInput {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ export const addWorkerGuide: Record<string, any> = {
|
|||||||
--restart=unless-stopped \\
|
--restart=unless-stopped \\
|
||||||
--privileged \\
|
--privileged \\
|
||||||
--net=host \\
|
--net=host \\
|
||||||
-v gpustack-data:/var/lib/gpustack \\
|
-v /var/run/docker.sock:/var/run/docker.sock \\
|
||||||
|
-v /var/lib/gpustack:/var/lib/gpustack \\
|
||||||
${params.image} \\
|
${params.image} \\
|
||||||
--server-url ${params.server} \\
|
--server-url ${params.server} \\
|
||||||
--registration-token ${params.token} \\
|
--registration-token ${params.token} \\
|
||||||
|
|||||||
Reference in New Issue
Block a user