mirror of https://github.com/langgenius/dify.git
refactor: update human input form handling to support async submission and improve placeholder resolution
This commit is contained in:
parent
ddfd1cb1f5
commit
3c0fd213bf
|
|
@ -1,111 +1,60 @@
|
|||
import React from 'react'
|
||||
import React, { useMemo } from 'react'
|
||||
import { Markdown } from '@/app/components/base/markdown'
|
||||
import Select from '@/app/components/base/select'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
import Input from '@/app/components/base/input'
|
||||
import FormInputBoolean from '@/app/components/workflow/nodes/_base/components/form-input-boolean'
|
||||
import { FileUploaderInAttachmentWrapper } from '@/app/components/base/file-uploader'
|
||||
import { getProcessedFiles } from '@/app/components/base/file-uploader/utils'
|
||||
import { DEFAULT_VALUE_MAX_LEN } from '@/config'
|
||||
import type { GeneratedFormInputItem } from '@/app/components/workflow/nodes/human-input/types'
|
||||
import type { ContentItemProps } from './type'
|
||||
|
||||
type Props = {
|
||||
content: string
|
||||
formInputFields: GeneratedFormInputItem[]
|
||||
inputs: Record<string, any>
|
||||
onInputChange: (name: string, value: any) => void
|
||||
}
|
||||
|
||||
const ContentItem = ({ content, formInputFields, inputs, onInputChange }: Props) => {
|
||||
const ContentItem = ({
|
||||
content,
|
||||
formInputFields,
|
||||
inputs,
|
||||
resolvedPlaceholderValues,
|
||||
onInputChange,
|
||||
}: ContentItemProps) => {
|
||||
const isInputField = (field: string) => {
|
||||
const outputVarRegex = /{{#\$output\.[^#]+#}}/
|
||||
return outputVarRegex.test(field)
|
||||
}
|
||||
|
||||
const extractFieldName = (str: string) => {
|
||||
const extractFieldName = (str: string): string => {
|
||||
const outputVarRegex = /{{#\$output\.([^#]+)#}}/
|
||||
const match = str.match(outputVarRegex)
|
||||
return match ? match[1] : ''
|
||||
}
|
||||
|
||||
const fieldName = useMemo(() => {
|
||||
return extractFieldName(content)
|
||||
}, [content])
|
||||
|
||||
const formInputField = useMemo(() => {
|
||||
return formInputFields.find(field => field.output_variable_name === fieldName)
|
||||
}, [formInputFields, fieldName])
|
||||
|
||||
const placeholder = useMemo(() => {
|
||||
return formInputField?.placeholder.type === 'variable'
|
||||
? resolvedPlaceholderValues?.[fieldName]
|
||||
: formInputField?.placeholder.value
|
||||
}, [formInputField, resolvedPlaceholderValues, fieldName])
|
||||
|
||||
if (!isInputField(content)) {
|
||||
return (
|
||||
<Markdown content={content} />
|
||||
)
|
||||
}
|
||||
|
||||
const fieldName = extractFieldName(content)
|
||||
const formInputField = formInputFields.find(field => field.output_variable_name === fieldName)
|
||||
|
||||
if (!formInputField) return null
|
||||
|
||||
return (
|
||||
<div className='py-3'>
|
||||
{formInputField.type === 'select' && (
|
||||
<Select
|
||||
className='w-full'
|
||||
defaultValue={inputs[fieldName]}
|
||||
onSelect={i => onInputChange(fieldName, i.value)}
|
||||
items={(formInputField.options || []).map(i => ({ name: i, value: i }))}
|
||||
allowSearch={false}
|
||||
/>
|
||||
)}
|
||||
{formInputField.type === 'text-input' && (
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={formInputField.placeholder}
|
||||
value={inputs[fieldName]}
|
||||
onChange={(e) => { onInputChange(fieldName, e.target.value) }}
|
||||
maxLength={formInputField.max_length || DEFAULT_VALUE_MAX_LEN}
|
||||
/>
|
||||
)}
|
||||
{formInputField.type === 'paragraph' && (
|
||||
<Textarea
|
||||
className='h-[104px] sm:text-xs'
|
||||
placeholder={formInputField.placeholder}
|
||||
placeholder={placeholder}
|
||||
value={inputs[fieldName]}
|
||||
onChange={(e) => { onInputChange(fieldName, e.target.value) }}
|
||||
/>
|
||||
)}
|
||||
{formInputField.type === 'number' && (
|
||||
<Input
|
||||
type="number"
|
||||
value={inputs[fieldName]}
|
||||
onChange={(e) => { onInputChange(fieldName, e.target.value) }}
|
||||
/>
|
||||
)}
|
||||
{formInputField.type === 'checkbox' && (
|
||||
<FormInputBoolean
|
||||
value={inputs[fieldName] as boolean}
|
||||
onChange={value => onInputChange(fieldName, value)}
|
||||
/>
|
||||
)}
|
||||
{formInputField.type === 'file' && (
|
||||
<FileUploaderInAttachmentWrapper
|
||||
onChange={(files) => { onInputChange(fieldName, getProcessedFiles(files)[0]) }}
|
||||
fileConfig={{
|
||||
number_limits: 1,
|
||||
allowed_file_extensions: formInputField.allowed_file_extensions,
|
||||
allowed_file_types: formInputField.allowed_file_types,
|
||||
allowed_file_upload_methods: formInputField.allowed_file_upload_methods as any,
|
||||
// fileUploadConfig: (visionConfig as any).fileUploadConfig,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{formInputField.type === 'file-list' && (
|
||||
<FileUploaderInAttachmentWrapper
|
||||
onChange={(files) => { onInputChange(fieldName, getProcessedFiles(files)) }}
|
||||
fileConfig={{
|
||||
number_limits: formInputField.max_length,
|
||||
allowed_file_extensions: formInputField.allowed_file_extensions,
|
||||
allowed_file_types: formInputField.allowed_file_types,
|
||||
allowed_file_upload_methods: formInputField.allowed_file_upload_methods as any,
|
||||
// fileUploadConfig: (visionConfig as any).fileUploadConfig,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ContentItem
|
||||
export default React.memo(ContentItem)
|
||||
|
|
|
|||
|
|
@ -1,32 +1,18 @@
|
|||
'use client'
|
||||
import React, { useState } from 'react'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import ContentItem from './content-item'
|
||||
import type { GeneratedFormInputItem, UserAction } from '@/app/components/workflow/nodes/human-input/types'
|
||||
import { getButtonStyle, initializeInputs, splitByOutputVar } from './utils'
|
||||
|
||||
export type FormData = {
|
||||
form_id: string
|
||||
site: any
|
||||
form_content: string
|
||||
inputs: GeneratedFormInputItem[]
|
||||
user_actions: UserAction[]
|
||||
timeout: number
|
||||
timeout_unit: 'hour' | 'day'
|
||||
}
|
||||
|
||||
export type Props = {
|
||||
formData: FormData
|
||||
showTimeout?: boolean
|
||||
onSubmit?: (formID: string, data: any) => void
|
||||
}
|
||||
import type { HumanInputFormProps } from './type'
|
||||
|
||||
const HumanInputForm = ({
|
||||
formData,
|
||||
showTimeout,
|
||||
timeout,
|
||||
timeoutUnit,
|
||||
onSubmit,
|
||||
}: Props) => {
|
||||
}: HumanInputFormProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const formID = formData.form_id
|
||||
|
|
@ -35,12 +21,12 @@ const HumanInputForm = ({
|
|||
const [inputs, setInputs] = useState(defaultInputs)
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
|
||||
const handleInputsChange = (name: string, value: any) => {
|
||||
const handleInputsChange = useCallback((name: string, value: any) => {
|
||||
setInputs(prev => ({
|
||||
...prev,
|
||||
[name]: value,
|
||||
}))
|
||||
}
|
||||
}, [])
|
||||
|
||||
const submit = async (formID: string, actionID: string, inputs: Record<string, any>) => {
|
||||
setIsSubmitting(true)
|
||||
|
|
@ -55,12 +41,13 @@ const HumanInputForm = ({
|
|||
key={index}
|
||||
content={content}
|
||||
formInputFields={formData.inputs}
|
||||
resolvedPlaceholderValues={formData.resolved_placeholder_values || {}}
|
||||
inputs={inputs}
|
||||
onInputChange={handleInputsChange}
|
||||
/>
|
||||
))}
|
||||
<div className='flex flex-wrap gap-1 py-1'>
|
||||
{formData.user_actions.map((action: any) => (
|
||||
{formData.actions.map((action: any) => (
|
||||
<Button
|
||||
key={action.id}
|
||||
disabled={isSubmitting}
|
||||
|
|
@ -73,7 +60,7 @@ const HumanInputForm = ({
|
|||
</div>
|
||||
{showTimeout && (
|
||||
<div className='system-xs-regular mt-1 text-text-tertiary'>
|
||||
{formData.timeout_unit === 'day' ? t('share.humanInput.timeoutDay', { count: formData.timeout }) : t('share.humanInput.timeoutHour', { count: formData.timeout })}
|
||||
{timeoutUnit === 'day' ? t('share.humanInput.timeoutDay', { count: timeout }) : t('share.humanInput.timeoutHour', { count: timeout })}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -1,40 +1,30 @@
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import HumanInputForm from './human-input-form'
|
||||
import type { FormData } from './human-input-form'
|
||||
import { useChatContext } from '../../context'
|
||||
import type { HumanInputFormData } from '@/types/workflow'
|
||||
import type { DeliveryMethod } from '@/app/components/workflow/nodes/human-input/types'
|
||||
import { DeliveryMethodType } from '@/app/components/workflow/nodes/human-input/types'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import type { HumanInputContentProps } from './type'
|
||||
|
||||
type Props = {
|
||||
formData: HumanInputFormData
|
||||
showTimeout?: boolean
|
||||
onSubmit?: (formID: string, data: any) => void
|
||||
}
|
||||
|
||||
const HumanInputContent = ({ formData, onSubmit }: Props) => {
|
||||
const HumanInputContent = ({
|
||||
formData,
|
||||
showEmailTip = false,
|
||||
showDebugModeTip = false,
|
||||
showTimeout = false,
|
||||
onSubmit,
|
||||
}: HumanInputContentProps) => {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
getHumanInputNodeData,
|
||||
} = useChatContext()
|
||||
|
||||
const deliveryMethodsConfig = getHumanInputNodeData?.(formData.node_id as any)?.data.delivery_methods || []
|
||||
const isWebappEnabled = deliveryMethodsConfig.some((method: DeliveryMethod) => method.type === DeliveryMethodType.WebApp && method.enabled)
|
||||
const isEmailEnabled = deliveryMethodsConfig.some((method: DeliveryMethod) => method.type === DeliveryMethodType.Email && method.enabled)
|
||||
|
||||
return (
|
||||
<>
|
||||
<HumanInputForm
|
||||
formData={formData as any as FormData}
|
||||
formData={formData}
|
||||
showTimeout={showTimeout}
|
||||
onSubmit={onSubmit}
|
||||
/>
|
||||
{(!isWebappEnabled || isEmailEnabled) && (
|
||||
{(showEmailTip || showDebugModeTip) && (
|
||||
<>
|
||||
<Divider className='!my-2 w-[30px]' />
|
||||
<div className='space-y-1 pt-1'>
|
||||
{isEmailEnabled && <div className='system-xs-regular text-text-secondary'>{t('humanInputEmailTip')}</div>}
|
||||
{!isWebappEnabled && <div className='system-xs-medium text-text-warning'>{t('humanInputWebappTip')}</div>}
|
||||
{showEmailTip && <div className='system-xs-regular text-text-secondary'>{t('humanInputEmailTip')}</div>}
|
||||
{showDebugModeTip && <div className='system-xs-medium text-text-warning'>{t('humanInputWebappTip')}</div>}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
import type { GeneratedFormInputItem } from '@/app/components/workflow/nodes/human-input/types'
|
||||
import type { HumanInputFormData } from '@/types/workflow'
|
||||
|
||||
export type ExecutedAction = {
|
||||
id: string
|
||||
title: string
|
||||
}
|
||||
|
||||
export type HumanInputContentProps = {
|
||||
formData: HumanInputFormData
|
||||
executedAction?: ExecutedAction
|
||||
showEmailTip?: boolean
|
||||
showDebugModeTip?: boolean
|
||||
showTimeout?: boolean
|
||||
timeout?: number
|
||||
timeoutUnit?: 'hour' | 'day'
|
||||
onSubmit?: (formID: string, data: any) => Promise<void>
|
||||
}
|
||||
|
||||
export type HumanInputFormProps = {
|
||||
formData: HumanInputFormData
|
||||
showTimeout?: boolean
|
||||
timeout?: number
|
||||
timeoutUnit?: 'hour' | 'day'
|
||||
onSubmit?: (formID: string, data: any) => Promise<void>
|
||||
}
|
||||
|
||||
export type ContentItemProps = {
|
||||
content: string
|
||||
formInputFields: GeneratedFormInputItem[]
|
||||
inputs: Record<string, string>
|
||||
resolvedPlaceholderValues?: Record<string, string>
|
||||
onInputChange: (name: string, value: any) => void
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { UserActionButtonType } from '@/app/components/workflow/nodes/human-input/types'
|
||||
import type { GeneratedFormInputItem } from '@/app/components/workflow/nodes/human-input/types'
|
||||
import { UserActionButtonType } from '@/app/components/workflow/nodes/human-input/types'
|
||||
|
||||
export const getButtonStyle = (style: UserActionButtonType) => {
|
||||
if (style === UserActionButtonType.Primary)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type {
|
|||
FC,
|
||||
ReactNode,
|
||||
} from 'react'
|
||||
import { memo, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type {
|
||||
ChatConfig,
|
||||
|
|
@ -23,6 +23,9 @@ import { cn } from '@/utils/classnames'
|
|||
import { FileList } from '@/app/components/base/file-uploader'
|
||||
import ContentSwitch from '../content-switch'
|
||||
import HumanInputContent from './human-input-content'
|
||||
import { useChatContext } from '../context'
|
||||
import type { DeliveryMethod } from '@/app/components/workflow/nodes/human-input/types'
|
||||
import { DeliveryMethodType } from '@/app/components/workflow/nodes/human-input/types'
|
||||
|
||||
type AnswerProps = {
|
||||
item: ChatItem
|
||||
|
|
@ -38,7 +41,7 @@ type AnswerProps = {
|
|||
noChatInput?: boolean
|
||||
switchSibling?: (siblingMessageId: string) => void
|
||||
hideAvatar?: boolean
|
||||
onHumanInputFormSubmit?: (formID: string, formData: any) => void
|
||||
onHumanInputFormSubmit?: (formID: string, formData: any) => Promise<void>
|
||||
}
|
||||
const Answer: FC<AnswerProps> = ({
|
||||
item,
|
||||
|
|
@ -75,6 +78,26 @@ const Answer: FC<AnswerProps> = ({
|
|||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const contentRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const {
|
||||
getHumanInputNodeData,
|
||||
} = useChatContext()
|
||||
|
||||
const deliveryMethodsConfig = useMemo(() => {
|
||||
const deliveryMethodsConfig = getHumanInputNodeData?.(humanInputFormData?.node_id as any)?.data.delivery_methods || []
|
||||
if (!deliveryMethodsConfig.length) {
|
||||
return {
|
||||
showEmailTip: false,
|
||||
showDebugModeTip: false,
|
||||
}
|
||||
}
|
||||
const isWebappEnabled = deliveryMethodsConfig.some((method: DeliveryMethod) => method.type === DeliveryMethodType.WebApp && method.enabled)
|
||||
const isEmailEnabled = deliveryMethodsConfig.some((method: DeliveryMethod) => method.type === DeliveryMethodType.Email && method.enabled)
|
||||
return {
|
||||
showEmailTip: isEmailEnabled,
|
||||
showDebugModeTip: !isWebappEnabled,
|
||||
}
|
||||
}, [getHumanInputNodeData, humanInputFormData?.node_id])
|
||||
|
||||
const getContainerWidth = () => {
|
||||
if (containerRef.current)
|
||||
setContainerWidth(containerRef.current?.clientWidth + 16)
|
||||
|
|
@ -176,7 +199,9 @@ const Answer: FC<AnswerProps> = ({
|
|||
}
|
||||
{humanInputFormData && (
|
||||
<HumanInputContent
|
||||
formData={humanInputFormData as any} // TODO type
|
||||
formData={humanInputFormData}
|
||||
showEmailTip={deliveryMethodsConfig.showEmailTip}
|
||||
showDebugModeTip={deliveryMethodsConfig.showDebugModeTip}
|
||||
onSubmit={onHumanInputFormSubmit}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ export type ChatProps = {
|
|||
inputDisabled?: boolean
|
||||
sidebarCollapseState?: boolean
|
||||
hideAvatar?: boolean
|
||||
onHumanInputFormSubmit?: (formID: string, formData: any) => void
|
||||
onHumanInputFormSubmit?: (formID: string, formData: any) => Promise<void>
|
||||
getHumanInputNodeData?: (nodeID: string) => any
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,11 +77,9 @@ export type UserAction = {
|
|||
export type GeneratedFormInputItem = {
|
||||
type: InputVarType
|
||||
output_variable_name: string
|
||||
// only text-input and paragraph support placeholder
|
||||
placeholder?: string
|
||||
options: any[]
|
||||
max_length: number
|
||||
allowed_file_extensions?: string[]
|
||||
allowed_file_types?: string[]
|
||||
allowed_file_upload_methods?: string[]
|
||||
placeholder: {
|
||||
selector: ValueSelector
|
||||
type: 'variable' | 'constant'
|
||||
value: string
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ export const handleStream = (
|
|||
else if (bufferObj.event === 'human_input_required') {
|
||||
onHumanInputRequired?.(bufferObj as HumanInputRequiredResponse)
|
||||
}
|
||||
else if (bufferObj.event === 'workflow_suspended') {
|
||||
else if (bufferObj.event === 'workflow_paused') {
|
||||
onWorkflowSuspended?.(bufferObj as WorkflowSuspendedResponse)
|
||||
}
|
||||
else if (bufferObj.event === 'datasource_processing') {
|
||||
|
|
@ -656,44 +656,46 @@ export const sseGet = async (
|
|||
}
|
||||
return
|
||||
}
|
||||
return handleStream(res, (str: string, isFirstMessage: boolean, moreInfo: IOnDataMoreInfo) => {
|
||||
if (moreInfo.errorMessage) {
|
||||
onError?.(moreInfo.errorMessage, moreInfo.errorCode)
|
||||
// TypeError: Cannot assign to read only property ... will happen in page leave, so it should be ignored.
|
||||
if (moreInfo.errorMessage !== 'AbortError: The user aborted a request.' && !moreInfo.errorMessage.includes('TypeError: Cannot assign to read only property'))
|
||||
Toast.notify({ type: 'error', message: moreInfo.errorMessage })
|
||||
return
|
||||
}
|
||||
onData?.(str, isFirstMessage, moreInfo)
|
||||
},
|
||||
onCompleted,
|
||||
onThought,
|
||||
onMessageEnd,
|
||||
onMessageReplace,
|
||||
onFile,
|
||||
onWorkflowStarted,
|
||||
onWorkflowFinished,
|
||||
onNodeStarted,
|
||||
onNodeFinished,
|
||||
onIterationStart,
|
||||
onIterationNext,
|
||||
onIterationFinish,
|
||||
onLoopStart,
|
||||
onLoopNext,
|
||||
onLoopFinish,
|
||||
onNodeRetry,
|
||||
onParallelBranchStarted,
|
||||
onParallelBranchFinished,
|
||||
onTextChunk,
|
||||
onTTSChunk,
|
||||
onTTSEnd,
|
||||
onTextReplace,
|
||||
onAgentLog,
|
||||
onHumanInputRequired,
|
||||
onWorkflowSuspended,
|
||||
onDataSourceNodeProcessing,
|
||||
onDataSourceNodeCompleted,
|
||||
onDataSourceNodeError,
|
||||
return handleStream(
|
||||
res,
|
||||
(str: string, isFirstMessage: boolean, moreInfo: IOnDataMoreInfo) => {
|
||||
if (moreInfo.errorMessage) {
|
||||
onError?.(moreInfo.errorMessage, moreInfo.errorCode)
|
||||
// TypeError: Cannot assign to read only property ... will happen in page leave, so it should be ignored.
|
||||
if (moreInfo.errorMessage !== 'AbortError: The user aborted a request.' && !moreInfo.errorMessage.includes('TypeError: Cannot assign to read only property'))
|
||||
Toast.notify({ type: 'error', message: moreInfo.errorMessage })
|
||||
return
|
||||
}
|
||||
onData?.(str, isFirstMessage, moreInfo)
|
||||
},
|
||||
onCompleted,
|
||||
onThought,
|
||||
onMessageEnd,
|
||||
onMessageReplace,
|
||||
onFile,
|
||||
onWorkflowStarted,
|
||||
onWorkflowFinished,
|
||||
onNodeStarted,
|
||||
onNodeFinished,
|
||||
onIterationStart,
|
||||
onIterationNext,
|
||||
onIterationFinish,
|
||||
onLoopStart,
|
||||
onLoopNext,
|
||||
onLoopFinish,
|
||||
onNodeRetry,
|
||||
onParallelBranchStarted,
|
||||
onParallelBranchFinished,
|
||||
onTextChunk,
|
||||
onTTSChunk,
|
||||
onTTSEnd,
|
||||
onTextReplace,
|
||||
onAgentLog,
|
||||
onHumanInputRequired,
|
||||
onWorkflowSuspended,
|
||||
onDataSourceNodeProcessing,
|
||||
onDataSourceNodeCompleted,
|
||||
onDataSourceNodeError,
|
||||
)
|
||||
}).catch((e) => {
|
||||
if (e.toString() !== 'AbortError: The user aborted a request.' && !e.toString().includes('TypeError: Cannot assign to read only property'))
|
||||
|
|
|
|||
|
|
@ -136,8 +136,7 @@ export const fetchFilePreview = ({ fileID }: { fileID: string }): Promise<{ cont
|
|||
}
|
||||
|
||||
export const fetchCurrentWorkspace = ({ url, params }: { url: string; params: Record<string, any> }): Promise<ICurrentWorkspace> => {
|
||||
// return post<ICurrentWorkspace>(url, { body: params })
|
||||
return get<ICurrentWorkspace>(url, { params })
|
||||
return post<ICurrentWorkspace>(url, { body: params })
|
||||
}
|
||||
|
||||
export const updateCurrentWorkspace = ({ url, body }: { url: string; body: Record<string, any> }): Promise<ICurrentWorkspace> => {
|
||||
|
|
|
|||
|
|
@ -105,7 +105,8 @@ export const useLangGeniusVersion = (currentVersion?: string | null, enabled?: b
|
|||
export const useCurrentWorkspace = () => {
|
||||
return useQuery<ICurrentWorkspace>({
|
||||
queryKey: commonQueryKeys.currentWorkspace,
|
||||
queryFn: () => post<ICurrentWorkspace>('/workspaces/current', { body: {} }),
|
||||
// queryFn: () => post<ICurrentWorkspace>('/workspaces/current', { body: {} }),
|
||||
queryFn: () => get<ICurrentWorkspace>('/workspaces/current'), // todo: Need to check later, POST or GET
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +221,7 @@ export const useIsLogin = () => {
|
|||
})
|
||||
}
|
||||
catch (e: any) {
|
||||
if(e.status === 401)
|
||||
if (e.status === 401)
|
||||
return { logged_in: false }
|
||||
return { logged_in: true }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type { ErrorHandleTypeEnum } from '@/app/components/workflow/nodes/_base/
|
|||
import type { RAGPipelineVariables } from '@/models/pipeline'
|
||||
import type { BeforeRunFormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form'
|
||||
import type { SpecialResultPanelProps } from '@/app/components/workflow/run/special-result-panel'
|
||||
import type { GeneratedFormInputItem } from '@/app/components/workflow/nodes/human-input/types'
|
||||
import type { GeneratedFormInputItem, UserAction } from '@/app/components/workflow/nodes/human-input/types'
|
||||
import type { RefObject } from 'react'
|
||||
|
||||
export type AgentLogItem = {
|
||||
|
|
@ -312,13 +312,14 @@ export type AgentLogResponse = {
|
|||
}
|
||||
|
||||
export type HumanInputFormData = {
|
||||
id: string
|
||||
workflow_id: string
|
||||
form_id: string
|
||||
node_id: string
|
||||
node_title: string
|
||||
form_content: string
|
||||
inputs: GeneratedFormInputItem[]
|
||||
web_app_form_token: string
|
||||
actions: UserAction[]
|
||||
web_app_form_token: string // For WebApp
|
||||
resolved_placeholder_values: Record<string, string> // For human input placeholder when its type is variable
|
||||
}
|
||||
|
||||
export type HumanInputRequiredResponse = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue