fix: prevent duplicate submit and unlock on validation failure in deploy/update modals
This commit is contained in:
@@ -59,7 +59,7 @@ type AddModalProps = {
|
||||
source: SourceType;
|
||||
width?: string | number;
|
||||
current?: any;
|
||||
onOk: (values: FormData) => void;
|
||||
onOk: (values: FormData) => void | Promise<void>;
|
||||
onCancel: () => void;
|
||||
};
|
||||
|
||||
@@ -104,8 +104,14 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
const specListRef = useRef<any[]>([]);
|
||||
const noCompatibleGPUsRef = useRef<boolean>(false);
|
||||
const backendOptionsCache = useRef<any>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const submitloadingRef = useRef<boolean>(false);
|
||||
|
||||
const handleSumit = () => {
|
||||
if (submitloadingRef.current) {
|
||||
return;
|
||||
}
|
||||
submitloadingRef.current = true;
|
||||
form.current?.submit?.();
|
||||
};
|
||||
|
||||
@@ -115,7 +121,11 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
return;
|
||||
}
|
||||
submitAnyway.current = true;
|
||||
form.current?.submit?.();
|
||||
handleSumit();
|
||||
};
|
||||
|
||||
const onFinishFailed = () => {
|
||||
submitloadingRef.current = false;
|
||||
};
|
||||
|
||||
const generateSubmitData = (formData: FormData) => {
|
||||
@@ -348,7 +358,13 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
..._.omit(selectSpecRef.current, ['name']),
|
||||
...values
|
||||
};
|
||||
onOk(data);
|
||||
setLoading(true);
|
||||
try {
|
||||
await onOk(data);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
submitloadingRef.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@@ -447,6 +463,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
<ModalFooter
|
||||
onCancel={handleCancel}
|
||||
onOk={handleSumit}
|
||||
loading={loading}
|
||||
showOkBtn={!showExtraButton}
|
||||
extra={
|
||||
showExtraButton && (
|
||||
@@ -472,6 +489,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
source={source}
|
||||
action={action}
|
||||
onOk={handleOk}
|
||||
onFinishFailed={onFinishFailed}
|
||||
ref={form}
|
||||
isGGUF={isGGUF}
|
||||
formKey={DeployFormKeyMap.CATALOG}
|
||||
|
||||
@@ -146,6 +146,8 @@ const AddModal: FC<AddModalProps> = (props) => {
|
||||
const requestModelIdRef = useRef<number>(0);
|
||||
const currentSelectedModel = useRef<any>({});
|
||||
const flatBackendOptionsRef = useRef<any[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const submitloadingRef = useRef<boolean>(false);
|
||||
|
||||
const { run: fetchModelFiles } = useDeferredRequest(
|
||||
() => modelFileRef.current?.fetchModelFiles?.(),
|
||||
@@ -422,22 +424,33 @@ const AddModal: FC<AddModalProps> = (props) => {
|
||||
};
|
||||
|
||||
const handleOnOk = async (allValues: FormData) => {
|
||||
onOk(allValues);
|
||||
setLoading(true);
|
||||
await onOk(allValues);
|
||||
setLoading(false);
|
||||
submitloadingRef.current = false;
|
||||
};
|
||||
|
||||
const handleSumit = () => {
|
||||
if (submitloadingRef.current) {
|
||||
return;
|
||||
}
|
||||
submitloadingRef.current = true;
|
||||
form.current?.submit?.();
|
||||
};
|
||||
|
||||
const handleSubmitAnyway = async () => {
|
||||
submitAnyway.current = true;
|
||||
form.current?.submit?.();
|
||||
};
|
||||
|
||||
const handleSumit = () => {
|
||||
form.current?.submit?.();
|
||||
handleSumit();
|
||||
};
|
||||
|
||||
const handleSetIsGGUF = async (flag: boolean) => {
|
||||
setIsGGUF(flag);
|
||||
};
|
||||
|
||||
const onFinishFailed = () => {
|
||||
submitloadingRef.current = false;
|
||||
};
|
||||
|
||||
const handleBackendChange = async (backend: string) => {
|
||||
const data = form.current.form.getFieldsValue?.();
|
||||
const res = handleBackendChangeBefore(data);
|
||||
@@ -660,6 +673,7 @@ const AddModal: FC<AddModalProps> = (props) => {
|
||||
<ModalFooter
|
||||
onCancel={handleCancel}
|
||||
onOk={handleSumit}
|
||||
loading={loading}
|
||||
showOkBtn={!showExtraButton}
|
||||
extra={
|
||||
showExtraButton && (
|
||||
@@ -691,6 +705,7 @@ const AddModal: FC<AddModalProps> = (props) => {
|
||||
onOk={handleOnOk}
|
||||
ref={form}
|
||||
isGGUF={isGGUF}
|
||||
onFinishFailed={onFinishFailed}
|
||||
onBackendChange={handleBackendChange}
|
||||
onValuesChange={onValuesChange}
|
||||
clearCacheFormValues={clearCacheFormValues}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { PageActionType } from '@/config/types';
|
||||
import { ColumnWrapper, GSDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import _ from 'lodash';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
DeployFormKeyMap,
|
||||
DO_NOT_NOTIFY_RECREATE,
|
||||
@@ -29,7 +29,7 @@ type AddModalProps = {
|
||||
number,
|
||||
{ provider: string; state: string | number }
|
||||
>[];
|
||||
onOk: (values: FormData) => void;
|
||||
onOk: (values: FormData) => void | Promise<void>;
|
||||
onCancel: () => void;
|
||||
};
|
||||
|
||||
@@ -60,6 +60,8 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
||||
const formRef = useRef<any>(null);
|
||||
const submitAnyway = useRef<boolean>(false);
|
||||
const originFormData = useRef<any>(null);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const submitloadingRef = useRef<boolean>(false);
|
||||
|
||||
const setOriginalFormData = () => {
|
||||
if (!originFormData.current) {
|
||||
@@ -157,12 +159,20 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
||||
};
|
||||
|
||||
const handleSumit = () => {
|
||||
if (submitloadingRef.current) {
|
||||
return;
|
||||
}
|
||||
submitloadingRef.current = true;
|
||||
formRef.current?.submit();
|
||||
};
|
||||
|
||||
const handleSubmitAnyway = async () => {
|
||||
submitAnyway.current = true;
|
||||
formRef.current?.submit?.();
|
||||
handleSumit();
|
||||
};
|
||||
|
||||
const onFinishFailed = () => {
|
||||
submitloadingRef.current = false;
|
||||
};
|
||||
|
||||
const handleOk = async (formdata: FormData) => {
|
||||
@@ -182,7 +192,13 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
||||
}
|
||||
: {})
|
||||
};
|
||||
onOk(submitData);
|
||||
setLoading(true);
|
||||
try {
|
||||
await onOk(submitData);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
submitloadingRef.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleManulOnValuesChange = (changedValues: any, allValues: any) => {
|
||||
@@ -266,6 +282,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
||||
style={ModalFooterStyle}
|
||||
onCancel={onCancel}
|
||||
onOk={handleSumit}
|
||||
loading={loading}
|
||||
></ModalFooter>
|
||||
</>
|
||||
}
|
||||
@@ -278,6 +295,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
||||
realAction={realAction}
|
||||
clusterList={clusterList}
|
||||
onOk={handleOk}
|
||||
onFinishFailed={onFinishFailed}
|
||||
ref={formRef}
|
||||
isGGUF={isGGUF}
|
||||
onBackendChange={handleAsyncBackendChange}
|
||||
|
||||
@@ -76,15 +76,15 @@ const SearchResult: React.FC<SearchResultProps> = (props) => {
|
||||
></IconFont>
|
||||
}
|
||||
description={
|
||||
source === modelSourceMap.huggingface_value ? (
|
||||
<div className="flex-column gap-5">
|
||||
<div className="flex-column gap-5">
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'models.search.networkerror' })}
|
||||
</span>
|
||||
<span>
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'models.search.networkerror' })}
|
||||
{intl.formatMessage({ id: 'models.search.hfvisit' })}
|
||||
</span>
|
||||
<span>
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'models.search.hfvisit' })}
|
||||
</span>
|
||||
{source === modelSourceMap.huggingface_value ? (
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
@@ -93,9 +93,18 @@ const SearchResult: React.FC<SearchResultProps> = (props) => {
|
||||
>
|
||||
Hugging Face
|
||||
</Button>
|
||||
</span>
|
||||
</div>
|
||||
) : null
|
||||
) : (
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
href="https://modelscope.cn/"
|
||||
target="_blank"
|
||||
>
|
||||
ModelScope
|
||||
</Button>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -66,6 +66,7 @@ interface DataFormProps {
|
||||
onOk: (values: FormData) => void;
|
||||
onBackendChange?: (value: string) => void;
|
||||
onClusterChange?: (value: number) => void;
|
||||
onFinishFailed?: (errorInfo: any) => void;
|
||||
}
|
||||
|
||||
const TABKeysMap = {
|
||||
@@ -91,6 +92,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
||||
onSourceChange,
|
||||
onValuesChange,
|
||||
onClusterChange,
|
||||
onFinishFailed,
|
||||
onOk
|
||||
} = props;
|
||||
const { getScrollElementScrollableHeight } = useWrapperContext();
|
||||
@@ -285,6 +287,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
||||
|
||||
const handleOnFinishFailed = (errorInfo: any) => {
|
||||
setSubmitAttempted(true);
|
||||
onFinishFailed?.(errorInfo);
|
||||
console.log('Failed:', errorInfo);
|
||||
const { errorFields } = errorInfo;
|
||||
if (errorFields && errorFields.length > 0) {
|
||||
|
||||
Reference in New Issue
Block a user