Feat/attachments (#9526)

Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: JzoNg <jzongcode@gmail.com>
This commit is contained in:
zxhlyh
2024-10-21 10:32:37 +08:00
committed by GitHub
parent 4fd2743efa
commit 7a1d6fe509
445 changed files with 11759 additions and 6922 deletions

View File

@@ -17,22 +17,25 @@ import { fetchConversationMessages } from '@/service/debug'
import { useStore as useAppStore } from '@/app/components/app/store'
import Loading from '@/app/components/base/loading'
import { UUID_NIL } from '@/app/components/base/chat/constants'
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
function appendQAToChatList(newChatList: ChatItem[], item: any) {
const answerFiles = item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || []
newChatList.push({
id: item.id,
content: item.answer,
feedback: item.feedback,
isAnswer: true,
citation: item.metadata?.retriever_resources,
message_files: item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || [],
message_files: getProcessedFilesFromResponse(answerFiles.map((item: any) => ({ ...item, related_id: item.id }))),
workflow_run_id: item.workflow_run_id,
})
const questionFiles = item.message_files?.filter((file: any) => file.belongs_to === 'user') || []
newChatList.push({
id: `question-${item.id}`,
content: item.query,
isAnswer: false,
message_files: item.message_files?.filter((file: any) => file.belongs_to === 'user') || [],
message_files: getProcessedFilesFromResponse(questionFiles.map((item: any) => ({ ...item, related_id: item.id }))),
})
}

View File

@@ -6,6 +6,7 @@ import { RiAddLine } from '@remixicon/react'
import produce from 'immer'
import RemoveButton from '@/app/components/workflow/nodes/_base/components/remove-button'
import Button from '@/app/components/base/button'
import Input from '@/app/components/base/input'
type Props = {
isString: boolean
@@ -49,8 +50,7 @@ const ArrayValueList: FC<Props> = ({
<div className='w-full space-y-2'>
{list.map((item, index) => (
<div className='flex items-center space-x-1' key={index}>
<input
className='block px-3 w-full h-8 bg-components-input-bg-normal system-sm-regular radius-md border border-transparent appearance-none outline-none caret-primary-600 hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:bg-components-input-bg-active focus:border-components-input-border-active focus:shadow-xs placeholder:system-sm-regular placeholder:text-components-input-text-placeholder'
<Input
placeholder={t('workflow.chatVariable.modal.arrayValue') || ''}
value={list[index]}
onChange={handleNameChange(index)}

View File

@@ -8,6 +8,7 @@ import ObjectValueList from '@/app/components/workflow/panel/chat-variable-panel
import { DEFAULT_OBJECT_VALUE } from '@/app/components/workflow/panel/chat-variable-panel/components/object-value-item'
import ArrayValueList from '@/app/components/workflow/panel/chat-variable-panel/components/array-value-list'
import Button from '@/app/components/base/button'
import Input from '@/app/components/base/input'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
import { ToastContext } from '@/app/components/base/toast'
import { useStore } from '@/app/components/workflow/store'
@@ -270,9 +271,7 @@ const ChatVariableModal = ({
<div className='mb-4'>
<div className='mb-1 h-6 flex items-center text-text-secondary system-sm-semibold'>{t('workflow.chatVariable.modal.name')}</div>
<div className='flex'>
<input
tabIndex={0}
className='block px-3 w-full h-8 bg-components-input-bg-normal system-sm-regular radius-md border border-transparent appearance-none outline-none caret-primary-600 hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:bg-components-input-bg-active focus:border-components-input-border-active focus:shadow-xs placeholder:system-sm-regular placeholder:text-components-input-text-placeholder'
<Input
placeholder={t('workflow.chatVariable.modal.namePlaceholder') || ''}
value={name}
onChange={e => setName(e.target.value || '')}
@@ -322,16 +321,14 @@ const ChatVariableModal = ({
</div>
<div className='flex'>
{type === ChatVarType.String && (
<input
className='block px-3 w-full h-8 bg-components-input-bg-normal system-sm-regular radius-md border border-transparent appearance-none outline-none caret-primary-600 hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:bg-components-input-bg-active focus:border-components-input-border-active focus:shadow-xs placeholder:system-sm-regular placeholder:text-components-input-text-placeholder'
<Input
placeholder={t('workflow.chatVariable.modal.valuePlaceholder') || ''}
value={value}
onChange={e => setValue(e.target.value)}
/>
)}
{type === ChatVarType.Number && (
<input
className='block px-3 w-full h-8 bg-components-input-bg-normal system-sm-regular radius-md border border-transparent appearance-none outline-none caret-primary-600 hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:bg-components-input-bg-active focus:border-components-input-border-active focus:shadow-xs placeholder:system-sm-regular placeholder:text-components-input-text-placeholder'
<Input
placeholder={t('workflow.chatVariable.modal.valuePlaceholder') || ''}
value={value}
onChange={e => setValue(Number(e.target.value))}

View File

@@ -2,6 +2,7 @@ import {
forwardRef,
memo,
useCallback,
useEffect,
useImperativeHandle,
useMemo,
} from 'react'
@@ -19,7 +20,7 @@ import { useChat } from './hooks'
import type { ChatWrapperRefType } from './index'
import Chat from '@/app/components/base/chat/chat'
import type { ChatItem, OnSend } from '@/app/components/base/chat/types'
import { useFeaturesStore } from '@/app/components/base/features/hooks'
import { useFeatures } from '@/app/components/base/features/hooks'
import {
fetchSuggestedQuestions,
stopChatMessageResponding,
@@ -31,22 +32,26 @@ type ChatWrapperProps = {
showConversationVariableModal: boolean
onConversationModalHide: () => void
showInputsFieldsPanel: boolean
onHide: () => void
}
const ChatWrapper = forwardRef<ChatWrapperRefType, ChatWrapperProps>(({ showConversationVariableModal, onConversationModalHide, showInputsFieldsPanel }, ref) => {
const ChatWrapper = forwardRef<ChatWrapperRefType, ChatWrapperProps>(({
showConversationVariableModal,
onConversationModalHide,
showInputsFieldsPanel,
onHide,
}, ref) => {
const nodes = useNodes<StartNodeType>()
const startNode = nodes.find(node => node.data.type === BlockEnum.Start)
const startVariables = startNode?.data.variables
const appDetail = useAppStore(s => s.appDetail)
const workflowStore = useWorkflowStore()
const featuresStore = useFeaturesStore()
const inputs = useStore(s => s.inputs)
const features = featuresStore!.getState().features
const features = useFeatures(s => s.features)
const config = useMemo(() => {
return {
opening_statement: features.opening?.opening_statement || '',
suggested_questions: features.opening?.suggested_questions || [],
opening_statement: features.opening?.enabled ? (features.opening?.opening_statement || '') : '',
suggested_questions: features.opening?.enabled ? (features.opening?.suggested_questions || []) : [],
suggested_questions_after_answer: features.suggested,
text_to_speech: features.text2speech,
speech_to_text: features.speech2text,
@@ -54,7 +59,8 @@ const ChatWrapper = forwardRef<ChatWrapperRefType, ChatWrapperProps>(({ showConv
sensitive_word_avoidance: features.moderation,
file_upload: features.file,
}
}, [features])
}, [features.opening, features.suggested, features.text2speech, features.speech2text, features.citation, features.moderation, features.file])
const setShowFeaturesPanel = useStore(s => s.setShowFeaturesPanel)
const {
conversationId,
@@ -70,7 +76,7 @@ const ChatWrapper = forwardRef<ChatWrapperRefType, ChatWrapperProps>(({ showConv
config,
{
inputs,
promptVariables: (startVariables as any) || [],
inputsForm: (startVariables || []) as any,
},
[],
taskId => stopChatMessageResponding(appDetail!.id, taskId),
@@ -113,6 +119,11 @@ const ChatWrapper = forwardRef<ChatWrapperRefType, ChatWrapperProps>(({ showConv
}
}, [handleRestart])
useEffect(() => {
if (isResponding)
onHide()
}, [isResponding, onHide])
return (
<>
<Chat
@@ -125,8 +136,13 @@ const ChatWrapper = forwardRef<ChatWrapperRefType, ChatWrapperProps>(({ showConv
chatContainerClassName='px-3'
chatContainerInnerClassName='pt-6 w-full max-w-full mx-auto'
chatFooterClassName='px-4 rounded-bl-2xl'
chatFooterInnerClassName='pb-4 w-full max-w-full mx-auto'
chatFooterInnerClassName='pb-0'
showFileUpload
showFeatureBar
onFeatureBarClick={setShowFeaturesPanel}
onSend={doSend}
inputs={inputs}
inputsForm={(startVariables || []) as any}
onRegenerate={doRegenerate}
onStopResponding={handleStop}
chatNode={(

View File

@@ -96,14 +96,14 @@ const ConversationVariableModal = ({
</div>
</div>
{/* RIGHT */}
<div className='grow flex flex-col h-full bg-components-panel-bg'>
<div className='grow flex flex-col w-0 h-full bg-components-panel-bg'>
<div className='shrink-0 p-4 pb-2'>
<div className='flex items-center gap-1 py-1'>
<div className='text-text-primary system-xl-semibold'>{currentVar.name}</div>
<div className='text-text-tertiary system-xs-medium'>{capitalize(currentVar.value_type)}</div>
</div>
</div>
<div className='grow p-4 pt-2 flex flex-col'>
<div className='grow p-4 pt-2 flex flex-col h-0'>
<div className='shrink-0 mb-2 flex items-center gap-2'>
<div className='shrink-0 text-text-tertiary system-xs-medium-uppercase'>{t('workflow.chatVariable.storedContent').toLocaleUpperCase()}</div>
<div className='grow h-[1px]' style={{
@@ -113,7 +113,7 @@ const ConversationVariableModal = ({
<div className='shrink-0 text-text-tertiary system-xs-regular'>{t('workflow.chatVariable.updatedAt')}{formatTime(latestValueTimestampMap[currentVar.id], t('appLog.dateTimeFormat') as string)}</div>
)}
</div>
<div className='grow'>
<div className='grow overflow-y-auto'>
{currentVar.value_type !== ChatVarType.Number && currentVar.value_type !== ChatVarType.String && (
<div className='h-full flex flex-col bg-components-input-bg-normal rounded-lg px-2 pb-2'>
<div className='shrink-0 flex justify-between items-center h-7 pt-1 pl-3 pr-2'>
@@ -142,7 +142,7 @@ const ConversationVariableModal = ({
</div>
)}
{(currentVar.value_type === ChatVarType.Number || currentVar.value_type === ChatVarType.String) && (
<div className='h-full px-4 py-3 rounded-lg bg-components-input-bg-normal text-components-input-text-filled system-md-regular overflow-y-auto'>{latestValueMap[currentVar.id] || ''}</div>
<div className='h-full px-4 py-3 rounded-lg bg-components-input-bg-normal text-components-input-text-filled system-md-regular overflow-y-auto overflow-x-hidden'>{latestValueMap[currentVar.id] || ''}</div>
)}
</div>
</div>

View File

@@ -6,17 +6,25 @@ import {
} from 'react'
import { useTranslation } from 'react-i18next'
import { produce, setAutoFreeze } from 'immer'
import { uniqBy } from 'lodash-es'
import { useWorkflowRun } from '../../hooks'
import { NodeRunningStatus, WorkflowRunningStatus } from '../../types'
import type {
ChatItem,
Inputs,
PromptVariable,
} from '@/app/components/base/chat/types'
import type { InputForm } from '@/app/components/base/chat/chat/type'
import {
getProcessedInputs,
processOpeningStatement,
} from '@/app/components/base/chat/chat/utils'
import { useToastContext } from '@/app/components/base/toast'
import { TransferMethod } from '@/types/app'
import type { VisionFile } from '@/types/app'
import { replaceStringWithValues } from '@/app/components/app/configuration/prompt-value-panel'
import {
getProcessedFiles,
getProcessedFilesFromResponse,
} from '@/app/components/base/file-uploader/utils'
import type { FileEntity } from '@/app/components/base/file-uploader/types'
type GetAbortController = (abortController: AbortController) => void
type SendCallback = {
@@ -24,9 +32,9 @@ type SendCallback = {
}
export const useChat = (
config: any,
promptVariablesConfig?: {
formSettings?: {
inputs: Inputs
promptVariables: PromptVariable[]
inputsForm: InputForm[]
},
prevChatList?: ChatItem[],
stopChat?: (taskId: string) => void,
@@ -62,8 +70,8 @@ export const useChat = (
}, [])
const getIntroduction = useCallback((str: string) => {
return replaceStringWithValues(str, promptVariablesConfig?.promptVariables || [], promptVariablesConfig?.inputs || {})
}, [promptVariablesConfig?.inputs, promptVariablesConfig?.promptVariables])
return processOpeningStatement(str, formSettings?.inputs || {}, formSettings?.inputsForm || [])
}, [formSettings?.inputs, formSettings?.inputsForm])
useEffect(() => {
if (config?.opening_statement) {
handleUpdateChatList(produce(chatListRef.current, (draft) => {
@@ -143,7 +151,11 @@ export const useChat = (
}, [handleUpdateChatList])
const handleSend = useCallback((
params: any,
params: {
query: string
files?: FileEntity[]
[key: string]: any
},
{
onGetSuggestedQuestions,
}: SendCallback,
@@ -182,12 +194,14 @@ export const useChat = (
handleResponding(true)
const { files, inputs, ...restParams } = params
const bodyParams = {
conversation_id: conversationId.current,
...params,
files: getProcessedFiles(files || []),
inputs: getProcessedInputs(inputs || {}, formSettings?.inputsForm || []),
...restParams,
}
if (bodyParams?.files?.length) {
bodyParams.files = bodyParams.files.map((item: VisionFile) => {
bodyParams.files = bodyParams.files.map((item) => {
if (item.transfer_method === TransferMethod.local_file) {
return {
...item,
@@ -201,7 +215,7 @@ export const useChat = (
let hasSetResponseId = false
handleRun(
params,
bodyParams,
{
onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId, taskId }: any) => {
responseItem.content = responseItem.content + message
@@ -260,6 +274,8 @@ export const useChat = (
},
onMessageEnd: (messageEnd) => {
responseItem.citation = messageEnd.metadata?.retriever_resources || []
const processedFilesFromResponse = getProcessedFilesFromResponse(messageEnd.files || [])
responseItem.allFiles = uniqBy([...(responseItem.allFiles || []), ...(processedFilesFromResponse || [])], 'id')
const newListWithAnswer = produce(
chatListRef.current.filter(item => item.id !== responseItem.id && item.id !== placeholderAnswerId),
@@ -382,7 +398,7 @@ export const useChat = (
},
},
)
}, [handleRun, handleResponding, handleUpdateChatList, notify, t, updateCurrentQA, config.suggested_questions_after_answer?.enabled])
}, [handleRun, handleResponding, handleUpdateChatList, notify, t, updateCurrentQA, config.suggested_questions_after_answer?.enabled, formSettings])
return {
conversationId: conversationId.current,

View File

@@ -54,11 +54,8 @@ const DebugAndPreview = () => {
return (
<div
className={cn(
'flex flex-col w-[420px] rounded-l-2xl h-full border border-black/2',
'flex flex-col w-[420px] bg-chatbot-bg rounded-l-2xl h-full border border-components-panel-border border-r-0 shadow-xl',
)}
style={{
background: 'linear-gradient(156deg, rgba(242, 244, 247, 0.80) 0%, rgba(242, 244, 247, 0.00) 99.43%), var(--white, #FFF)',
}}
>
<div className='shrink-0 flex items-center justify-between px-4 pt-3 pb-2 text-text-primary system-xl-semibold'>
<div className='h-8'>{t('workflow.common.debugAndPreview').toLocaleUpperCase()}</div>
@@ -88,6 +85,7 @@ const DebugAndPreview = () => {
<RiEqualizer2Line className='w-4 h-4' />
</ActionButton>
</Tooltip>
{expanded && <div className='absolute z-10 bottom-[-17px] right-[5px] w-3 h-3 bg-components-panel-on-panel-item-bg border-l-[0.5px] border-t-[0.5px] border-components-panel-border-subtle rotate-45'/>}
</div>
)}
<div className='mx-3 w-[1px] h-3.5 bg-gray-200'></div>
@@ -105,6 +103,7 @@ const DebugAndPreview = () => {
showConversationVariableModal={showConversationVariableModal}
onConversationModalHide={() => setShowConversationVariableModal(false)}
showInputsFieldsPanel={expanded}
onHide={() => setExpanded(false)}
/>
</div>
</div>

View File

@@ -19,7 +19,11 @@ const UserInput = () => {
const variables = startNode?.data.variables || []
const handleValueChange = (variable: string, v: string) => {
workflowStore.getState().setInputs({
const {
inputs,
setInputs,
} = workflowStore.getState()
setInputs({
...inputs,
[variable]: v,
})
@@ -29,7 +33,7 @@ const UserInput = () => {
return null
return (
<div className={cn('relative bg-components-panel-on-panel-item-bg rounded-xl border-[0.5px] border-components-panel-border-subtle shadow-xs z-[1]')}>
<div className={cn('sticky top-0 bg-components-panel-on-panel-item-bg rounded-xl border-[0.5px] border-components-panel-border-subtle shadow-xs z-[1]')}>
<div className='px-4 pt-3 pb-4'>
{variables.map((variable, index) => (
<div

View File

@@ -4,6 +4,7 @@ import { v4 as uuid4 } from 'uuid'
import { RiCloseLine } from '@remixicon/react'
import { useContext } from 'use-context-selector'
import Button from '@/app/components/base/button'
import Input from '@/app/components/base/input'
import Tooltip from '@/app/components/base/tooltip'
import { ToastContext } from '@/app/components/base/toast'
import { useStore } from '@/app/components/workflow/store'
@@ -117,9 +118,7 @@ const VariableModal = ({
<div className='mb-4'>
<div className='mb-1 h-6 flex items-center text-text-secondary system-sm-semibold'>{t('workflow.env.modal.name')}</div>
<div className='flex'>
<input
tabIndex={0}
className='block px-3 w-full h-8 bg-components-input-bg-normal system-sm-regular radius-md border border-transparent appearance-none outline-none caret-primary-600 hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:bg-components-input-bg-active focus:border-components-input-border-active focus:shadow-xs placeholder:system-sm-regular placeholder:text-components-input-text-placeholder'
<Input
placeholder={t('workflow.env.modal.namePlaceholder') || ''}
value={name}
onChange={e => setName(e.target.value || '')}
@@ -132,9 +131,7 @@ const VariableModal = ({
<div className=''>
<div className='mb-1 h-6 flex items-center text-text-secondary system-sm-semibold'>{t('workflow.env.modal.value')}</div>
<div className='flex'>
<input
tabIndex={0}
className='block px-3 w-full h-8 bg-components-input-bg-normal system-sm-regular radius-md border border-transparent appearance-none outline-none caret-primary-600 hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:bg-components-input-bg-active focus:border-components-input-border-active focus:shadow-xs placeholder:system-sm-regular placeholder:text-components-input-text-placeholder'
<Input
placeholder={t('workflow.env.modal.valuePlaceholder') || ''}
value={value}
onChange={e => setValue(e.target.value)}

View File

@@ -0,0 +1,56 @@
import {
memo,
} from 'react'
import { RiCloseLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import type { GlobalVariable } from '../../types'
import Item from './item'
import { useStore } from '@/app/components/workflow/store'
import cn from '@/utils/classnames'
const Panel = () => {
const { t } = useTranslation()
const setShowPanel = useStore(s => s.setShowGlobalVariablePanel)
const globalVariableList: GlobalVariable[] = [
{
name: 'conversation_id',
value_type: 'string',
description: 'conversation id',
},
]
return (
<div
className={cn(
'relative flex flex-col w-[420px] bg-components-panel-bg-alt rounded-l-2xl h-full border border-components-panel-border',
)}
>
<div className='shrink-0 flex items-center justify-between p-4 pb-0 text-text-primary system-xl-semibold'>
Global Variables(Current not show)
<div className='flex items-center'>
<div
className='flex items-center justify-center w-6 h-6 cursor-pointer'
onClick={() => setShowPanel(false)}
>
<RiCloseLine className='w-4 h-4 text-text-tertiary' />
</div>
</div>
</div>
<div className='shrink-0 py-1 px-4 system-sm-regular text-text-tertiary'>...</div>
<div className='grow px-4 rounded-b-2xl overflow-y-auto'>
{globalVariableList.map(item => (
<Item
key={item.name}
payload={item}
/>
))}
</div>
</div>
)
}
export default memo(Panel)

View File

@@ -0,0 +1,30 @@
import { memo } from 'react'
import { capitalize } from 'lodash-es'
import { Env } from '@/app/components/base/icons/src/vender/line/others'
import type { GlobalVariable } from '@/app/components/workflow/types'
import cn from '@/utils/classnames'
type Props = {
payload: GlobalVariable
}
const Item = ({
payload,
}: Props) => {
return (
<div className={cn(
'mb-1 px-2.5 py-2 bg-components-panel-on-panel-item-bg radius-md border border-components-panel-border-subtle shadow-xs hover:bg-components-panel-on-panel-item-bg-hover',
)}>
<div className='flex items-center justify-between'>
<div className='grow flex gap-1 items-center'>
<Env className='w-4 h-4 text-util-colors-violet-violet-600' />
<div className='text-text-primary system-sm-medium'>{payload.name}</div>
<div className='text-text-tertiary system-xs-medium'>{capitalize(payload.value_type)}</div>
</div>
</div>
<div className='text-text-tertiary system-xs-regular truncate'>{payload.description}</div>
</div>
)
}
export default memo(Item)

View File

@@ -14,6 +14,7 @@ import WorkflowPreview from './workflow-preview'
import ChatRecord from './chat-record'
import ChatVariablePanel from './chat-variable-panel'
import EnvPanel from './env-panel'
import GlobalVariablePanel from './global-variable-panel'
import cn from '@/utils/classnames'
import { useStore as useAppStore } from '@/app/components/app/store'
import MessageLogModal from '@/app/components/base/message-log-modal'
@@ -26,6 +27,7 @@ const Panel: FC = () => {
const showDebugAndPreviewPanel = useStore(s => s.showDebugAndPreviewPanel)
const showEnvPanel = useStore(s => s.showEnvPanel)
const showChatVariablePanel = useStore(s => s.showChatVariablePanel)
const showGlobalVariablePanel = useStore(s => s.showGlobalVariablePanel)
const isRestoring = useStore(s => s.isRestoring)
const { currentLogItem, setCurrentLogItem, showMessageLogModal, setShowMessageLogModal, currentLogModalActiveTab } = useAppStore(useShallow(state => ({
currentLogItem: state.currentLogItem,
@@ -90,6 +92,11 @@ const Panel: FC = () => {
<ChatVariablePanel />
)
}
{
showGlobalVariablePanel && (
<GlobalVariablePanel />
)
}
</div>
)
}

View File

@@ -1,5 +1,6 @@
import {
memo,
useCallback,
useMemo,
} from 'react'
import { useTranslation } from 'react-i18next'
@@ -19,6 +20,10 @@ import type { StartNodeType } from '../nodes/start/types'
import { TransferMethod } from '../../base/text-generation/types'
import Button from '@/app/components/base/button'
import { useFeatures } from '@/app/components/base/features/hooks'
import {
getProcessedInputs,
} from '@/app/components/base/chat/chat/utils'
import { useCheckInputsForms } from '@/app/components/base/chat/chat/check-input-forms-hooks'
type Props = {
onRun: () => void
@@ -37,6 +42,7 @@ const InputsPanel = ({ onRun }: Props) => {
} = useWorkflowRun()
const startNode = nodes.find(node => node.data.type === BlockEnum.Start)
const startVariables = startNode?.data.variables
const { checkInputsForm } = useCheckInputsForms()
const variables = useMemo(() => {
const data = startVariables || []
@@ -56,34 +62,40 @@ const InputsPanel = ({ onRun }: Props) => {
}, [fileSettings?.image?.enabled, startVariables])
const handleValueChange = (variable: string, v: any) => {
const {
inputs,
setInputs,
} = workflowStore.getState()
if (variable === '__image') {
workflowStore.setState({
files: v,
})
}
else {
workflowStore.getState().setInputs({
setInputs({
...inputs,
[variable]: v,
})
}
}
const doRun = () => {
const doRun = useCallback(() => {
if (!checkInputsForm(inputs, variables as any))
return
onRun()
handleRun({ inputs, files })
}
handleRun({ inputs: getProcessedInputs(inputs, variables as any), files })
}, [files, handleRun, inputs, onRun, variables, checkInputsForm])
const canRun = (() => {
const canRun = useMemo(() => {
if (files?.some(item => (item.transfer_method as any) === TransferMethod.local_file && !item.upload_file_id))
return false
return true
})()
}, [files])
return (
<>
<div className='px-4 pb-2'>
<div className='pt-3 px-4 pb-2'>
{
variables.map((variable, index) => (
<div

View File

@@ -18,8 +18,8 @@ const Record = () => {
}, [handleUpdateWorkflowCanvas])
return (
<div className='flex flex-col w-[400px] h-full rounded-l-2xl border-[0.5px] border-gray-200 shadow-xl bg-white'>
<div className='flex items-center justify-between p-4 pb-1 text-base font-semibold text-gray-900'>
<div className='flex flex-col w-[400px] h-full rounded-l-2xl border-[0.5px] border-components-panel-border shadow-xl bg-components-panel-bg'>
<div className='flex items-center justify-between p-4 pb-0 text-text-primary system-xl-semibold'>
{`Test Run#${historyWorkflowData?.sequence_number}`}
</div>
<Run

View File

@@ -146,8 +146,8 @@ const WorkflowPreview = () => {
>{t('runLog.tracing')}</div>
</div>
<div className={cn(
'grow bg-white h-0 overflow-y-auto rounded-b-2xl',
(currentTab === 'RESULT' || currentTab === 'TRACING') && '!bg-gray-50',
'grow bg-components-panel-bg h-0 overflow-y-auto rounded-b-2xl',
(currentTab === 'RESULT' || currentTab === 'TRACING') && '!bg-background-section-burn',
)}>
{currentTab === 'INPUT' && showInputsPanel && (
<InputsPanel onRun={() => switchTab('RESULT')} />
@@ -157,6 +157,7 @@ const WorkflowPreview = () => {
<ResultText
isRunning={workflowRunningData?.result?.status === WorkflowRunningStatus.Running || !workflowRunningData?.result}
outputs={workflowRunningData?.resultText}
allFiles={workflowRunningData?.result?.files as any}
error={workflowRunningData?.result?.error}
onClick={() => switchTab('DETAIL')}
/>
@@ -191,18 +192,19 @@ const WorkflowPreview = () => {
/>
)}
{currentTab === 'DETAIL' && !workflowRunningData?.result && (
<div className='flex h-full items-center justify-center bg-white'>
<div className='flex h-full items-center justify-center bg-components-panel-bg'>
<Loading />
</div>
)}
{currentTab === 'TRACING' && (
<TracingPanel
className='bg-background-section-burn'
list={workflowRunningData?.tracing || []}
onShowIterationDetail={handleShowIterationDetail}
/>
)}
{currentTab === 'TRACING' && !workflowRunningData?.tracing?.length && (
<div className='flex h-full items-center justify-center bg-gray-50'>
<div className='flex h-full items-center justify-center !bg-background-section-burn'>
<Loading />
</div>
)}