fix: anti double submit in form
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
import { useMemoizedFn } from 'ahooks';
|
||||||
|
import { useRef, useState } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centralizes the anti-double-submit + anti-deadlock logic shared by the
|
||||||
|
* "add/edit" modals.
|
||||||
|
*
|
||||||
|
* The lock has to straddle antd's async field validation, whose result comes
|
||||||
|
* back through two separate callbacks (`onFinish` / `onFinishFailed`). So the
|
||||||
|
* three wiring points below are intentional and map 1:1 to those anchors:
|
||||||
|
*
|
||||||
|
* - `guard` wrap the submit trigger (button / ModalFooter onOk). Blocks
|
||||||
|
* re-entry while a submit is already in flight, then fires submit.
|
||||||
|
* - `run` wrap the `onFinish` handler. Holds the lock + loading until the
|
||||||
|
* `onOk` request settles (success or error).
|
||||||
|
* - `release` pass as the form's `onFinishFailed`. Releases the lock when
|
||||||
|
* validation fails, otherwise the button would dead-lock.
|
||||||
|
*/
|
||||||
|
export default function useSubmitLock() {
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
const lockRef = useRef<boolean>(false);
|
||||||
|
|
||||||
|
const release = useMemoizedFn(() => {
|
||||||
|
setLoading(false);
|
||||||
|
lockRef.current = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
const guard = useMemoizedFn((submit: () => void) => {
|
||||||
|
if (lockRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lockRef.current = true;
|
||||||
|
submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
const run = useMemoizedFn(async (task: () => void | Promise<void>) => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
await task();
|
||||||
|
} finally {
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { loading, guard, run, release };
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||||
import {
|
import {
|
||||||
AlertBlockInfo,
|
AlertBlockInfo,
|
||||||
Input as CInput,
|
Input as CInput,
|
||||||
@@ -45,7 +46,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [showKey, setShowKey] = useState(false);
|
const [showKey, setShowKey] = useState(false);
|
||||||
const [apikeyValue, setAPIKeyValue] = useState('');
|
const [apikeyValue, setAPIKeyValue] = useState('');
|
||||||
const [loading, setLoading] = useState(false);
|
const { loading, guard, run, release } = useSubmitLock();
|
||||||
const [isChanged, setIsChanged] = useState(false);
|
const [isChanged, setIsChanged] = useState(false);
|
||||||
const cacheFormRef = useRef<{
|
const cacheFormRef = useRef<{
|
||||||
allowed_type: string;
|
allowed_type: string;
|
||||||
@@ -116,31 +117,31 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleOnOk = async (formdata: FormData) => {
|
const handleOnOk = async (formdata: FormData) => {
|
||||||
try {
|
await run(async () => {
|
||||||
setLoading(true);
|
try {
|
||||||
const data = {
|
const data = {
|
||||||
..._.omit(formdata, ['allowed_type']),
|
..._.omit(formdata, ['allowed_type']),
|
||||||
allowed_model_names:
|
allowed_model_names:
|
||||||
formdata.allowed_type === 'all' ||
|
formdata.allowed_type === 'all' ||
|
||||||
!formdata.scope?.includes('inference')
|
!formdata.scope?.includes('inference')
|
||||||
? []
|
? []
|
||||||
: formdata.allowed_model_names || []
|
: formdata.allowed_model_names || []
|
||||||
};
|
};
|
||||||
if (action === PageAction.CREATE) {
|
if (action === PageAction.CREATE) {
|
||||||
await createAPIKey(data);
|
await createAPIKey(data);
|
||||||
} else if (action === PageAction.EDIT && currentData?.id) {
|
} else if (action === PageAction.EDIT && currentData?.id) {
|
||||||
await updateAPIKey({
|
await updateAPIKey({
|
||||||
..._.omit(data, ['expires_in'])
|
..._.omit(data, ['expires_in'])
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// handled in interceptor
|
||||||
}
|
}
|
||||||
setLoading(false);
|
});
|
||||||
} catch (error) {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSumit = () => {
|
const handleSumit = () => {
|
||||||
form.submit();
|
guard(() => form.submit());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDone = () => {
|
const handleDone = () => {
|
||||||
@@ -278,6 +279,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
name="addAPIKey"
|
name="addAPIKey"
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={handleOnOk}
|
onFinish={handleOnOk}
|
||||||
|
onFinishFailed={release}
|
||||||
preserve={false}
|
preserve={false}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
allowed_type: 'all',
|
allowed_type: 'all',
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||||
import {
|
import {
|
||||||
AlertBlockInfo,
|
AlertBlockInfo,
|
||||||
GSDrawer,
|
GSDrawer,
|
||||||
@@ -63,6 +64,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
const [yamlContent, setYamlContent] = useState<string>('');
|
const [yamlContent, setYamlContent] = useState<string>('');
|
||||||
const [formContent, setFormContent] = useState<FormData>({} as FormData);
|
const [formContent, setFormContent] = useState<FormData>({} as FormData);
|
||||||
const alertRef = useRef<HTMLDivElement>(null);
|
const alertRef = useRef<HTMLDivElement>(null);
|
||||||
|
const { loading, guard, run, release } = useSubmitLock();
|
||||||
|
|
||||||
const showVersionCustomSuffix =
|
const showVersionCustomSuffix =
|
||||||
currentData?.backend_source === BackendSourceValueMap.BUILTIN ||
|
currentData?.backend_source === BackendSourceValueMap.BUILTIN ||
|
||||||
@@ -92,17 +94,22 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onOk = () => {
|
const onOk = () => {
|
||||||
if (activeKey === 'yaml') {
|
guard(() => {
|
||||||
const content = editorRef.current?.getContent();
|
if (activeKey === 'yaml') {
|
||||||
if (content) {
|
const content = editorRef.current?.getContent();
|
||||||
onSubmitYaml({ content: content });
|
if (!content) {
|
||||||
|
// nothing to submit — drop the lock so the button stays usable
|
||||||
|
release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
run(() => onSubmitYaml({ content: content }));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
formRef.current?.submit();
|
formRef.current?.submit();
|
||||||
}
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFinish = (values: FormData) => {
|
const onFinish = async (values: FormData) => {
|
||||||
const versionConfigs = values.version_configs?.reduce(
|
const versionConfigs = values.version_configs?.reduce(
|
||||||
(acc: Record<string, any>, curr) => {
|
(acc: Record<string, any>, curr) => {
|
||||||
if (curr.version_no) {
|
if (curr.version_no) {
|
||||||
@@ -117,16 +124,18 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
|
|
||||||
const defaultVersion = values.version_configs?.find((v) => v.is_default);
|
const defaultVersion = values.version_configs?.find((v) => v.is_default);
|
||||||
|
|
||||||
onSubmit({
|
await run(() =>
|
||||||
...values,
|
onSubmit({
|
||||||
parameter_format:
|
...values,
|
||||||
values.parameter_format === 'auto' || !values.parameter_format
|
parameter_format:
|
||||||
? null
|
values.parameter_format === 'auto' || !values.parameter_format
|
||||||
: values.parameter_format,
|
? null
|
||||||
default_version: defaultVersion?.version_no || '',
|
: values.parameter_format,
|
||||||
// @ts-ignore
|
default_version: defaultVersion?.version_no || '',
|
||||||
version_configs: versionConfigs
|
// @ts-ignore
|
||||||
});
|
version_configs: versionConfigs
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -279,6 +288,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
<ModalFooter
|
<ModalFooter
|
||||||
onCancel={onClose}
|
onCancel={onClose}
|
||||||
onOk={onOk}
|
onOk={onOk}
|
||||||
|
loading={loading}
|
||||||
style={ModalFooterStyle}
|
style={ModalFooterStyle}
|
||||||
></ModalFooter>
|
></ModalFooter>
|
||||||
</>
|
</>
|
||||||
@@ -295,6 +305,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
children: (
|
children: (
|
||||||
<BackendForm
|
<BackendForm
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
|
onFinishFailed={release}
|
||||||
action={action}
|
action={action}
|
||||||
currentData={formContent as ListItem}
|
currentData={formContent as ListItem}
|
||||||
ref={formRef}
|
ref={formRef}
|
||||||
|
|||||||
@@ -13,10 +13,11 @@ type AddModalProps = {
|
|||||||
action: PageActionType;
|
action: PageActionType;
|
||||||
currentData?: ListItem;
|
currentData?: ListItem;
|
||||||
onFinish: (values: FormData) => void;
|
onFinish: (values: FormData) => void;
|
||||||
|
onFinishFailed?: (errorInfo: any) => void;
|
||||||
ref?: any;
|
ref?: any;
|
||||||
};
|
};
|
||||||
const BackendForm: React.FC<AddModalProps> = forwardRef(
|
const BackendForm: React.FC<AddModalProps> = forwardRef(
|
||||||
({ action, currentData, onFinish }, ref) => {
|
({ action, currentData, onFinish, onFinishFailed }, ref) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [activeKey, setActiveKey] = React.useState<string[]>([]);
|
const [activeKey, setActiveKey] = React.useState<string[]>([]);
|
||||||
@@ -26,7 +27,7 @@ const BackendForm: React.FC<AddModalProps> = forwardRef(
|
|||||||
currentData?.backend_source === BackendSourceValueMap.BUILTIN ||
|
currentData?.backend_source === BackendSourceValueMap.BUILTIN ||
|
||||||
currentData?.backend_source === BackendSourceValueMap.COMMUNITY;
|
currentData?.backend_source === BackendSourceValueMap.COMMUNITY;
|
||||||
|
|
||||||
const onFinishFailed = (errorInfo: any) => {
|
const handleOnFinishFailed = (errorInfo: any) => {
|
||||||
const errorFields = errorInfo.errorFields || [];
|
const errorFields = errorInfo.errorFields || [];
|
||||||
if (errorFields.length > 0) {
|
if (errorFields.length > 0) {
|
||||||
const versionError = errorFields.find((field: any) =>
|
const versionError = errorFields.find((field: any) =>
|
||||||
@@ -38,6 +39,7 @@ const BackendForm: React.FC<AddModalProps> = forwardRef(
|
|||||||
setActiveKey([]);
|
setActiveKey([]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onFinishFailed?.(errorInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnFinish = (values: FormData) => {
|
const handleOnFinish = (values: FormData) => {
|
||||||
@@ -106,7 +108,7 @@ const BackendForm: React.FC<AddModalProps> = forwardRef(
|
|||||||
preserve={false}
|
preserve={false}
|
||||||
scrollToFirstError={true}
|
scrollToFirstError={true}
|
||||||
initialValues={_.omit(currentData, ['version_configs'])}
|
initialValues={_.omit(currentData, ['version_configs'])}
|
||||||
onFinishFailed={onFinishFailed}
|
onFinishFailed={handleOnFinishFailed}
|
||||||
>
|
>
|
||||||
<BasicForm></BasicForm>
|
<BasicForm></BasicForm>
|
||||||
<VersionsForm
|
<VersionsForm
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||||
import { FormDrawer } from '@gpustack/core-ui';
|
import { FormDrawer } from '@gpustack/core-ui';
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { FormData, BenchmarkListItem as ListItem } from '../config/types';
|
import { FormData, BenchmarkListItem as ListItem } from '../config/types';
|
||||||
@@ -22,21 +23,24 @@ const AddBenchmark: React.FC<AddModalProps> = ({
|
|||||||
open,
|
open,
|
||||||
currentData,
|
currentData,
|
||||||
clusterList,
|
clusterList,
|
||||||
profilesOptions,
|
profilesOptions = [],
|
||||||
datasetList,
|
datasetList = [],
|
||||||
onOk,
|
onOk,
|
||||||
onCancel
|
onCancel
|
||||||
}) => {
|
}) => {
|
||||||
const form = useRef<any>(null);
|
const form = useRef<any>(null);
|
||||||
|
const { loading, guard, run, release } = useSubmitLock();
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
form.current?.submit();
|
guard(() => form.current?.submit());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOk = async (data: FormData) => {
|
const handleOk = async (data: FormData) => {
|
||||||
onOk({
|
await run(() =>
|
||||||
...data
|
onOk({
|
||||||
});
|
...data
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -51,6 +55,7 @@ const AddBenchmark: React.FC<AddModalProps> = ({
|
|||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
width={600}
|
width={600}
|
||||||
|
loading={loading}
|
||||||
>
|
>
|
||||||
<BenchmarkForm
|
<BenchmarkForm
|
||||||
ref={form}
|
ref={form}
|
||||||
@@ -61,6 +66,7 @@ const AddBenchmark: React.FC<AddModalProps> = ({
|
|||||||
profilesOptions={profilesOptions}
|
profilesOptions={profilesOptions}
|
||||||
datasetList={datasetList}
|
datasetList={datasetList}
|
||||||
onFinish={handleOk}
|
onFinish={handleOk}
|
||||||
|
onFinishFailed={release}
|
||||||
/>
|
/>
|
||||||
</FormDrawer>
|
</FormDrawer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ interface ProviderFormProps {
|
|||||||
datasetList: Global.BaseOption<number | string>[];
|
datasetList: Global.BaseOption<number | string>[];
|
||||||
profilesOptions: Global.BaseOption<string>[];
|
profilesOptions: Global.BaseOption<string>[];
|
||||||
onFinish: (values: FormData) => Promise<void>;
|
onFinish: (values: FormData) => Promise<void>;
|
||||||
|
onFinishFailed?: (errorInfo: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TABKeysMap = {
|
const TABKeysMap = {
|
||||||
@@ -42,6 +43,7 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
action,
|
action,
|
||||||
currentData,
|
currentData,
|
||||||
onFinish,
|
onFinish,
|
||||||
|
onFinishFailed,
|
||||||
open,
|
open,
|
||||||
clusterList,
|
clusterList,
|
||||||
profilesOptions,
|
profilesOptions,
|
||||||
@@ -122,6 +124,7 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
|
onFinishFailed={onFinishFailed}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
dataset_input_tokens: null,
|
dataset_input_tokens: null,
|
||||||
dataset_output_tokens: null,
|
dataset_output_tokens: null,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||||
import { ExclamationCircleFilled } from '@ant-design/icons';
|
import { ExclamationCircleFilled } from '@ant-design/icons';
|
||||||
import { AlertBlockInfo, FormDrawer, ModalFooter } from '@gpustack/core-ui';
|
import { AlertBlockInfo, FormDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
@@ -39,20 +40,23 @@ const AddCluster: React.FC<AddModalProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const form = useRef<any>(null);
|
const form = useRef<any>(null);
|
||||||
|
const { loading, guard, run, release } = useSubmitLock();
|
||||||
// Whether the user has changed any k8s_options field. Lifted from ClusterForm
|
// Whether the user has changed any k8s_options field. Lifted from ClusterForm
|
||||||
// so the "re-run registration" notice can sit in the drawer footer, above the
|
// so the "re-run registration" notice can sit in the drawer footer, above the
|
||||||
// Save/Cancel buttons (mirrors the model edit interaction).
|
// Save/Cancel buttons (mirrors the model edit interaction).
|
||||||
const [k8sOptionsChanged, setK8sOptionsChanged] = useState<boolean>(false);
|
const [k8sOptionsChanged, setK8sOptionsChanged] = useState<boolean>(false);
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
form.current?.submit();
|
guard(() => form.current?.submit());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOk = async (data: FormData) => {
|
const handleOk = async (data: FormData) => {
|
||||||
onOk({
|
await run(() =>
|
||||||
...data,
|
onOk({
|
||||||
provider
|
...data,
|
||||||
});
|
provider
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -84,6 +88,7 @@ const AddCluster: React.FC<AddModalProps> = ({
|
|||||||
<ModalFooter
|
<ModalFooter
|
||||||
onOk={handleSubmit}
|
onOk={handleSubmit}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
loading={loading}
|
||||||
style={ModalFooterStyle}
|
style={ModalFooterStyle}
|
||||||
></ModalFooter>
|
></ModalFooter>
|
||||||
</>
|
</>
|
||||||
@@ -96,6 +101,7 @@ const AddCluster: React.FC<AddModalProps> = ({
|
|||||||
action={action}
|
action={action}
|
||||||
currentData={currentData}
|
currentData={currentData}
|
||||||
onFinish={handleOk}
|
onFinish={handleOk}
|
||||||
|
onFinishFailed={release}
|
||||||
onK8sOptionsChange={setK8sOptionsChanged}
|
onK8sOptionsChange={setK8sOptionsChanged}
|
||||||
/>
|
/>
|
||||||
</FormDrawer>
|
</FormDrawer>
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ type AddModalProps = {
|
|||||||
provider: ProviderType;
|
provider: ProviderType;
|
||||||
credentialList: Global.BaseOption<number>[];
|
credentialList: Global.BaseOption<number>[];
|
||||||
onFinish: (values: FormData) => void;
|
onFinish: (values: FormData) => void;
|
||||||
|
onFinishFailed?: (errorInfo: any) => void;
|
||||||
// Reports whether the user has changed any k8s_options field, so the parent
|
// Reports whether the user has changed any k8s_options field, so the parent
|
||||||
// can show the "re-run registration" notice in the footer.
|
// can show the "re-run registration" notice in the footer.
|
||||||
onK8sOptionsChange?: (changed: boolean) => void;
|
onK8sOptionsChange?: (changed: boolean) => void;
|
||||||
@@ -49,6 +50,7 @@ const ClusterForm: React.FC<AddModalProps> = forwardRef(
|
|||||||
currentData,
|
currentData,
|
||||||
credentialList,
|
credentialList,
|
||||||
onFinish,
|
onFinish,
|
||||||
|
onFinishFailed,
|
||||||
onK8sOptionsChange
|
onK8sOptionsChange
|
||||||
},
|
},
|
||||||
ref
|
ref
|
||||||
@@ -212,8 +214,9 @@ const ClusterForm: React.FC<AddModalProps> = forwardRef(
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const handleOnFinishFailed = () => {
|
const handleOnFinishFailed = (errorInfo: any) => {
|
||||||
setSubmitAttempted(true);
|
setSubmitAttempted(true);
|
||||||
|
onFinishFailed?.(errorInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||||
import { useQueryClusterList } from '@/pages/cluster-management/services/use-query-cluster-list';
|
import { useQueryClusterList } from '@/pages/cluster-management/services/use-query-cluster-list';
|
||||||
import Separator from '@/pages/llmodels/components/separator';
|
import Separator from '@/pages/llmodels/components/separator';
|
||||||
import { SearchOutlined } from '@ant-design/icons';
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
@@ -89,7 +90,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
const [templateId, setTemplateId] = useState<number | undefined>();
|
const [templateId, setTemplateId] = useState<number | undefined>();
|
||||||
const [instanceKeyword, setInstanceKeyword] = useState('');
|
const [instanceKeyword, setInstanceKeyword] = useState('');
|
||||||
const [templateKeyword, setTemplateKeyword] = useState('');
|
const [templateKeyword, setTemplateKeyword] = useState('');
|
||||||
const [loading, setLoading] = useState(false);
|
const { loading, guard, run, release } = useSubmitLock();
|
||||||
const initializedRef = useRef(false);
|
const initializedRef = useRef(false);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -385,7 +386,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
form.current?.submit();
|
guard(() => form.current?.submit());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -394,15 +395,12 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFinish = async (values: FormData) => {
|
const onFinish = async (values: FormData) => {
|
||||||
setLoading(true);
|
await run(async () => {
|
||||||
try {
|
|
||||||
await onOk({
|
await onOk({
|
||||||
...values
|
...values
|
||||||
});
|
});
|
||||||
console.log('submit form values', values);
|
console.log('submit form values', values);
|
||||||
} finally {
|
});
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleInstanceTypeChange = (item: InstanceTypeItem) => {
|
const handleInstanceTypeChange = (item: InstanceTypeItem) => {
|
||||||
@@ -576,6 +574,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
currentData={data}
|
currentData={data}
|
||||||
disabled={readonly}
|
disabled={readonly}
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
|
onFinishFailed={release}
|
||||||
onScopeChange={handleScopeChange}
|
onScopeChange={handleScopeChange}
|
||||||
open={open}
|
open={open}
|
||||||
instanceTypeList={ownedInstanceTypes}
|
instanceTypeList={ownedInstanceTypes}
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ interface InstanceFormProps {
|
|||||||
// tenant-scoped instance-type / template offerings.
|
// tenant-scoped instance-type / template offerings.
|
||||||
onScopeChange?: (orgId: number | null | undefined) => void;
|
onScopeChange?: (orgId: number | null | undefined) => void;
|
||||||
onFinish: (values: FormData) => Promise<void>;
|
onFinish: (values: FormData) => Promise<void>;
|
||||||
|
onFinishFailed?: (errorInfo: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TABKeysMap = {
|
const TABKeysMap = {
|
||||||
@@ -113,7 +114,8 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
instanceTypeList = [],
|
instanceTypeList = [],
|
||||||
noAvailableInstanceTypes,
|
noAvailableInstanceTypes,
|
||||||
onScopeChange,
|
onScopeChange,
|
||||||
onFinish
|
onFinish,
|
||||||
|
onFinishFailed
|
||||||
} = props;
|
} = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { getRuleMessage } = useAppUtils();
|
const { getRuleMessage } = useAppUtils();
|
||||||
@@ -370,6 +372,7 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
]
|
]
|
||||||
}));
|
}));
|
||||||
rawHandleOnFinishFailed({ ...errorInfo, errorFields });
|
rawHandleOnFinishFailed({ ...errorInfo, errorFields });
|
||||||
|
onFinishFailed?.(errorInfo);
|
||||||
};
|
};
|
||||||
const detectMode = (volume?: FormData['spec']['volume']) => {
|
const detectMode = (volume?: FormData['spec']['volume']) => {
|
||||||
if (volume?.persistent?.name || volume?.persistentTemplate?.name) {
|
if (volume?.persistent?.name || volume?.persistentTemplate?.name) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||||
import { ModalFooter } from '@gpustack/core-ui';
|
import { ModalFooter } from '@gpustack/core-ui';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import FormDrawer from '../../../_components/form-drawer';
|
import FormDrawer from '../../../_components/form-drawer';
|
||||||
@@ -23,9 +24,10 @@ const AddPublicKeyModal: React.FC<AddPublicKeyModalProps> = ({
|
|||||||
onCancel
|
onCancel
|
||||||
}) => {
|
}) => {
|
||||||
const form = useRef<any>(null);
|
const form = useRef<any>(null);
|
||||||
|
const { loading, guard, run, release } = useSubmitLock();
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
form.current?.submit();
|
guard(() => form.current?.submit());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -34,7 +36,7 @@ const AddPublicKeyModal: React.FC<AddPublicKeyModalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFinish = async (values: FormData) => {
|
const onFinish = async (values: FormData) => {
|
||||||
onOk({ ...values });
|
await run(() => onOk({ ...values }));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -48,6 +50,7 @@ const AddPublicKeyModal: React.FC<AddPublicKeyModalProps> = ({
|
|||||||
<ModalFooter
|
<ModalFooter
|
||||||
onOk={handleSubmit}
|
onOk={handleSubmit}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
loading={loading}
|
||||||
style={{
|
style={{
|
||||||
padding: '16px 24px 8px',
|
padding: '16px 24px 8px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -61,6 +64,7 @@ const AddPublicKeyModal: React.FC<AddPublicKeyModalProps> = ({
|
|||||||
action={action}
|
action={action}
|
||||||
currentData={data}
|
currentData={data}
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
|
onFinishFailed={release}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
</FormDrawer>
|
</FormDrawer>
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ interface PublicKeyFormProps {
|
|||||||
action: PageActionType;
|
action: PageActionType;
|
||||||
currentData?: ListItem | null;
|
currentData?: ListItem | null;
|
||||||
onFinish: (values: FormData) => Promise<void>;
|
onFinish: (values: FormData) => Promise<void>;
|
||||||
|
onFinishFailed?: (errorInfo: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GPUServicePublicKeyForm: React.FC<PublicKeyFormProps> = forwardRef(
|
const GPUServicePublicKeyForm: React.FC<PublicKeyFormProps> = forwardRef(
|
||||||
(props, ref) => {
|
(props, ref) => {
|
||||||
const { action, currentData, open, onFinish } = props;
|
const { action, currentData, open, onFinish, onFinishFailed } = props;
|
||||||
const [form] = Form.useForm<FormData>();
|
const [form] = Form.useForm<FormData>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -50,6 +51,7 @@ const GPUServicePublicKeyForm: React.FC<PublicKeyFormProps> = forwardRef(
|
|||||||
name="gpuServicePublicKeyForm"
|
name="gpuServicePublicKeyForm"
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
|
onFinishFailed={onFinishFailed}
|
||||||
preserve={false}
|
preserve={false}
|
||||||
initialValues={{}}
|
initialValues={{}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||||
import { ModalFooter } from '@gpustack/core-ui';
|
import { ModalFooter } from '@gpustack/core-ui';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import FormDrawer from '../../../_components/form-drawer';
|
import FormDrawer from '../../../_components/form-drawer';
|
||||||
@@ -23,9 +24,10 @@ const AddStorageTypeModal: React.FC<AddStorageTypeModalProps> = ({
|
|||||||
onCancel
|
onCancel
|
||||||
}) => {
|
}) => {
|
||||||
const form = useRef<any>(null);
|
const form = useRef<any>(null);
|
||||||
|
const { loading, guard, run, release } = useSubmitLock();
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
form.current?.submit();
|
guard(() => form.current?.submit());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -34,7 +36,7 @@ const AddStorageTypeModal: React.FC<AddStorageTypeModalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFinish = async (values: FormData) => {
|
const onFinish = async (values: FormData) => {
|
||||||
onOk({ ...values });
|
await run(() => onOk({ ...values }));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -48,6 +50,7 @@ const AddStorageTypeModal: React.FC<AddStorageTypeModalProps> = ({
|
|||||||
<ModalFooter
|
<ModalFooter
|
||||||
onOk={handleSubmit}
|
onOk={handleSubmit}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
loading={loading}
|
||||||
style={{
|
style={{
|
||||||
padding: '16px 24px 8px',
|
padding: '16px 24px 8px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -61,6 +64,7 @@ const AddStorageTypeModal: React.FC<AddStorageTypeModalProps> = ({
|
|||||||
action={action}
|
action={action}
|
||||||
currentData={data}
|
currentData={data}
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
|
onFinishFailed={release}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
</FormDrawer>
|
</FormDrawer>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ interface StorageTypeFormProps {
|
|||||||
action: PageActionType;
|
action: PageActionType;
|
||||||
currentData?: ListItem | null;
|
currentData?: ListItem | null;
|
||||||
onFinish: (values: FormData) => Promise<void>;
|
onFinish: (values: FormData) => Promise<void>;
|
||||||
|
onFinishFailed?: (errorInfo: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const detectKind = (item?: ListItem | null): StorageTypeKind => {
|
const detectKind = (item?: ListItem | null): StorageTypeKind => {
|
||||||
@@ -27,7 +28,7 @@ const detectKind = (item?: ListItem | null): StorageTypeKind => {
|
|||||||
|
|
||||||
const GPUServiceStorageTypeForm: React.FC<StorageTypeFormProps> = forwardRef(
|
const GPUServiceStorageTypeForm: React.FC<StorageTypeFormProps> = forwardRef(
|
||||||
(props, ref) => {
|
(props, ref) => {
|
||||||
const { action, currentData, open, onFinish } = props;
|
const { action, currentData, open, onFinish, onFinishFailed } = props;
|
||||||
const [form] = Form.useForm<FormData>();
|
const [form] = Form.useForm<FormData>();
|
||||||
const kind = Form.useWatch('type', form);
|
const kind = Form.useWatch('type', form);
|
||||||
|
|
||||||
@@ -115,6 +116,7 @@ const GPUServiceStorageTypeForm: React.FC<StorageTypeFormProps> = forwardRef(
|
|||||||
name="gpuServiceStorageTypeForm"
|
name="gpuServiceStorageTypeForm"
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={handleFinish}
|
onFinish={handleFinish}
|
||||||
|
onFinishFailed={onFinishFailed}
|
||||||
preserve={false}
|
preserve={false}
|
||||||
initialValues={{}}
|
initialValues={{}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||||
import { ModalFooter } from '@gpustack/core-ui';
|
import { ModalFooter } from '@gpustack/core-ui';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import FormDrawer from '../../../_components/form-drawer';
|
import FormDrawer from '../../../_components/form-drawer';
|
||||||
@@ -26,9 +27,10 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
storageClassList
|
storageClassList
|
||||||
}) => {
|
}) => {
|
||||||
const form = useRef<any>(null);
|
const form = useRef<any>(null);
|
||||||
|
const { loading, guard, run, release } = useSubmitLock();
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
form.current?.submit();
|
guard(() => form.current?.submit());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -37,9 +39,11 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFinish = async (values: FormData) => {
|
const onFinish = async (values: FormData) => {
|
||||||
onOk({
|
await run(() =>
|
||||||
...values
|
onOk({
|
||||||
});
|
...values
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -53,6 +57,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
<ModalFooter
|
<ModalFooter
|
||||||
onOk={handleSubmit}
|
onOk={handleSubmit}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
loading={loading}
|
||||||
style={{
|
style={{
|
||||||
padding: '16px 24px 8px',
|
padding: '16px 24px 8px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -67,6 +72,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
action={action}
|
action={action}
|
||||||
currentData={data}
|
currentData={data}
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
|
onFinishFailed={release}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
</FormContext.Provider>
|
</FormContext.Provider>
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ interface StorageFormProps {
|
|||||||
action: PageActionType;
|
action: PageActionType;
|
||||||
currentData?: ListItem | null;
|
currentData?: ListItem | null;
|
||||||
onFinish: (values: FormData) => Promise<void>;
|
onFinish: (values: FormData) => Promise<void>;
|
||||||
|
onFinishFailed?: (errorInfo: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GPUServiceStorageForm: React.FC<StorageFormProps> = forwardRef(
|
const GPUServiceStorageForm: React.FC<StorageFormProps> = forwardRef(
|
||||||
(props, ref) => {
|
(props, ref) => {
|
||||||
const { action, currentData, open, onFinish } = props;
|
const { action, currentData, open, onFinish, onFinishFailed } = props;
|
||||||
const [form] = Form.useForm<FormData>();
|
const [form] = Form.useForm<FormData>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -51,6 +52,7 @@ const GPUServiceStorageForm: React.FC<StorageFormProps> = forwardRef(
|
|||||||
name="gpuServiceStorageForm"
|
name="gpuServiceStorageForm"
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
|
onFinishFailed={onFinishFailed}
|
||||||
preserve={false}
|
preserve={false}
|
||||||
initialValues={{}}
|
initialValues={{}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||||
import { ModalFooter } from '@gpustack/core-ui';
|
import { ModalFooter } from '@gpustack/core-ui';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import FormDrawer from '../../../_components/form-drawer';
|
import FormDrawer from '../../../_components/form-drawer';
|
||||||
@@ -23,9 +24,10 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
onCancel
|
onCancel
|
||||||
}) => {
|
}) => {
|
||||||
const form = useRef<any>(null);
|
const form = useRef<any>(null);
|
||||||
|
const { loading, guard, run, release } = useSubmitLock();
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
form.current?.submit();
|
guard(() => form.current?.submit());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -34,9 +36,11 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onFinish = async (values: FormData) => {
|
const onFinish = async (values: FormData) => {
|
||||||
onOk({
|
await run(() =>
|
||||||
...values
|
onOk({
|
||||||
});
|
...values
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -50,6 +54,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
<ModalFooter
|
<ModalFooter
|
||||||
onOk={handleSubmit}
|
onOk={handleSubmit}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
loading={loading}
|
||||||
style={{
|
style={{
|
||||||
padding: '16px 24px 8px',
|
padding: '16px 24px 8px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -63,6 +68,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
action={action}
|
action={action}
|
||||||
currentData={currentData}
|
currentData={currentData}
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
|
onFinishFailed={release}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
</FormDrawer>
|
</FormDrawer>
|
||||||
|
|||||||
@@ -12,11 +12,12 @@ interface TemplateFormProps {
|
|||||||
action: PageActionType;
|
action: PageActionType;
|
||||||
currentData?: ListItem | null;
|
currentData?: ListItem | null;
|
||||||
onFinish: (values: FormData) => Promise<void>;
|
onFinish: (values: FormData) => Promise<void>;
|
||||||
|
onFinishFailed?: (errorInfo: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GPUServiceTemplateForm: React.FC<TemplateFormProps> = forwardRef(
|
const GPUServiceTemplateForm: React.FC<TemplateFormProps> = forwardRef(
|
||||||
(props, ref) => {
|
(props, ref) => {
|
||||||
const { action, currentData, open, onFinish } = props;
|
const { action, currentData, open, onFinish, onFinishFailed } = props;
|
||||||
const [form] = Form.useForm<FormData>();
|
const [form] = Form.useForm<FormData>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -58,6 +59,7 @@ const GPUServiceTemplateForm: React.FC<TemplateFormProps> = forwardRef(
|
|||||||
name="gpuServiceTemplateForm"
|
name="gpuServiceTemplateForm"
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={handleFinish}
|
onFinish={handleFinish}
|
||||||
|
onFinishFailed={onFinishFailed}
|
||||||
preserve={false}
|
preserve={false}
|
||||||
scrollToFirstError
|
scrollToFirstError
|
||||||
initialValues={{
|
initialValues={{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||||
import { FormDrawer } from '@gpustack/core-ui';
|
import { FormDrawer } from '@gpustack/core-ui';
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { FormData, MaasProviderItem as ListItem } from '../config/types';
|
import { FormData, MaasProviderItem as ListItem } from '../config/types';
|
||||||
@@ -22,16 +23,19 @@ const AddProvider: React.FC<AddModalProps> = ({
|
|||||||
onCancel
|
onCancel
|
||||||
}) => {
|
}) => {
|
||||||
const form = useRef<any>(null);
|
const form = useRef<any>(null);
|
||||||
|
const { loading, guard, run, release } = useSubmitLock();
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
form.current?.submit();
|
guard(() => form.current?.submit());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnFinish = async (data: FormData) => {
|
const handleOnFinish = async (data: FormData) => {
|
||||||
console.log('handleOnFinish', data);
|
console.log('handleOnFinish', data);
|
||||||
onOk({
|
await run(() =>
|
||||||
...data
|
onOk({
|
||||||
});
|
...data
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -46,12 +50,14 @@ const AddProvider: React.FC<AddModalProps> = ({
|
|||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
width={600}
|
width={600}
|
||||||
|
loading={loading}
|
||||||
>
|
>
|
||||||
<ProviderForm
|
<ProviderForm
|
||||||
ref={form}
|
ref={form}
|
||||||
action={action}
|
action={action}
|
||||||
currentData={currentData}
|
currentData={currentData}
|
||||||
onFinish={handleOnFinish}
|
onFinish={handleOnFinish}
|
||||||
|
onFinishFailed={release}
|
||||||
/>
|
/>
|
||||||
</FormDrawer>
|
</FormDrawer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ interface ProviderFormProps {
|
|||||||
action: PageActionType;
|
action: PageActionType;
|
||||||
currentData?: ListItem; // Used when action is EDIT
|
currentData?: ListItem; // Used when action is EDIT
|
||||||
onFinish: (values: FormData) => Promise<void>;
|
onFinish: (values: FormData) => Promise<void>;
|
||||||
|
onFinishFailed?: (errorInfo: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TABKeysMap = {
|
const TABKeysMap = {
|
||||||
@@ -51,7 +52,7 @@ const requiredFields = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
||||||
const { action, currentData, onFinish } = props;
|
const { action, currentData, onFinish, onFinishFailed } = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const providerRequiredFieldsMap = useProviderRequiredFields();
|
const providerRequiredFieldsMap = useProviderRequiredFields();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
@@ -146,6 +147,11 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
updateActiveKey
|
updateActiveKey
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleFinishFailed = (errorInfo: any) => {
|
||||||
|
handleOnFinishFailed(errorInfo);
|
||||||
|
onFinishFailed?.(errorInfo);
|
||||||
|
};
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
submit: () => {
|
submit: () => {
|
||||||
form.submit();
|
form.submit();
|
||||||
@@ -217,7 +223,7 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={handleOnFinish}
|
onFinish={handleOnFinish}
|
||||||
onFinishFailed={handleOnFinishFailed}
|
onFinishFailed={handleFinishFailed}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
proxy_enabled: false,
|
proxy_enabled: false,
|
||||||
proxy_url: '',
|
proxy_url: '',
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||||
import { AlertBlockInfo, FormDrawer, ModalFooter } from '@gpustack/core-ui';
|
import { AlertBlockInfo, FormDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
@@ -26,15 +27,18 @@ const AddProvider: React.FC<AddModalProps> = ({
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [isChanged, setIsChanged] = React.useState(false);
|
const [isChanged, setIsChanged] = React.useState(false);
|
||||||
const form = useRef<any>(null);
|
const form = useRef<any>(null);
|
||||||
|
const { loading, guard, run, release } = useSubmitLock();
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
form.current?.submit();
|
guard(() => form.current?.submit());
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFinish = async (data: FormData) => {
|
const onFinish = async (data: FormData) => {
|
||||||
onOk({
|
await run(() =>
|
||||||
...data
|
onOk({
|
||||||
});
|
...data
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -63,6 +67,7 @@ const AddProvider: React.FC<AddModalProps> = ({
|
|||||||
<ModalFooter
|
<ModalFooter
|
||||||
onOk={handleSubmit}
|
onOk={handleSubmit}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
|
loading={loading}
|
||||||
styles={{
|
styles={{
|
||||||
wrapper: {
|
wrapper: {
|
||||||
paddingTop: 16
|
paddingTop: 16
|
||||||
@@ -78,6 +83,7 @@ const AddProvider: React.FC<AddModalProps> = ({
|
|||||||
realAction={realAction}
|
realAction={realAction}
|
||||||
currentData={currentData}
|
currentData={currentData}
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
|
onFinishFailed={release}
|
||||||
open={open}
|
open={open}
|
||||||
onFallbackChange={(changed: boolean) => {
|
onFallbackChange={(changed: boolean) => {
|
||||||
setIsChanged(changed);
|
setIsChanged(changed);
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ interface ProviderFormProps {
|
|||||||
routeTargets?: RouteTargetFormItem[];
|
routeTargets?: RouteTargetFormItem[];
|
||||||
}; // Used when action is EDIT
|
}; // Used when action is EDIT
|
||||||
onFinish: (values: FormData) => Promise<void>;
|
onFinish: (values: FormData) => Promise<void>;
|
||||||
|
onFinishFailed?: (errorInfo: any) => void;
|
||||||
onFallbackChange?: (changed: boolean) => void;
|
onFallbackChange?: (changed: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,8 +87,15 @@ const requiredFields = {
|
|||||||
|
|
||||||
const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { action, realAction, currentData, open, onFinish, onFallbackChange } =
|
const {
|
||||||
props;
|
action,
|
||||||
|
realAction,
|
||||||
|
currentData,
|
||||||
|
open,
|
||||||
|
onFinish,
|
||||||
|
onFinishFailed,
|
||||||
|
onFallbackChange
|
||||||
|
} = props;
|
||||||
const { getScrollElementScrollableHeight } = useWrapperContext();
|
const { getScrollElementScrollableHeight } = useWrapperContext();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const scrollTabsRef = useRef<any>(null);
|
const scrollTabsRef = useRef<any>(null);
|
||||||
@@ -238,6 +246,11 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
updateActiveKey
|
updateActiveKey
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleFinishFailed = (errorInfo: any) => {
|
||||||
|
handleOnFinishFailed(errorInfo);
|
||||||
|
onFinishFailed?.(errorInfo);
|
||||||
|
};
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
submit: () => {
|
submit: () => {
|
||||||
form.submit();
|
form.submit();
|
||||||
@@ -266,7 +279,7 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={handleOnFinish}
|
onFinish={handleOnFinish}
|
||||||
onFinishFailed={handleOnFinishFailed}
|
onFinishFailed={handleFinishFailed}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
categories: [modelCategoriesMap.llm],
|
categories: [modelCategoriesMap.llm],
|
||||||
meta: {}
|
meta: {}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { PageAction, PasswordReg } from '@/config';
|
import { PageAction, PasswordReg } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||||
import {
|
import {
|
||||||
Input as CInput,
|
Input as CInput,
|
||||||
FormDrawer,
|
FormDrawer,
|
||||||
@@ -32,6 +33,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
const { initialState } = useModel('@@initialState') || {};
|
const { initialState } = useModel('@@initialState') || {};
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const { loading, guard, run, release } = useSubmitLock();
|
||||||
|
|
||||||
const initFormValue = () => {
|
const initFormValue = () => {
|
||||||
if (action === PageAction.EDIT && open) {
|
if (action === PageAction.EDIT && open) {
|
||||||
@@ -49,7 +51,11 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
form.submit();
|
guard(() => form.submit());
|
||||||
|
};
|
||||||
|
|
||||||
|
const onFinish = async (values: FormData) => {
|
||||||
|
await run(() => onOk(values));
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -62,8 +68,15 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
open={open}
|
open={open}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
|
loading={loading}
|
||||||
>
|
>
|
||||||
<Form name="addUserForm" form={form} onFinish={onOk} preserve={false}>
|
<Form
|
||||||
|
name="addUserForm"
|
||||||
|
form={form}
|
||||||
|
onFinish={onFinish}
|
||||||
|
onFinishFailed={release}
|
||||||
|
preserve={false}
|
||||||
|
>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="username"
|
name="username"
|
||||||
rules={[
|
rules={[
|
||||||
|
|||||||
Reference in New Issue
Block a user