diff --git a/web/app/components/base/form/hooks/use-check-validated.ts b/web/app/components/base/form/hooks/use-check-validated.ts index aaf79f55d9..ce2e524e07 100644 --- a/web/app/components/base/form/hooks/use-check-validated.ts +++ b/web/app/components/base/form/hooks/use-check-validated.ts @@ -7,7 +7,6 @@ export const useCheckValidated = (form: AnyFormApi) => { const checkValidated = useCallback(() => { const allError = form?.getAllErrors() - console.log('allError', allError) if (allError) { const fields = allError.fields diff --git a/web/app/components/plugins/plugin-auth/authorize/add-oauth-button.tsx b/web/app/components/plugins/plugin-auth/authorize/add-oauth-button.tsx index 8e6fc5aa03..e3780b11d7 100644 --- a/web/app/components/plugins/plugin-auth/authorize/add-oauth-button.tsx +++ b/web/app/components/plugins/plugin-auth/authorize/add-oauth-button.tsx @@ -51,7 +51,7 @@ const AddOAuthButton = ({ const renderI18nObject = useRenderI18nObject() const [isOAuthSettingsOpen, setIsOAuthSettingsOpen] = useState(false) const { mutateAsync: getPluginOAuthUrl } = useGetPluginOAuthUrlHook(pluginPayload) - const { data } = useGetPluginOAuthClientSchemaHook(pluginPayload) + const { data, isLoading } = useGetPluginOAuthClientSchemaHook(pluginPayload) const { schema = [], is_oauth_custom_client_enabled, @@ -214,7 +214,7 @@ const AddOAuthButton = ({ setIsOAuthSettingsOpen(false)} - disabled={disabled} + disabled={disabled || isLoading} schemas={memorizedSchemas} onAuth={handleOAuth} editValues={client_params} diff --git a/web/app/components/plugins/plugin-auth/authorize/api-key-modal.tsx b/web/app/components/plugins/plugin-auth/authorize/api-key-modal.tsx index 0f81f8ace4..03849f1d66 100644 --- a/web/app/components/plugins/plugin-auth/authorize/api-key-modal.tsx +++ b/web/app/components/plugins/plugin-auth/authorize/api-key-modal.tsx @@ -3,6 +3,7 @@ import { useCallback, useMemo, useRef, + useState, } from 'react' import { useTranslation } from 'react-i18next' import { RiExternalLinkLine } from '@remixicon/react' @@ -39,6 +40,12 @@ const ApiKeyModal = ({ }: ApiKeyModalProps) => { const { t } = useTranslation() const { notify } = useToastContext() + const [doingAction, setDoingAction] = useState(false) + const doingActionRef = useRef(doingAction) + const handleSetDoingAction = useCallback((value: boolean) => { + doingActionRef.current = value + setDoingAction(value) + }, []) const { data = [], isLoading } = useGetPluginCredentialSchemaHook(pluginPayload, CredentialTypeEnum.API_KEY) const formSchemas = useMemo(() => { return [ @@ -63,6 +70,8 @@ const ApiKeyModal = ({ const invalidatePluginCredentialInfo = useInvalidPluginCredentialInfoHook(pluginPayload) const formRef = useRef(null) const handleConfirm = useCallback(async () => { + if (doingActionRef.current) + return const { isCheckValidated, values, @@ -73,34 +82,40 @@ const ApiKeyModal = ({ if (!isCheckValidated) return - const { - __name__, - __credential_id__, - ...restValues - } = values + try { + const { + __name__, + __credential_id__, + ...restValues + } = values - if (editValues) { - await updatePluginCredential({ - credentials: restValues, - credential_id: __credential_id__, - name: __name__ || '', + handleSetDoingAction(true) + if (editValues) { + await updatePluginCredential({ + credentials: restValues, + credential_id: __credential_id__, + name: __name__ || '', + }) + } + else { + await addPluginCredential({ + credentials: restValues, + type: CredentialTypeEnum.API_KEY, + name: __name__ || '', + }) + } + notify({ + type: 'success', + message: t('common.api.actionSuccess'), }) + + onClose?.() + invalidatePluginCredentialInfo() } - else { - await addPluginCredential({ - credentials: restValues, - type: CredentialTypeEnum.API_KEY, - name: __name__ || '', - }) + finally { + handleSetDoingAction(false) } - notify({ - type: 'success', - message: t('common.api.actionSuccess'), - }) - - onClose?.() - invalidatePluginCredentialInfo() - }, [addPluginCredential, onClose, invalidatePluginCredentialInfo, updatePluginCredential, notify, t, editValues]) + }, [addPluginCredential, onClose, invalidatePluginCredentialInfo, updatePluginCredential, notify, t, editValues, handleSetDoingAction]) return ( { isLoading && ( diff --git a/web/app/components/plugins/plugin-auth/authorize/oauth-client-settings.tsx b/web/app/components/plugins/plugin-auth/authorize/oauth-client-settings.tsx index 283617543a..09d2571cb2 100644 --- a/web/app/components/plugins/plugin-auth/authorize/oauth-client-settings.tsx +++ b/web/app/components/plugins/plugin-auth/authorize/oauth-client-settings.tsx @@ -2,6 +2,7 @@ import { memo, useCallback, useRef, + useState, } from 'react' import { useTranslation } from 'react-i18next' import Modal from '@/app/components/base/modal/modal' @@ -35,6 +36,12 @@ const OAuthClientSettings = ({ }: OAuthClientSettingsProps) => { const { t } = useTranslation() const { notify } = useToastContext() + const [doingAction, setDoingAction] = useState(false) + const doingActionRef = useRef(doingAction) + const handleSetDoingAction = useCallback((value: boolean) => { + doingActionRef.current = value + setDoingAction(value) + }, []) const defaultValues = schemas.reduce((acc, schema) => { if (schema.default) acc[schema.name] = schema.default @@ -44,6 +51,8 @@ const OAuthClientSettings = ({ const invalidatePluginCredentialInfo = useInvalidPluginCredentialInfoHook(pluginPayload) const formRef = useRef(null) const handleConfirm = useCallback(async () => { + if (doingActionRef.current) + return const { isCheckValidated, values, @@ -53,23 +62,30 @@ const OAuthClientSettings = ({ }) || { isCheckValidated: false, values: {} } if (!isCheckValidated) return - const { - __oauth_client__, - ...restValues - } = values - await setPluginOAuthCustomClient({ - client_params: restValues, - enable_oauth_custom_client: __oauth_client__ === 'custom', - }) - notify({ - type: 'success', - message: t('common.api.actionSuccess'), - }) + try { + const { + __oauth_client__, + ...restValues + } = values + + handleSetDoingAction(true) + await setPluginOAuthCustomClient({ + client_params: restValues, + enable_oauth_custom_client: __oauth_client__ === 'custom', + }) + notify({ + type: 'success', + message: t('common.api.actionSuccess'), + }) - onClose?.() - invalidatePluginCredentialInfo() - }, [onClose, invalidatePluginCredentialInfo, setPluginOAuthCustomClient, notify, t]) + onClose?.() + invalidatePluginCredentialInfo() + } + finally { + handleSetDoingAction(false) + } + }, [onClose, invalidatePluginCredentialInfo, setPluginOAuthCustomClient, notify, t, handleSetDoingAction]) const handleConfirmAndAuthorize = useCallback(async () => { await handleConfirm() @@ -88,6 +104,7 @@ const OAuthClientSettings = ({ onClose={onClose} onCancel={handleConfirm} onConfirm={handleConfirmAndAuthorize} + disabled={disabled || doingAction} > { + doingActionRef.current = doing + setDoingAction(doing) + }, []) const handleConfirm = useCallback(async () => { + if (doingActionRef.current) + return if (!pendingOperationCredentialId.current) { setDeleteCredentialId(null) return } - - await deletePluginCredential({ credential_id: pendingOperationCredentialId.current }) - notify({ - type: 'success', - message: t('common.api.actionSuccess'), - }) - invalidatePluginCredentialInfo() - setDeleteCredentialId(null) - pendingOperationCredentialId.current = null - }, [deletePluginCredential, invalidatePluginCredentialInfo, notify, t]) + try { + handleSetDoingAction(true) + await deletePluginCredential({ credential_id: pendingOperationCredentialId.current }) + notify({ + type: 'success', + message: t('common.api.actionSuccess'), + }) + invalidatePluginCredentialInfo() + setDeleteCredentialId(null) + pendingOperationCredentialId.current = null + } + finally { + handleSetDoingAction(false) + } + }, [deletePluginCredential, invalidatePluginCredentialInfo, notify, t, handleSetDoingAction]) const [editValues, setEditValues] = useState | null>(null) const handleEdit = useCallback((id: string, values: Record) => { pendingOperationCredentialId.current = id @@ -123,24 +136,41 @@ const Authorized = ({ }, []) const { mutateAsync: setPluginDefaultCredential } = useSetPluginDefaultCredentialHook(pluginPayload) const handleSetDefault = useCallback(async (id: string) => { - await setPluginDefaultCredential(id) - notify({ - type: 'success', - message: t('common.api.actionSuccess'), - }) - invalidatePluginCredentialInfo() - }, [setPluginDefaultCredential, invalidatePluginCredentialInfo, notify, t]) + if (doingActionRef.current) + return + try { + handleSetDoingAction(true) + await setPluginDefaultCredential(id) + notify({ + type: 'success', + message: t('common.api.actionSuccess'), + }) + invalidatePluginCredentialInfo() + } + finally { + handleSetDoingAction(false) + } + }, [setPluginDefaultCredential, invalidatePluginCredentialInfo, notify, t, handleSetDoingAction]) const { mutateAsync: updatePluginCredential } = useUpdatePluginCredentialHook(pluginPayload) const handleRename = useCallback(async (payload: { credential_id: string name: string }) => { - await updatePluginCredential(payload) - notify({ - type: 'success', - message: t('common.api.actionSuccess'), - }) - }, [updatePluginCredential, notify, t]) + if (doingActionRef.current) + return + try { + handleSetDoingAction(true) + await updatePluginCredential(payload) + notify({ + type: 'success', + message: t('common.api.actionSuccess'), + }) + invalidatePluginCredentialInfo() + } + finally { + handleSetDoingAction(false) + } + }, [updatePluginCredential, notify, t, handleSetDoingAction, invalidatePluginCredentialInfo]) return ( <> @@ -283,6 +313,7 @@ const Authorized = ({ @@ -298,7 +329,7 @@ const Authorized = ({ pendingOperationCredentialId.current = null }} onRemove={handleRemove} - disabled={disabled} + disabled={disabled || doingAction} /> ) }