Pārlūkot izejas kodu

fix: when the variable does not exist, an error should be prompted (#8413)

Co-authored-by: Chen(MAC) <chenchen404@outlook.com>
Pika 7 mēneši atpakaļ
vecāks
revīzija
5b18e851d2

+ 48 - 33
web/app/components/workflow/nodes/_base/components/variable-tag.tsx

@@ -1,9 +1,12 @@
 import { useMemo } from 'react'
 import { useNodes } from 'reactflow'
 import { capitalize } from 'lodash-es'
+import { useTranslation } from 'react-i18next'
+import { RiErrorWarningFill } from '@remixicon/react'
 import { VarBlockIcon } from '@/app/components/workflow/block-icon'
 import type {
   CommonNodeType,
+  Node,
   ValueSelector,
   VarType,
 } from '@/app/components/workflow/types'
@@ -11,63 +14,75 @@ import { BlockEnum } from '@/app/components/workflow/types'
 import { Line3 } from '@/app/components/base/icons/src/public/common'
 import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
 import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others'
-import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
+import { getNodeInfoById, isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
+import Tooltip from '@/app/components/base/tooltip'
 import cn from '@/utils/classnames'
 
 type VariableTagProps = {
   valueSelector: ValueSelector
   varType: VarType
+  availableNodes?: Node[]
 }
 const VariableTag = ({
   valueSelector,
   varType,
+  availableNodes,
 }: VariableTagProps) => {
   const nodes = useNodes<CommonNodeType>()
   const node = useMemo(() => {
-    if (isSystemVar(valueSelector))
-      return nodes.find(node => node.data.type === BlockEnum.Start)
+    if (isSystemVar(valueSelector)) {
+      const startNode = availableNodes?.find(n => n.data.type === BlockEnum.Start)
+      if (startNode)
+        return startNode
+    }
+    return getNodeInfoById(availableNodes || nodes, valueSelector[0])
+  }, [nodes, valueSelector, availableNodes])
 
-    return nodes.find(node => node.id === valueSelector[0])
-  }, [nodes, valueSelector])
   const isEnv = isENV(valueSelector)
   const isChatVar = isConversationVar(valueSelector)
+  const isValid = Boolean(node) || isEnv || isChatVar
 
   const variableName = isSystemVar(valueSelector) ? valueSelector.slice(0).join('.') : valueSelector.slice(1).join('.')
 
+  const { t } = useTranslation()
   return (
-    <div className='inline-flex items-center px-1.5 max-w-full h-6 text-xs rounded-md border-[0.5px] border-[rgba(16, 2440,0.08)] bg-white shadow-xs'>
-      {!isEnv && !isChatVar && (
-        <>
+    <Tooltip popupContent={!isValid && t('workflow.errorMsg.invalidVariable')}>
+      <div className={cn('inline-flex items-center px-1.5 max-w-full h-6 text-xs rounded-md border-[0.5px] border-[rgba(16, 2440,0.08)] bg-white shadow-xs',
+        !isValid && 'border-red-400 !bg-[#FEF3F2]',
+      )}>
+        {(!isEnv && !isChatVar && <>
           {node && (
-            <VarBlockIcon
-              className='shrink-0 mr-0.5 text-text-secondary'
-              type={node!.data.type}
-            />
+            <>
+              <VarBlockIcon
+                type={BlockEnum.Start}
+              />
+              <div
+                className='max-w-[60px] truncate text-text-secondary font-medium'
+                title={node?.data.title}
+              >
+                {node?.data.title}
+              </div>
+            </>
           )}
-          <div
-            className='max-w-[60px] truncate text-text-secondary font-medium'
-            title={node?.data.title}
-          >
-            {node?.data.title}
-          </div>
           <Line3 className='shrink-0 mx-0.5' />
           <Variable02 className='shrink-0 mr-0.5 w-3.5 h-3.5 text-text-accent' />
-        </>
-      )}
-      {isEnv && <Env className='shrink-0 mr-0.5 w-3.5 h-3.5 text-util-colors-violet-violet-600' />}
-      {isChatVar && <BubbleX className='w-3.5 h-3.5 text-util-colors-teal-teal-700' />}
-      <div
-        className={cn('truncate text-text-accent font-medium', (isEnv || isChatVar) && 'text-text-secondary')}
-        title={variableName}
-      >
-        {variableName}
+        </>)}
+        {isEnv && <Env className='shrink-0 mr-0.5 w-3.5 h-3.5 text-util-colors-violet-violet-600' />}
+        {isChatVar && <BubbleX className='w-3.5 h-3.5 text-util-colors-teal-teal-700' />}
+        <div
+          className={cn('truncate text-text-accent font-medium', (isEnv || isChatVar) && 'text-text-secondary')}
+          title={variableName}
+        >
+          {variableName}
+        </div>
+        {
+          varType && (
+            <div className='shrink-0 ml-0.5 text-text-tertiary'>{capitalize(varType)}</div>
+          )
+        }
+        {!isValid && <RiErrorWarningFill className='ml-0.5 w-3 h-3 text-[#D92D20]' />}
       </div>
-      {
-        varType && (
-          <div className='shrink-0 ml-0.5 text-text-tertiary'>{capitalize(varType)}</div>
-        )
-      }
-    </div>
+    </Tooltip>
   )
 }
 

