diff --git a/web/app/(humanInputLayout)/form/[token]/form.tsx b/web/app/(humanInputLayout)/form/[token]/form.tsx
index e1455361fb..0853799ffb 100644
--- a/web/app/(humanInputLayout)/form/[token]/form.tsx
+++ b/web/app/(humanInputLayout)/form/[token]/form.tsx
@@ -11,6 +11,7 @@ import { useTranslation } from 'react-i18next'
import AppIcon from '@/app/components/base/app-icon'
import Button from '@/app/components/base/button'
import ContentItem from '@/app/components/base/chat/chat/answer/human-input-content/content-item'
+import ExpirationTime from '@/app/components/base/chat/chat/answer/human-input-content/expiration-time'
import Loading from '@/app/components/base/loading'
import DifyLogo from '@/app/components/base/logo/dify-logo'
import { UserActionButtonType } from '@/app/components/workflow/nodes/human-input/types'
@@ -24,8 +25,7 @@ export type FormData = {
form_content: string
inputs: FormInputItem[]
user_actions: UserAction[]
- timeout: number
- timeout_unit: 'hour' | 'day'
+ expiration_time: number
}
const FormContent = () => {
@@ -249,9 +249,7 @@ const FormContent = () => {
))}
-
- {formData.timeout_unit === 'day' ? t('share.humanInput.timeoutDay', { count: formData.timeout }) : t('share.humanInput.timeoutHour', { count: formData.timeout })}
-
+
{
+ const { t } = useTranslation()
+ const { locale } = useI18N()
+ const relativeTime = formatRelativeTimeInZone(expirationTime, locale)
+
+ return (
+
+ {t('share.humanInput.expirationTime', { relativeTime })}
+
+ )
+}
+
+export default ExpirationTime
diff --git a/web/app/components/base/chat/chat/answer/human-input-content/human-input-form.tsx b/web/app/components/base/chat/chat/answer/human-input-content/human-input-form.tsx
index 72b66173bc..a05b29a018 100644
--- a/web/app/components/base/chat/chat/answer/human-input-content/human-input-form.tsx
+++ b/web/app/components/base/chat/chat/answer/human-input-content/human-input-form.tsx
@@ -2,20 +2,17 @@
import type { HumanInputFormProps } from './type'
import * as React from 'react'
import { useCallback, useState } from 'react'
-import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
import ContentItem from './content-item'
+import ExpirationTime from './expiration-time'
import { getButtonStyle, initializeInputs, splitByOutputVar } from './utils'
const HumanInputForm = ({
formData,
showTimeout,
- timeout,
- timeoutUnit,
onSubmit,
+ expirationTime,
}: HumanInputFormProps) => {
- const { t } = useTranslation()
-
const formID = formData.form_id
const defaultInputs = initializeInputs(formData.inputs)
const contentList = splitByOutputVar(formData.form_content)
@@ -59,10 +56,8 @@ const HumanInputForm = ({
))}
- {showTimeout && (
-
- {timeoutUnit === 'day' ? t('share.humanInput.timeoutDay', { count: timeout }) : t('share.humanInput.timeoutHour', { count: timeout })}
-
+ {showTimeout && typeof expirationTime === 'number' && (
+
)}
>
)
diff --git a/web/app/components/base/chat/chat/answer/human-input-content/type.ts b/web/app/components/base/chat/chat/answer/human-input-content/type.ts
index 9687ff52ef..563b24c005 100644
--- a/web/app/components/base/chat/chat/answer/human-input-content/type.ts
+++ b/web/app/components/base/chat/chat/answer/human-input-content/type.ts
@@ -12,16 +12,14 @@ export type HumanInputContentProps = {
showEmailTip?: boolean
showDebugModeTip?: boolean
showTimeout?: boolean
- timeout?: number
- timeoutUnit?: 'hour' | 'day'
+ expirationTime?: number
onSubmit?: (formID: string, data: any) => Promise
}
export type HumanInputFormProps = {
formData: HumanInputFormData
showTimeout?: boolean
- timeout?: number
- timeoutUnit?: 'hour' | 'day'
+ expirationTime?: number
onSubmit?: (formID: string, data: any) => Promise
}
diff --git a/web/app/components/base/chat/chat/answer/human-input-content/utils.ts b/web/app/components/base/chat/chat/answer/human-input-content/utils.ts
index 9408dd94d1..d00633a940 100644
--- a/web/app/components/base/chat/chat/answer/human-input-content/utils.ts
+++ b/web/app/components/base/chat/chat/answer/human-input-content/utils.ts
@@ -1,5 +1,15 @@
import type { FormInputItem } from '@/app/components/workflow/nodes/human-input/types'
+import type { Locale } from '@/i18n-config'
+import dayjs from 'dayjs'
+import relativeTime from 'dayjs/plugin/relativeTime'
+import utc from 'dayjs/plugin/utc'
import { UserActionButtonType } from '@/app/components/workflow/nodes/human-input/types'
+import 'dayjs/locale/en'
+import 'dayjs/locale/zh-cn'
+import 'dayjs/locale/ja'
+
+dayjs.extend(utc)
+dayjs.extend(relativeTime)
export const getButtonStyle = (style: UserActionButtonType) => {
if (style === UserActionButtonType.Primary)
@@ -28,3 +38,21 @@ export const initializeInputs = (formInputs: FormInputItem[]) => {
})
return initialInputs
}
+
+const localeMap: Record = {
+ 'en-US': 'en',
+ 'zh-Hans': 'zh-cn',
+ 'ja-JP': 'ja',
+}
+
+export const formatRelativeTimeInZone = (
+ utcTimestamp: string | number,
+ locale: Locale = 'en-US',
+) => {
+ const dayjsLocale = localeMap[locale] ?? 'en'
+
+ return dayjs
+ .utc(utcTimestamp)
+ .locale(dayjsLocale)
+ .fromNow()
+}
diff --git a/web/i18n/en-US/share.ts b/web/i18n/en-US/share.ts
index a7aa965a0e..6fff1b9bb2 100644
--- a/web/i18n/en-US/share.ts
+++ b/web/i18n/en-US/share.ts
@@ -82,14 +82,13 @@ const translation = {
backToHome: 'Back to Home',
},
humanInput: {
- timeoutDay: 'This action will expire in {{count}} days.',
- timeoutHour: 'This action will expire in {{count}} hours.',
+ expirationTime: 'This action will expire {{relativeTime}}.',
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. ',
+ expired: 'Seems like this request has expired.',
+ completed: 'Seems like this request was dealt with elsewhere.',
},
}
diff --git a/web/i18n/ja-JP/share.ts b/web/i18n/ja-JP/share.ts
index 07d6ae3e45..54bdfc48ec 100644
--- a/web/i18n/ja-JP/share.ts
+++ b/web/i18n/ja-JP/share.ts
@@ -77,6 +77,14 @@ const translation = {
login: {
backToHome: 'ホームに戻る',
},
+ humanInput: {
+ expirationTime: 'この操作は{{relativeTime}}で期限切れになります。',
+ thanks: 'ありがとうございます!',
+ sorry: '申し訳ありません!',
+ recorded: '入力内容は記録されました。',
+ expired: 'このリクエストは期限切れのようです。',
+ completed: 'このリクエストは他の場所で処理されたようです。',
+ },
}
export default translation
diff --git a/web/i18n/zh-Hans/share.ts b/web/i18n/zh-Hans/share.ts
index 876d59267b..b06bdfc4bc 100644
--- a/web/i18n/zh-Hans/share.ts
+++ b/web/i18n/zh-Hans/share.ts
@@ -78,8 +78,7 @@ const translation = {
backToHome: '返回首页',
},
humanInput: {
- timeoutDay: '此操作将在 {{count}} 天后过期。',
- timeoutHour: '此操作将在 {{count}} 小时后过期。',
+ expirationTime: '此操作将在{{relativeTime}}过期。',
thanks: '谢谢!',
sorry: '抱歉!',
recorded: '您的输入已被记录。',
diff --git a/web/service/share.ts b/web/service/share.ts
index 8c39cc765f..fa72d2cf2e 100644
--- a/web/service/share.ts
+++ b/web/service/share.ts
@@ -333,8 +333,7 @@ export const getHumanInputForm = (token: string) => {
form_content: string
inputs: FormInputItem[]
user_actions: UserAction[]
- timeout: number
- timeout_unit: 'hour' | 'day'
+ expiration_time: number
}>(`/api/form/human_input/${token}`)
}