diff --git a/web/app/(humanInputLayout)/form/[token]/form.tsx b/web/app/(humanInputLayout)/form/[token]/form.tsx
new file mode 100644
index 0000000000..55292af07f
--- /dev/null
+++ b/web/app/(humanInputLayout)/form/[token]/form.tsx
@@ -0,0 +1,166 @@
+'use client'
+import React 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 AppIcon from '@/app/components/base/app-icon'
+import { Markdown } from '@/app/components/base/markdown'
+import Button, { } from '@/app/components/base/button'
+import DifyLogo from '@/app/components/base/logo/dify-logo'
+import { UserActionButtonType } from '@/app/components/workflow/nodes/human-input/types'
+
+import cn from '@/utils/classnames'
+
+import { MOCK_DATA } from './mock'
+
+const success = true
+
+const expired = true
+
+const submitted = true
+
+const FormContent = () => {
+ const { t } = useTranslation()
+
+ const { token } = useParams()
+ useDocumentTitle('')
+
+ const { site } = MOCK_DATA.site
+ const { form_content, user_actions, timeout, timeout_unit } = MOCK_DATA
+
+ 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'
+ }
+
+ 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')}
+
+
+
+
+
+ )
+ }
+
+ return (
+
+
+
+
+
+
+ {user_actions.map((action: any) => (
+
+ ))}
+
+
+ {timeout_unit === 'day' ? t('share.humanInput.timeoutDay', { count: timeout }) : t('share.humanInput.timeoutHour', { count: timeout })}
+
+
+
+
+
{t('share.chat.poweredBy')}
+
+
+
+
+
+ )
+}
+
+export default React.memo(FormContent)
diff --git a/web/app/(humanInputLayout)/form/[token]/mock.ts b/web/app/(humanInputLayout)/form/[token]/mock.ts
new file mode 100644
index 0000000000..e1fb770d3e
--- /dev/null
+++ b/web/app/(humanInputLayout)/form/[token]/mock.ts
@@ -0,0 +1,81 @@
+import { UserActionButtonType } from '@/app/components/workflow/nodes/human-input/types'
+
+export const MOCK_DATA = {
+ site: {
+ app_id: 'e9823576-d836-4f2b-b46f-bd4df1d82230',
+ end_user_id: 'b7aa295d-1560-4d87-a828-77b3f39b30d0',
+ enable_site: true,
+ site: {
+ title: 'wf',
+ chat_color_theme: null,
+ chat_color_theme_inverted: false,
+ icon_type: 'emoji',
+ icon: '\uD83E\uDD16',
+ icon_background: '#FFEAD5',
+ icon_url: null,
+ description: null,
+ copyright: null,
+ privacy_policy: null,
+ custom_disclaimer: '',
+ default_language: 'en-US',
+ prompt_public: false,
+ show_workflow_steps: true,
+ use_icon_as_answer_icon: false,
+ },
+ model_config: null,
+ plan: 'basic',
+ can_replace_logo: false,
+ custom_config: null,
+ },
+ // 采用与上方 form editor 相同的数据结构,唯一不同的就是
+ // 对于 Text 类型,其文本已完成了变量替换(即,所有使用
+ // {{#node_name.var_name#}} 格式引用其他变量的位置,都
+ // 被替换成了对应的变量的值)
+ //
+ // 参考 FormContent
+ form_content: `
+ # Experiencing the Four Seasons
+ 
+
+ ## My Seasonal Guide
+ Name: {{#noddename.name#}}
+ Location: {{#nodename.location#}}
+ Favorite Season: {{#nodename.season#}}
+
+ The four seasons throughout the year:
+ - Spring: Cherry blossoms, returning birds
+ - Summer: Long sunny days, thunderstorms, beach adventures
+ - Autumn: Red and gold foliage, harvest festivals, apple picking
+ - Winter: Snowfall, frozen lakes, holiday celebrations
+ ## Notes
+
+ {{#$output.content#}}
+ `,
+ // 对每一个字段的描述,参考上方 FormInput 的定义。
+ inputs: [''],
+ // 用户对这个表单可采取的操作,参考上方 UserAction 的定义。
+ user_actions: [
+ {
+ id: 'approve-action',
+ title: 'Post to X',
+ button_style: UserActionButtonType.Primary,
+ },
+ {
+ id: 'regenerate-action',
+ title: 'regenerate',
+ button_style: UserActionButtonType.Default,
+ },
+ {
+ id: 'thinking-action',
+ title: 'thinking',
+ button_style: UserActionButtonType.Accent,
+ },
+ {
+ id: 'cancel-action',
+ title: 'cancel',
+ button_style: UserActionButtonType.Ghost,
+ },
+ ],
+ timeout: 3,
+ timeout_unit: 'day',
+}
diff --git a/web/app/(humanInputLayout)/form/[token]/page.tsx b/web/app/(humanInputLayout)/form/[token]/page.tsx
new file mode 100644
index 0000000000..8f736df638
--- /dev/null
+++ b/web/app/(humanInputLayout)/form/[token]/page.tsx
@@ -0,0 +1,13 @@
+'use client'
+import React from 'react'
+import FormContent from './form'
+
+const FormPage = () => {
+ return (
+
+
+
+ )
+}
+
+export default React.memo(FormPage)
diff --git a/web/i18n/en-US/share.ts b/web/i18n/en-US/share.ts
index ab589ffb76..4934e1a481 100644
--- a/web/i18n/en-US/share.ts
+++ b/web/i18n/en-US/share.ts
@@ -80,6 +80,16 @@ const translation = {
login: {
backToHome: 'Back to Home',
},
+ humanInput: {
+ timeoutDay: 'This action will expire in {{count}} days.',
+ timeoutHour: 'This action will expire in {{count}} hours.',
+ submissionID: 'submission_id: {{id}}',
+ thanks: 'Thanks!',
+ sorry: 'Sorry!',
+ recorded: 'Your input has been recorded.',
+ expired: 'Seems like this request has expired. ',
+ completed: 'Seems like this request was dealt with elsewhere. ',
+ },
}
export default translation
diff --git a/web/i18n/zh-Hans/share.ts b/web/i18n/zh-Hans/share.ts
index ce1270dae8..4df2bde11b 100644
--- a/web/i18n/zh-Hans/share.ts
+++ b/web/i18n/zh-Hans/share.ts
@@ -76,6 +76,15 @@ const translation = {
login: {
backToHome: '返回首页',
},
+ humanInput: {
+ timeoutDay: '此操作将在 {{count}} 天后过期。',
+ timeoutHour: '此操作将在 {{count}} 小时后过期。',
+ thanks: '谢谢!',
+ sorry: '抱歉!',
+ recorded: '您的输入已被记录。',
+ expired: '此请求似乎已过期。',
+ completed: '此请求似乎在其他地方得到了处理。',
+ },
}
export default translation