+ 51 - 34
web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx

@@ -5,9 +5,10 @@ import { useTranslation } from 'react-i18next'
 import {
   RiArrowDownSLine,
   RiCloseLine,
+  RiErrorWarningFill,
 } from '@remixicon/react'
 import produce from 'immer'
-import { useStoreApi } from 'reactflow'
+import { useEdges, useStoreApi } from 'reactflow'
 import useAvailableVarList from '../../hooks/use-available-var-list'
 import VarReferencePopup from './var-reference-popup'
 import { getNodeInfoById, isConversationVar, isENV, isSystemVar } from './utils'
@@ -33,6 +34,8 @@ import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/typ
 import TypeSelector from '@/app/components/workflow/nodes/_base/components/selector'
 import AddButton from '@/app/components/base/button/add-button'
 import Badge from '@/app/components/base/badge'
+import Tooltip from '@/app/components/base/tooltip'
+
 const TRIGGER_DEFAULT_WIDTH = 227
 
 type Props = {
@@ -77,6 +80,7 @@ const VarReferencePicker: FC<Props> = ({
   const {
     getNodes,
   } = store.getState()
+  const edges = useEdges()
   const isChatMode = useIsChatMode()
 
   const { getCurrentVariableType } = useWorkflowVariables()
@@ -206,8 +210,16 @@ const VarReferencePicker: FC<Props> = ({
     isConstant: !!isConstant,
   })
 
-  const isEnv = isENV(value as ValueSelector)
-  const isChatVar = isConversationVar(value as ValueSelector)
+  const { isEnv, isChatVar, isValidVar } = useMemo(() => {
+    const isEnv = isENV(value as ValueSelector)
+    const isChatVar = isConversationVar(value as ValueSelector)
+    const isValidVar = Boolean(outputVarNode) || isEnv || isChatVar
+    return {
+      isEnv,
+      isChatVar,
+      isValidVar,
+    }
+  }, [value, edges, outputVarNode])
 
   // 8(left/right-padding) + 14(icon) + 4 + 14 + 2 = 42 + 17 buff
   const availableWidth = triggerWidth - 56
@@ -285,39 +297,44 @@ const VarReferencePicker: FC<Props> = ({
                     className='grow h-full'
                   >
                     <div ref={isSupportConstantValue ? triggerRef : null} className={cn('h-full', isSupportConstantValue && 'flex items-center pl-1 py-1 rounded-lg bg-gray-100')}>
-                      <div className={cn('h-full items-center px-1.5 rounded-[5px]', hasValue ? 'bg-white inline-flex' : 'flex')}>
-                        {hasValue
-                          ? (
-                            <>
-                              {isShowNodeName && !isEnv && !isChatVar && (
-                                <div className='flex items-center'>
-                                  <div className='p-[1px]'>
-                                    <VarBlockIcon
-                                      className='!text-gray-900'
-                                      type={outputVarNode?.type || BlockEnum.Start}
-                                    />
+                      <Tooltip popupContent={!isValidVar && hasValue && t('workflow.errorMsg.invalidVariable')}>
+                        <div className={cn('h-full items-center px-1.5 rounded-[5px] ', hasValue ? 'bg-white inline-flex' : 'flex',
+                          !isValidVar && hasValue && 'border border-red-400 !bg-[#FEF3F2]',
+                        )}>
+                          {hasValue
+                            ? (
+                              <>
+                                {isShowNodeName && !isEnv && !isChatVar && (
+                                  <div className='flex items-center'>
+                                    <div className='px-[1px] h-3'>
+                                      {outputVarNode?.type && <VarBlockIcon
+                                        className='!text-gray-900'
+                                        type={outputVarNode.type}
+                                      />}
+                                    </div>
+                                    <div className='mx-0.5 text-xs font-medium text-gray-700 truncate' title={outputVarNode?.title} style={{
+                                      maxWidth: maxNodeNameWidth,
+                                    }}>{outputVarNode?.title}</div>
+                                    <Line3 className='mr-0.5'></Line3>
                                   </div>
-                                  <div className='mx-0.5 text-xs font-medium text-gray-700 truncate' title={outputVarNode?.title} style={{
-                                    maxWidth: maxNodeNameWidth,
-                                  }}>{outputVarNode?.title}</div>
-                                  <Line3 className='mr-0.5'></Line3>
+                                )}
+                                <div className='flex items-center text-primary-600'>
+                                  {!hasValue && <Variable02 className='w-3.5 h-3.5' />}
+                                  {isEnv && <Env className='w-3.5 h-3.5 text-util-colors-violet-violet-600' />}
+                                  {isChatVar && <BubbleX className='w-3.5 h-3.5 text-util-colors-teal-teal-700' />}
+                                  <div className={cn('ml-0.5 text-xs font-medium truncate', (isEnv || isChatVar) && '!text-text-secondary')} title={varName} style={{
+                                    maxWidth: maxVarNameWidth,
+                                  }}>{varName}</div>
                                 </div>
-                              )}
-                              <div className='flex items-center text-primary-600'>
-                                {!hasValue && <Variable02 className='w-3.5 h-3.5' />}
-                                {isEnv && <Env className='w-3.5 h-3.5 text-util-colors-violet-violet-600' />}
-                                {isChatVar && <BubbleX className='w-3.5 h-3.5 text-util-colors-teal-teal-700' />}
-                                <div className={cn('ml-0.5 text-xs font-medium truncate', (isEnv || isChatVar) && '!text-text-secondary')} title={varName} style={{
-                                  maxWidth: maxVarNameWidth,
-                                }}>{varName}</div>
-                              </div>
-                              <div className='ml-0.5 text-xs font-normal text-gray-500 capitalize truncate' title={type} style={{
-                                maxWidth: maxTypeWidth,
-                              }}>{type}</div>
-                            </>
-                          )
-                          : <div className='text-[13px] font-normal text-gray-400'>{t('workflow.common.setVarValuePlaceholder')}</div>}
-                      </div>
+                                <div className='ml-0.5 text-xs font-normal text-gray-500 capitalize truncate' title={type} style={{
+                                  maxWidth: maxTypeWidth,
+                                }}>{type}</div>
+                                {!isValidVar && <RiErrorWarningFill className='ml-0.5 w-3 h-3 text-[#D92D20]' /> }
+                              </>
+                            )
+                            : <div className='text-[13px] font-normal text-gray-400'>{t('workflow.common.setVarValuePlaceholder')}</div>}
+                        </div>
+                      </Tooltip>
                     </div>
 
                   </VarPickerWrap>

+ 1 - 0
web/app/components/workflow/nodes/if-else/components/condition-list/condition-item.tsx

@@ -80,6 +80,7 @@ const ConditionItem = ({
             <VariableTag
               valueSelector={condition.variable_selector}
               varType={condition.varType}
+              availableNodes={availableNodes}
             />
           </div>
           <div className='mx-1 w-[1px] h-3 bg-divider-regular'></div>