chore: get started for add cluster
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import AlertBlockInfo from '@/components/alert-info/block';
|
||||
import TooltipList from '@/components/tooltip-list';
|
||||
import { PageAction } from '@/config';
|
||||
import { PageActionType } from '@/config/types';
|
||||
import TransferInner from '@/pages/_components/transfer';
|
||||
@@ -29,7 +30,34 @@ import { AccessControlFormData, ListItem } from '../../config/types';
|
||||
|
||||
type TransferKey = string | number | bigint;
|
||||
|
||||
const accessScopeTips = [
|
||||
{
|
||||
title: {
|
||||
text: 'models.accessSettings.authed',
|
||||
locale: true
|
||||
},
|
||||
tips: 'models.accessSettings.authed.tips'
|
||||
},
|
||||
{
|
||||
title: {
|
||||
text: 'models.accessSettings.allowedUsers',
|
||||
locale: true
|
||||
},
|
||||
tips: 'models.accessSettings.allowedUsers.tips'
|
||||
},
|
||||
{
|
||||
title: {
|
||||
text: 'models.accessSettings.public',
|
||||
locale: true
|
||||
},
|
||||
tips: 'models.accessSettings.public.desc'
|
||||
}
|
||||
];
|
||||
|
||||
const Label = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-weight: 500;
|
||||
margin-block: 8px 12px;
|
||||
font-size: 14px;
|
||||
@@ -263,7 +291,13 @@ const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
|
||||
access_policy: action === PageAction.CREATE ? 'authed' : undefined
|
||||
}}
|
||||
>
|
||||
<Label>{intl.formatMessage({ id: 'models.table.accessScope' })}</Label>
|
||||
<Label>
|
||||
{intl.formatMessage({ id: 'models.table.accessScope' })}
|
||||
<Tooltip title={<TooltipList list={accessScopeTips}></TooltipList>}>
|
||||
<QuestionCircleOutlined />
|
||||
</Tooltip>
|
||||
</Label>
|
||||
|
||||
<Form.Item<AccessControlFormData> name="access_policy" noStyle>
|
||||
<Radio.Group
|
||||
onChange={handleOnPolicyChange}
|
||||
@@ -307,7 +341,7 @@ const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
|
||||
id: 'models.table.userSelection.tips'
|
||||
})}
|
||||
>
|
||||
<QuestionCircleOutlined style={{ marginLeft: 4 }} />
|
||||
<QuestionCircleOutlined />
|
||||
</Tooltip>
|
||||
</Label>
|
||||
<Form.Item<AccessControlFormData> name="users">
|
||||
|
||||
@@ -110,7 +110,6 @@ const AddModal: FC<AddModalProps> = (props) => {
|
||||
|
||||
const { checkOnlyAscendNPU } = useCheckBackend();
|
||||
const {
|
||||
handleShowCompatibleAlert,
|
||||
setWarningStatus,
|
||||
handleBackendChangeBefore,
|
||||
cancelEvaluate,
|
||||
|
||||
@@ -429,6 +429,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
data: row
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleSelect = useMemoizedFn(async (val: any, row: ListItem) => {
|
||||
try {
|
||||
if (val === 'edit') {
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import { clusterSessionAtom } from '@/atoms/clusters';
|
||||
import SealInput from '@/components/seal-form/seal-input';
|
||||
import SealSelect from '@/components/seal-form/seal-select';
|
||||
import { modelNameReg } from '@/config';
|
||||
import { modelNameReg, PageAction } from '@/config';
|
||||
import { GPUSTACK_API_BASE_URL } from '@/config/settings';
|
||||
import useAppUtils from '@/hooks/use-app-utils';
|
||||
import {
|
||||
ClusterStatusLabelMap,
|
||||
ClusterStatusValueMap
|
||||
} from '@/pages/cluster-management/config';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Link, useIntl } from '@umijs/max';
|
||||
import { Form } from 'antd';
|
||||
import { useAtom } from 'jotai';
|
||||
import { useMemo } from 'react';
|
||||
import { sourceOptions } from '../config';
|
||||
import { FormData } from '../config/types';
|
||||
@@ -28,6 +30,26 @@ interface BasicFormProps {
|
||||
onSourceChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
const NotFoundCredentialContent: React.FC = () => {
|
||||
const [, setFromClusterCreation] = useAtom(clusterSessionAtom);
|
||||
const intl = useIntl();
|
||||
const handleOnClick = () => {
|
||||
setFromClusterCreation({
|
||||
firstAddWorker: false,
|
||||
firstAddCluster: true
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Link
|
||||
to={`/cluster-management/clusters/create?action=${PageAction.CREATE}`}
|
||||
onClick={handleOnClick}
|
||||
>
|
||||
{intl.formatMessage({ id: 'noresult.resources.gotocluster' })}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const BasicForm: React.FC<BasicFormProps> = (props) => {
|
||||
const {
|
||||
fields = [],
|
||||
@@ -118,6 +140,9 @@ const BasicForm: React.FC<BasicFormProps> = (props) => {
|
||||
>
|
||||
{
|
||||
<SealSelect
|
||||
notFoundContent={
|
||||
<NotFoundCredentialContent></NotFoundCredentialContent>
|
||||
}
|
||||
onChange={handleClusterChange}
|
||||
label={intl.formatMessage({ id: 'clusters.title' })}
|
||||
options={clusterOptions}
|
||||
|
||||
@@ -173,6 +173,16 @@ export const useCheckCompatibility = () => {
|
||||
|
||||
const handleEvaluate = async (data: any) => {
|
||||
try {
|
||||
// when no cluster selected, show warning and prompt user to add cluster first
|
||||
if (!data.cluster_id) {
|
||||
setWarningStatus({
|
||||
show: true,
|
||||
title: '',
|
||||
type: 'warning',
|
||||
message: intl.formatMessage({ id: 'noresult.resources.cluster' })
|
||||
});
|
||||
return;
|
||||
}
|
||||
checkTokenRef.current?.cancel();
|
||||
checkTokenRef.current = createAxiosToken();
|
||||
setWarningStatus({
|
||||
@@ -407,6 +417,7 @@ export const useCheckCompatibility = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// when custom backend, and no run_command or image_name, skip evaluate
|
||||
if (
|
||||
backendOptionsMap.custom === allValues.backend &&
|
||||
(!allValues.run_command || !allValues.image_name)
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
import { clusterSessionAtom } from '@/atoms/clusters';
|
||||
import IconFont from '@/components/icon-font';
|
||||
import { PageAction } from '@/config';
|
||||
import NoResult from '@/pages/_components/no-result';
|
||||
import { useIntl, useNavigate } from '@umijs/max';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { Button } from 'antd';
|
||||
import { useAtom } from 'jotai';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
const useNoResourceResult = (props: {
|
||||
iconType: string;
|
||||
loading?: boolean;
|
||||
loadend?: boolean;
|
||||
dataSource?: any[];
|
||||
queryParams?: Record<string, any>;
|
||||
title: React.ReactNode;
|
||||
noClusters?: boolean;
|
||||
noWorkers?: boolean;
|
||||
subTitle?: React.ReactNode;
|
||||
defaultContent?: {
|
||||
subTitle: string;
|
||||
noFoundText: string;
|
||||
buttonText: string;
|
||||
onClick: () => void;
|
||||
};
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const navigate = useNavigate();
|
||||
const {
|
||||
noClusters,
|
||||
noWorkers,
|
||||
defaultContent,
|
||||
loading,
|
||||
loadend,
|
||||
dataSource,
|
||||
queryParams,
|
||||
iconType,
|
||||
title,
|
||||
subTitle
|
||||
} = props;
|
||||
const [, setClusterSession] = useAtom(clusterSessionAtom);
|
||||
|
||||
const handleClick = useMemoizedFn(() => {
|
||||
if (noClusters) {
|
||||
setClusterSession({
|
||||
firstAddWorker: false,
|
||||
firstAddCluster: true
|
||||
});
|
||||
|
||||
navigate(
|
||||
`/cluster-management/clusters/create?action=${PageAction.CREATE}`
|
||||
);
|
||||
}
|
||||
|
||||
if (noWorkers) {
|
||||
setClusterSession({
|
||||
firstAddWorker: true,
|
||||
firstAddCluster: false
|
||||
});
|
||||
navigate(`/cluster-management/clusters/list`);
|
||||
}
|
||||
});
|
||||
|
||||
const statusContent = useMemo(() => {
|
||||
if (noClusters) {
|
||||
return {
|
||||
subTitle:
|
||||
subTitle || intl.formatMessage({ id: 'noresult.resources.cluster' }),
|
||||
noFoundText: defaultContent?.noFoundText || '',
|
||||
buttonText: intl.formatMessage({
|
||||
id: 'noresult.resources.gotocluster'
|
||||
}),
|
||||
onClick: handleClick
|
||||
};
|
||||
}
|
||||
|
||||
if (noWorkers) {
|
||||
return {
|
||||
subTitle:
|
||||
subTitle || intl.formatMessage({ id: 'noresult.resources.worker' }),
|
||||
noFoundText: defaultContent?.noFoundText || '',
|
||||
buttonText: intl.formatMessage({ id: 'noresult.resources.gotoworker' }),
|
||||
onClick: handleClick
|
||||
};
|
||||
}
|
||||
return {
|
||||
...defaultContent
|
||||
};
|
||||
}, [noClusters, noWorkers, intl]);
|
||||
|
||||
const noResourceResult = (
|
||||
<NoResult
|
||||
loading={loading}
|
||||
loadend={loadend}
|
||||
dataSource={dataSource}
|
||||
image={<IconFont type={iconType} />}
|
||||
filters={queryParams}
|
||||
noFoundText={statusContent.noFoundText}
|
||||
title={title}
|
||||
subTitle={statusContent.subTitle}
|
||||
>
|
||||
<Button type="primary" iconPosition="end" onClick={statusContent.onClick}>
|
||||
{statusContent.buttonText}
|
||||
</Button>
|
||||
</NoResult>
|
||||
);
|
||||
return {
|
||||
noResourceResult
|
||||
};
|
||||
};
|
||||
|
||||
export default useNoResourceResult;
|
||||
Reference in New Issue
Block a user