diff --git a/web/app/components/base/chat/chat/chat-input-area/index.tsx b/web/app/components/base/chat/chat/chat-input-area/index.tsx index 8a1289a19e..0f3f135a93 100644 --- a/web/app/components/base/chat/chat/chat-input-area/index.tsx +++ b/web/app/components/base/chat/chat/chat-input-area/index.tsx @@ -34,6 +34,7 @@ type ChatInputAreaProps = { visionConfig?: FileUpload speechToTextConfig?: EnableType onSend?: OnSend + onSendCheck?: () => boolean theme?: Theme | null } const ChatInputArea = ({ @@ -44,6 +45,7 @@ const ChatInputArea = ({ visionConfig, speechToTextConfig = { enabled: true }, onSend, + onSendCheck = () => true, // theme, }: ChatInputAreaProps) => { const { t } = useTranslation() @@ -80,9 +82,11 @@ const ChatInputArea = ({ notify({ type: 'info', message: t('appAnnotation.errorMessage.queryRequired') }) return } - onSend(query, files) - setQuery('') - setFiles([]) + if (onSendCheck()) { + onSend(query, files) + setQuery('') + setFiles([]) + } } } diff --git a/web/app/components/base/chat/chat/index.tsx b/web/app/components/base/chat/chat/index.tsx index 7203f1e059..c4939ee528 100644 --- a/web/app/components/base/chat/chat/index.tsx +++ b/web/app/components/base/chat/chat/index.tsx @@ -43,6 +43,7 @@ export type ChatProps = { onStopResponding?: () => void noChatInput?: boolean onSend?: OnSend + onSendCheck?: () => boolean onRegenerate?: OnRegenerate chatContainerClassName?: string chatContainerInnerClassName?: string @@ -72,6 +73,7 @@ const Chat: FC = ({ appData, config, onSend, + onSendCheck, onRegenerate, chatList, isResponding, @@ -281,6 +283,7 @@ const Chat: FC = ({ visionConfig={config?.file_upload} speechToTextConfig={config?.speech_to_text} onSend={onSend} + onSendCheck={onSendCheck} theme={themeBuilder?.theme} /> ) diff --git a/web/app/components/workflow/hooks/index.ts b/web/app/components/workflow/hooks/index.ts index 463e9b3271..afea0116ea 100644 --- a/web/app/components/workflow/hooks/index.ts +++ b/web/app/components/workflow/hooks/index.ts @@ -16,3 +16,4 @@ export * from './use-workflow-variables' export * from './use-shortcuts' export * from './use-workflow-interactions' export * from './use-workflow-mode' +export * from './use-check-start-node-form' diff --git a/web/app/components/workflow/hooks/use-check-start-node-form.ts b/web/app/components/workflow/hooks/use-check-start-node-form.ts new file mode 100644 index 0000000000..e5ad9710ca --- /dev/null +++ b/web/app/components/workflow/hooks/use-check-start-node-form.ts @@ -0,0 +1,46 @@ +import { useCallback } from 'react' +import { useTranslation } from 'react-i18next' +import { useStoreApi } from 'reactflow' +import { useWorkflowStore } from '@/app/components/workflow/store' +import { BlockEnum } from '@/app/components/workflow/types' +import { useToastContext } from '@/app/components/base/toast' +import type { InputVar } from '@/app/components/workflow/types' + +export const useCheckStartNodeForm = () => { + const { t } = useTranslation() + const storeApi = useStoreApi() + const workflowStore = useWorkflowStore() + const { notify } = useToastContext() + + const checkStartNodeForm = useCallback(() => { + const { getNodes } = storeApi.getState() + const nodes = getNodes() + const startNode = nodes.find(node => node.data.type === BlockEnum.Start) + const variables: InputVar[] = startNode?.data.variables || [] + const inputs = workflowStore.getState().inputs + + let hasEmptyInput = '' + const requiredVars = variables.filter(({ required }) => required) + + if (requiredVars?.length) { + requiredVars.forEach(({ variable, label }) => { + if (hasEmptyInput) + return + + if (!inputs[variable]) + hasEmptyInput = label as string + }) + } + + if (hasEmptyInput) { + notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }) }) + return false + } + + return true + }, [storeApi, workflowStore, notify, t]) + + return { + checkStartNodeForm, + } +} diff --git a/web/app/components/workflow/panel/debug-and-preview/chat-wrapper.tsx b/web/app/components/workflow/panel/debug-and-preview/chat-wrapper.tsx index 917a378f32..a8094ba0be 100644 --- a/web/app/components/workflow/panel/debug-and-preview/chat-wrapper.tsx +++ b/web/app/components/workflow/panel/debug-and-preview/chat-wrapper.tsx @@ -12,6 +12,7 @@ import { useStore, useWorkflowStore, } from '../../store' +import { useCheckStartNodeForm } from '../../hooks' import type { StartNodeType } from '../../nodes/start/types' import Empty from './empty' import UserInput from './user-input' @@ -61,6 +62,7 @@ const ChatWrapper = forwardRef(({ } }, [features.opening, features.suggested, features.text2speech, features.speech2text, features.citation, features.moderation, features.file]) const setShowFeaturesPanel = useStore(s => s.setShowFeaturesPanel) + const { checkStartNodeForm } = useCheckStartNodeForm() const { conversationId, @@ -141,6 +143,7 @@ const ChatWrapper = forwardRef(({ showFeatureBar onFeatureBarClick={setShowFeaturesPanel} onSend={doSend} + onSendCheck={checkStartNodeForm} onRegenerate={doRegenerate} onStopResponding={handleStop} chatNode={(