diff --git a/web/app/components/workflow/nodes/_base/components/before-run-form/index.tsx b/web/app/components/workflow/nodes/_base/components/before-run-form/index.tsx index b9af38610d..4e769c2e69 100644 --- a/web/app/components/workflow/nodes/_base/components/before-run-form/index.tsx +++ b/web/app/components/workflow/nodes/_base/components/before-run-form/index.tsx @@ -33,7 +33,9 @@ export type BeforeRunFormProps = { existVarValuesInForms: Record[] filteredExistVarForms: FormProps[] generatedFormContentData?: Record - setSubmittedData?: (data: Record) => void + showGeneratedForm?: boolean + handleShowGeneratedForm?: (data: Record) => void + handleHideGeneratedForm?: () => void } & Partial function formatValue(value: string | any, type: InputVarType) { @@ -70,7 +72,9 @@ const BeforeRunForm: FC = ({ filteredExistVarForms, existVarValuesInForms, generatedFormContentData, - setSubmittedData, + showGeneratedForm = false, + handleShowGeneratedForm, + handleHideGeneratedForm, }) => { const { t } = useTranslation() @@ -143,7 +147,7 @@ const BeforeRunForm: FC = ({ } if (isHumanInput) - setSubmittedData?.(submitData) + handleShowGeneratedForm?.(submitData) else onRun(submitData) } @@ -167,7 +171,7 @@ const BeforeRunForm: FC = ({ onHide={onHide} >
- {!generatedFormContentData && ( + {!showGeneratedForm && (
{filteredExistVarForms.map((form, index) => (
@@ -181,21 +185,29 @@ const BeforeRunForm: FC = ({ ))}
)} - {generatedFormContentData && ( - + {showGeneratedForm && generatedFormContentData && ( + + )} + {!showGeneratedForm && ( +
+ {!isHumanInput && ( + + )} + {isHumanInput && ( + + )} +
)} -
- {!isHumanInput && ( - - )} - {isHumanInput && ( - - )} -
) diff --git a/web/app/components/workflow/nodes/human-input/components/single-run-form.tsx b/web/app/components/workflow/nodes/human-input/components/single-run-form.tsx index 5000f38443..d51015a59d 100644 --- a/web/app/components/workflow/nodes/human-input/components/single-run-form.tsx +++ b/web/app/components/workflow/nodes/human-input/components/single-run-form.tsx @@ -1,60 +1,31 @@ 'use client' -import React, { useEffect, useState } from 'react' +import React, { useState } from 'react' import { useTranslation } from 'react-i18next' -import useDocumentTitle from '@/hooks/use-document-title' -import { useParams } from 'next/navigation' -import { - RiCheckboxCircleFill, - RiInformation2Fill, -} from '@remixicon/react' -import Loading from '@/app/components/base/loading' -import AppIcon from '@/app/components/base/app-icon' +import { RiArrowLeftLine } from '@remixicon/react' + import Button from '@/app/components/base/button' -import DifyLogo from '@/app/components/base/logo/dify-logo' import ContentItem from '@/app/components/base/chat/chat/answer/human-input-content/content-item' import { UserActionButtonType } from '@/app/components/workflow/nodes/human-input/types' import type { GeneratedFormInputItem, UserAction } from '@/app/components/workflow/nodes/human-input/types' -import { getHumanInputForm, submitHumanInputForm } from '@/service/share' -import { asyncRunSafe } from '@/utils' -import cn from '@/utils/classnames' +// import cn from '@/utils/classnames' -export type FormData = { - site: any - form_content: string - inputs: GeneratedFormInputItem[] - user_actions: UserAction[] - timeout: number - timeout_unit: 'hour' | 'day' +type Props = { + nodeName: string + formContent: string + inputFields: GeneratedFormInputItem[] + userActions: UserAction[] + handleBack?: () => void } -const FormContent = () => { +const FormContent = ({ + nodeName, + formContent, + inputFields, + userActions, + handleBack, +}: Props) => { const { t } = useTranslation() - const { token } = useParams<{ token: string }>() - useDocumentTitle('') - - const [isLoading, setIsLoading] = useState(false) - const [isSubmitting, setIsSubmitting] = useState(false) - const [formData, setFormData] = useState() - const [contentList, setContentList] = useState([]) - const [inputs, setInputs] = useState({}) - const [success, setSuccess] = useState(false) - const [expired, setExpired] = useState(false) - const [submitted, setSubmitted] = useState(false) - - const site = formData?.site.site - - const getButtonStyle = (style: UserActionButtonType) => { - if (style === UserActionButtonType.Primary) - return 'primary' - if (style === UserActionButtonType.Default) - return 'secondary' - if (style === UserActionButtonType.Accent) - return 'secondary-accent' - if (style === UserActionButtonType.Ghost) - return 'ghost' - } - const splitByOutputVar = (content: string): string[] => { const outputVarRegex = /({{#\$output\.[^#]+#}})/g const parts = content.split(outputVarRegex) @@ -69,12 +40,22 @@ const FormContent = () => { else initialInputs[item.output_variable_name] = undefined }) - setInputs(initialInputs) + return initialInputs } - const initializeContentList = (formContent: string) => { - const parts = splitByOutputVar(formContent) - setContentList(parts) + const contentList = splitByOutputVar(formContent) + const defaultInputValues = initializeInputs(inputFields) + const [inputs, setInputs] = useState(defaultInputValues) + + const getButtonStyle = (style: UserActionButtonType) => { + if (style === UserActionButtonType.Primary) + return 'primary' + if (style === UserActionButtonType.Default) + return 'secondary' + if (style === UserActionButtonType.Accent) + return 'secondary-accent' + if (style === UserActionButtonType.Ghost) + return 'ghost' } // use immer @@ -85,180 +66,45 @@ const FormContent = () => { })) } - const getForm = async (token: string) => { - try { - const data = await getHumanInputForm(token) - setFormData(data) - initializeInputs(data.inputs) - initializeContentList(data.form_content) - setIsLoading(false) - } - catch (error) { - console.error(error) - } - } - const submit = async (actionID: string) => { - setIsSubmitting(true) - try { - await submitHumanInputForm(token, { inputs, action: actionID }) - setSuccess(true) - } - catch (e: any) { - if (e.status === 400) { - const [, errRespData] = await asyncRunSafe<{ error_code: string }>(e.json()) - const { error_code } = errRespData || {} - if (error_code === 'human_input_form_expired') - setExpired(true) - if (error_code === 'human_input_form_submitted') - setSubmitted(true) - } - } - finally { - setIsSubmitting(false) - } - } - - useEffect(() => { - getForm(token) - }, [token]) - - if (isLoading || !formData) { - return ( - - ) - } - - if (success) { - return ( -
-
-
-
- -
-
-
{t('share.humanInput.thanks')}
-
{t('share.humanInput.recorded')}
-
-
{t('share.humanInput.submissionID', { id: token })}
-
-
-
-
{t('share.chat.poweredBy')}
- -
-
-
-
- ) - } - - if (expired) { - return ( -
-
-
-
- -
-
-
{t('share.humanInput.sorry')}
-
{t('share.humanInput.expired')}
-
-
{t('share.humanInput.submissionID', { id: token })}
-
-
-
-
{t('share.chat.poweredBy')}
- -
-
-
-
- ) - } - - if (submitted) { - return ( -
-
-
-
- -
-
-
{t('share.humanInput.sorry')}
-
{t('share.humanInput.completed')}
-
-
{t('share.humanInput.submissionID', { id: token })}
-
-
-
-
{t('share.chat.poweredBy')}
- -
-
-
-
- ) + // TODO } return ( -
-
- -
{site.title}
-
-
-
- {contentList.map((content, index) => ( - + <> + {inputFields.length > 0 && ( +
+
+ + {t('workflow.nodes.humanInput.singleRun.back')} +
+
/
+
{nodeName}
+
+ )} +
+ {contentList.map((content, index) => ( + + ))} +
+ {userActions.map((action: any) => ( + ))} -
- {formData.user_actions.map((action: any) => ( - - ))} -
-
- {formData.timeout_unit === 'day' ? t('share.humanInput.timeoutDay', { count: formData.timeout }) : t('share.humanInput.timeoutHour', { count: formData.timeout })} -
-
-
-
-
{t('share.chat.poweredBy')}
- -
-
+ ) } diff --git a/web/app/components/workflow/nodes/human-input/use-single-run-form-params.ts b/web/app/components/workflow/nodes/human-input/use-single-run-form-params.ts index 4fe0c1be54..9d65e77926 100644 --- a/web/app/components/workflow/nodes/human-input/use-single-run-form-params.ts +++ b/web/app/components/workflow/nodes/human-input/use-single-run-form-params.ts @@ -25,6 +25,7 @@ const useSingleRunFormParams = ({ const { t } = useTranslation() const { inputs } = useNodeCrud(id, payload) const [submittedData, setSubmittedData] = useState | null>(null) + const [showGeneratedForm, setShowGeneratedForm] = useState(false) const generatedInputs = useMemo(() => { if (!inputs.form_content) return [] @@ -71,28 +72,43 @@ const useSingleRunFormParams = ({ return null if (!generatedInputs.length) { return { - content: inputs.form_content, + formContent: inputs.form_content, inputFields: formContentOutputFields, + userActions: inputs.user_actions, } } else { if (!submittedData) return null const newContent = inputs.form_content.replace(/{{#(.*?)#}}/g, (originStr, varName) => { - return submittedData[varName] || isOutput(varName.split('.')) ? originStr : '' + if (isOutput(varName.split('.'))) + return originStr + return submittedData[`#${varName}#`] ?? '' }) return { - content: newContent, + formContent: newContent, inputFields: formContentOutputFields, + userActions: inputs.user_actions, } } - }, [inputs.form_content, submittedData, formContentOutputFields]) + }, [inputs.form_content, inputs.user_actions, submittedData, formContentOutputFields]) + + const handleShowGeneratedForm = (formValue: Record) => { + setSubmittedData(formValue) + setShowGeneratedForm(true) + } + + const handleHideGeneratedForm = () => { + setShowGeneratedForm(false) + } return { forms, getDependentVars, generatedFormContentData, - setSubmittedData, + showGeneratedForm, + handleShowGeneratedForm, + handleHideGeneratedForm, } } diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index 503dadf906..ca06c1db29 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -1030,6 +1030,7 @@ const translation = { singleRun: { label: 'Form variables', button: 'Generate Form', + back: 'Back', }, }, }, diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index ec7dc92f7f..5655c15300 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -1030,6 +1030,7 @@ const translation = { singleRun: { label: '表单变量', button: '生成表单', + back: '返回', }, }, },