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