Chore/variable label (#23270)

This commit is contained in:
zxhlyh 2025-08-01 15:43:36 +08:00 • committed by GitHub
commit f78b903a49
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 595 additions and 483 deletions

View file

@ -10,10 +10,6 @@ import {
} from 'lexical' } from 'lexical'
import { mergeRegister } from '@lexical/utils' import { mergeRegister } from '@lexical/utils'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import {
RiErrorWarningFill,
RiMoreLine,
} from '@remixicon/react'
import { useReactFlow, useStoreApi } from 'reactflow' import { useReactFlow, useStoreApi } from 'reactflow'
import { useSelectOrDelete } from '../../hooks' import { useSelectOrDelete } from '../../hooks'
import type { WorkflowNodesMap } from './node' import type { WorkflowNodesMap } from './node'
@ -22,17 +18,15 @@ import {
DELETE_WORKFLOW_VARIABLE_BLOCK_COMMAND, DELETE_WORKFLOW_VARIABLE_BLOCK_COMMAND,
UPDATE_WORKFLOW_NODES_MAP, UPDATE_WORKFLOW_NODES_MAP,
} from './index' } from './index'
import cn from '@/utils/classnames'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others'
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
import { Line3 } from '@/app/components/base/icons/src/public/common'
import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils' import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
import { isExceptionVariable } from '@/app/components/workflow/utils' import { isExceptionVariable } from '@/app/components/workflow/utils'
import VarFullPathPanel from '@/app/components/workflow/nodes/_base/components/variable/var-full-path-panel' import VarFullPathPanel from '@/app/components/workflow/nodes/_base/components/variable/var-full-path-panel'
import { Type } from '@/app/components/workflow/nodes/llm/types' import { Type } from '@/app/components/workflow/nodes/llm/types'
import type { ValueSelector, Var } from '@/app/components/workflow/types' import type { ValueSelector, Var } from '@/app/components/workflow/types'
import {
VariableLabelInEditor,
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
type WorkflowVariableBlockComponentProps = { type WorkflowVariableBlockComponentProps = {
nodeKey: string nodeKey: string
@ -126,69 +120,22 @@ const WorkflowVariableBlockComponent = ({
}, [node, reactflow, store]) }, [node, reactflow, store])
const Item = ( const Item = (
<div <VariableLabelInEditor
className={cn( nodeType={node?.type}
'group/wrap relative mx-0.5 flex h-[18px] select-none items-center rounded-[5px] border pl-0.5 pr-[3px] hover:border-state-accent-solid hover:bg-state-accent-hover', nodeTitle={node?.title}
isSelected ? ' border-state-accent-solid bg-state-accent-hover' : ' border-components-panel-border-subtle bg-components-badge-white-to-dark', variables={variables}
!variableValid && '!border-state-destructive-solid !bg-state-destructive-hover',
)}
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
handleVariableJump() handleVariableJump()
}} }}
isExceptionVariable={isException}
errorMsg={!variableValid ? t('workflow.errorMsg.invalidVariable') : undefined}
isSelected={isSelected}
ref={ref} ref={ref}
> notShowFullPath={isShowAPart}
{!isEnv && !isChatVar && ( />
<div className='flex items-center'>
{
node?.type && (
<div className='p-[1px]'>
<VarBlockIcon
className='!text-text-secondary'
type={node?.type}
/>
</div>
)
}
<div className='mx-0.5 max-w-[60px] shrink-0 truncate text-xs font-medium text-text-secondary' title={node?.title} style={{
}}>{node?.title}</div>
<Line3 className='mr-0.5 text-divider-deep'></Line3>
</div>
)}
{isShowAPart && (
<div className='flex items-center'>
<RiMoreLine className='h-3 w-3 text-text-secondary' />
<Line3 className='mr-0.5 text-divider-deep'></Line3>
</div>
)}
<div className='flex items-center text-text-accent'>
{!isEnv && !isChatVar && <Variable02 className={cn('h-3.5 w-3.5 shrink-0', isException && 'text-text-warning')} />}
{isEnv && <Env className='h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />}
{isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />}
<div className={cn(
'ml-0.5 shrink-0 truncate text-xs font-medium',
isEnv && 'text-util-colors-violet-violet-600',
isChatVar && 'text-util-colors-teal-teal-700',
isException && 'text-text-warning',
)} title={varName}>{varName}</div>
{
!variableValid && (
<RiErrorWarningFill className='ml-0.5 h-3 w-3 text-text-destructive' />
)
}
</div>
</div>
) )
if (!variableValid) {
return (
<Tooltip popupContent={t('workflow.errorMsg.invalidVariable')}>
{Item}
</Tooltip>
)
}
if (!node) if (!node)
return Item return Item

View file

@ -4,12 +4,10 @@ import React from 'react'
import cn from 'classnames' import cn from 'classnames'
import { useWorkflow } from '../../../hooks' import { useWorkflow } from '../../../hooks'
import { BlockEnum } from '../../../types' import { BlockEnum } from '../../../types'
import { VarBlockIcon } from '../../../block-icon' import { getNodeInfoById, isSystemVar } from './variable/utils'
import { getNodeInfoById, isConversationVar, isENV, isSystemVar } from './variable/utils' import {
import { Line3 } from '@/app/components/base/icons/src/public/common' VariableLabelInText,
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others'
import { RiMoreLine } from '@remixicon/react'
type Props = { type Props = {
nodeId: string nodeId: string
value: string value: string
@ -42,40 +40,17 @@ const ReadonlyInputWithSelectVar: FC<Props> = ({
const value = vars[index].split('.') const value = vars[index].split('.')
const isSystem = isSystemVar(value) const isSystem = isSystemVar(value)
const isEnv = isENV(value)
const isChatVar = isConversationVar(value)
const node = (isSystem ? startNode : getNodeInfoById(availableNodes, value[0]))?.data const node = (isSystem ? startNode : getNodeInfoById(availableNodes, value[0]))?.data
const varName = `${isSystem ? 'sys.' : ''}${value[value.length - 1]}`
const isShowAPart = value.length > 2 const isShowAPart = value.length > 2
return (<span key={index}> return (<span key={index}>
<span className='relative top-[-3px] leading-[16px]'>{str}</span> <span className='relative top-[-3px] leading-[16px]'>{str}</span>
<div className=' inline-flex h-[16px] items-center rounded-[5px] bg-components-badge-white-to-dark px-1.5'> <VariableLabelInText
{!isEnv && !isChatVar && ( nodeTitle={node?.title}
<div className='flex items-center'> nodeType={node?.type}
<div className='p-[1px]'> notShowFullPath={isShowAPart}
<VarBlockIcon variables={value}
className='!text-text-primary' />
type={node?.type || BlockEnum.Start}
/>
</div>
<div className='mx-0.5 max-w-[60px] truncate text-xs font-medium text-text-secondary' title={node?.title}>{node?.title}</div>
<Line3 className='mr-0.5'></Line3>
</div>
)}
{isShowAPart && (
<div className='flex items-center'>
<RiMoreLine className='h-3 w-3 text-text-secondary' />
<Line3 className='mr-0.5 text-divider-deep'></Line3>
</div>
)}
<div className='flex items-center text-text-accent'>
{!isEnv && !isChatVar && <Variable02 className='h-3.5 w-3.5 shrink-0' />}
{isEnv && <Env className='h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />}
{isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />}
<div className={cn('ml-0.5 max-w-[50px] truncate text-xs font-medium', (isEnv || isChatVar) && 'text-text-primary')} title={varName}>{varName}</div>
</div>
</div>
</span>) </span>)
}) })
return html return html

View file

@ -1,9 +1,6 @@
import { useCallback, useMemo } from 'react' import { useCallback, useMemo } from 'react'
import { useNodes, useReactFlow, useStoreApi } from 'reactflow' import { useNodes, useReactFlow, useStoreApi } from 'reactflow'
import { capitalize } from 'lodash-es'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { RiErrorWarningFill } from '@remixicon/react'
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
import type { import type {
CommonNodeType, CommonNodeType,
Node, Node,
@ -11,13 +8,11 @@ import type {
VarType, VarType,
} from '@/app/components/workflow/types' } from '@/app/components/workflow/types'
import { BlockEnum } from '@/app/components/workflow/types' 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 { getNodeInfoById, 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'
import { isExceptionVariable } from '@/app/components/workflow/utils' import { isExceptionVariable } from '@/app/components/workflow/utils'
import {
VariableLabelInSelect,
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
type VariableTagProps = { type VariableTagProps = {
valueSelector: ValueSelector valueSelector: ValueSelector
@ -73,51 +68,20 @@ const VariableTag = ({
const { t } = useTranslation() const { t } = useTranslation()
return ( return (
<Tooltip popupContent={!isValid && t('workflow.errorMsg.invalidVariable')}> <VariableLabelInSelect
<div className={cn('border-[rgba(16, 2440,0.08)] inline-flex h-6 max-w-full items-center rounded-md border-[0.5px] border-divider-subtle bg-components-badge-white-to-dark px-1.5 text-xs shadow-xs', variables={valueSelector}
!isValid && 'border-red-400 !bg-[#FEF3F2]', nodeType={node?.data.type}
)} nodeTitle={node?.data.title}
onClick={(e) => { variableType={!isShort ? varType : undefined}
if (e.metaKey || e.ctrlKey) { onClick={(e) => {
e.stopPropagation() if (e.metaKey || e.ctrlKey) {
handleVariableJump() e.stopPropagation()
} handleVariableJump()
}}
>
{(!isEnv && !isChatVar && <>
{node && (
<>
<VarBlockIcon
type={node.data.type || BlockEnum.Start}
className='mr-0.5 !text-text-primary'
/>
<div
className='max-w-[60px] truncate font-medium text-text-secondary'
title={node?.data.title}
>
{node?.data.title}
</div>
</>
)}
<Line3 className='mx-0.5 shrink-0' />
<Variable02 className={cn('mr-0.5 h-3.5 w-3.5 shrink-0 text-text-accent', isException && 'text-text-warning')} />
</>)}
{isEnv && <Env className='mr-0.5 h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />}
{isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />}
<div
className={cn('ml-0.5 truncate font-medium text-text-accent', (isEnv || isChatVar) && 'text-text-secondary', isException && 'text-text-warning')}
title={variableName}
>
{variableName}
</div>
{
!isShort && varType && (
<div className='ml-0.5 shrink-0 text-text-tertiary'>{capitalize(varType)}</div>
)
} }
{!isValid && <RiErrorWarningFill className='ml-0.5 h-3 w-3 text-[#D92D20]' />} }}
</div> errorMsg={!isValid ? t('workflow.errorMsg.invalidVariable') : undefined}
</Tooltip> isExceptionVariable={isException}
/>
) )
} }

View file

@ -23,7 +23,6 @@ import { type CredentialFormSchema, type FormOption, FormTypeEnum } from '@/app/
import { BlockEnum } from '@/app/components/workflow/types' import { BlockEnum } from '@/app/components/workflow/types'
import { VarBlockIcon } from '@/app/components/workflow/block-icon' import { VarBlockIcon } from '@/app/components/workflow/block-icon'
import { Line3 } from '@/app/components/base/icons/src/public/common' import { Line3 } from '@/app/components/base/icons/src/public/common'
import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import { import {
PortalToFollowElem, PortalToFollowElem,
@ -44,6 +43,7 @@ import VarFullPathPanel from './var-full-path-panel'
import { noop } from 'lodash-es' import { noop } from 'lodash-es'
import { useFetchDynamicOptions } from '@/service/use-plugins' import { useFetchDynamicOptions } from '@/service/use-plugins'
import type { Tool } from '@/app/components/tools/types' import type { Tool } from '@/app/components/tools/types'
import { VariableIconWithColor } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
const TRIGGER_DEFAULT_WIDTH = 227 const TRIGGER_DEFAULT_WIDTH = 227
@ -138,7 +138,6 @@ const VarReferencePicker: FC<Props> = ({
useEffect(() => { useEffect(() => {
if (triggerRef.current) if (triggerRef.current)
setTriggerWidth(triggerRef.current.clientWidth) setTriggerWidth(triggerRef.current.clientWidth)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [triggerRef.current]) }, [triggerRef.current])
const [varKindType, setVarKindType] = useState<VarKindType>(defaultVarKindType) const [varKindType, setVarKindType] = useState<VarKindType>(defaultVarKindType)
@ -149,7 +148,6 @@ const VarReferencePicker: FC<Props> = ({
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
useEffect(() => { useEffect(() => {
onOpen() onOpen()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [open]) }, [open])
const hasValue = !isConstant && value.length > 0 const hasValue = !isConstant && value.length > 0
@ -362,6 +360,13 @@ const VarReferencePicker: FC<Props> = ({
return schema return schema
}, [dynamicOptions]) }, [dynamicOptions])
const variableCategory = useMemo(() => {
if (isEnv) return 'environment'
if (isChatVar) return 'conversation'
if (isLoopVar) return 'loop'
return 'system'
}, [isEnv, isChatVar, isLoopVar])
return ( return (
<div className={cn(className, !readonly && 'cursor-pointer')}> <div className={cn(className, !readonly && 'cursor-pointer')}>
<PortalToFollowElem <PortalToFollowElem
@ -458,10 +463,11 @@ const VarReferencePicker: FC<Props> = ({
</div> </div>
)} )}
<div className='flex items-center text-text-accent'> <div className='flex items-center text-text-accent'>
{!hasValue && <Variable02 className='h-3.5 w-3.5' />}
{isLoading && <RiLoader4Line className='h-3.5 w-3.5 animate-spin text-text-secondary' />} {isLoading && <RiLoader4Line className='h-3.5 w-3.5 animate-spin text-text-secondary' />}
{isEnv && <Env className='h-3.5 w-3.5 text-util-colors-violet-violet-600' />} <VariableIconWithColor
{isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />} variableCategory={variableCategory}
isExceptionVariable={isException}
/>
<div className={cn('ml-0.5 truncate text-xs font-medium', isEnv && '!text-text-secondary', isChatVar && 'text-util-colors-teal-teal-700', isException && 'text-text-warning')} title={varName} style={{ <div className={cn('ml-0.5 truncate text-xs font-medium', isEnv && '!text-text-secondary', isChatVar && 'text-util-colors-teal-teal-700', isException && 'text-text-warning')} title={varName} style={{
maxWidth: maxVarNameWidth, maxWidth: maxVarNameWidth,
}}>{varName}</div> }}>{varName}</div>

View file

@ -5,7 +5,6 @@ import { useHover } from 'ahooks'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { type NodeOutPutVar, type ValueSelector, type Var, VarType } from '@/app/components/workflow/types' import { type NodeOutPutVar, type ValueSelector, type Var, VarType } from '@/app/components/workflow/types'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows' import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows'
import { import {
PortalToFollowElem, PortalToFollowElem,
@ -13,7 +12,6 @@ import {
PortalToFollowElemTrigger, PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem' } from '@/app/components/base/portal-to-follow-elem'
import Input from '@/app/components/base/input' import Input from '@/app/components/base/input'
import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others'
import { checkKeys } from '@/utils/var' import { checkKeys } from '@/utils/var'
import type { StructuredOutput } from '../../../llm/types' import type { StructuredOutput } from '../../../llm/types'
import { Type } from '../../../llm/types' import { Type } from '../../../llm/types'
@ -21,8 +19,8 @@ import PickerStructurePanel from '@/app/components/workflow/nodes/_base/componen
import { varTypeToStructType } from './utils' import { varTypeToStructType } from './utils'
import type { Field } from '@/app/components/workflow/nodes/llm/types' import type { Field } from '@/app/components/workflow/nodes/llm/types'
import { FILE_STRUCT } from '@/app/components/workflow/constants' import { FILE_STRUCT } from '@/app/components/workflow/constants'
import { Loop } from '@/app/components/base/icons/src/vender/workflow'
import { noop } from 'lodash-es' import { noop } from 'lodash-es'
import { VariableIconWithColor } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
type ObjectChildrenProps = { type ObjectChildrenProps = {
nodeId: string nodeId: string
@ -118,7 +116,6 @@ const Item: FC<ItemProps> = ({
const open = (isObj || isStructureOutput) && isHovering const open = (isObj || isStructureOutput) && isHovering
useEffect(() => { useEffect(() => {
onHovering && onHovering(isHovering) onHovering && onHovering(isHovering)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isHovering]) }, [isHovering])
const handleChosen = (e: React.MouseEvent) => { const handleChosen = (e: React.MouseEvent) => {
e.stopPropagation() e.stopPropagation()
@ -132,6 +129,12 @@ const Item: FC<ItemProps> = ({
onChange([nodeId, ...objPath, itemData.variable], itemData) onChange([nodeId, ...objPath, itemData.variable], itemData)
} }
} }
const variableCategory = useMemo(() => {
if (isEnv) return 'environment'
if (isChatVar) return 'conversation'
if (isLoopVar) return 'loop'
return 'system'
}, [isEnv, isChatVar, isSys, isLoopVar])
return ( return (
<PortalToFollowElem <PortalToFollowElem
open={open} open={open}
@ -150,10 +153,10 @@ const Item: FC<ItemProps> = ({
onMouseDown={e => e.preventDefault()} onMouseDown={e => e.preventDefault()}
> >
<div className='flex w-0 grow items-center'> <div className='flex w-0 grow items-center'>
{!isEnv && !isChatVar && !isLoopVar && <Variable02 className={cn('h-3.5 w-3.5 shrink-0 text-text-accent', isException && 'text-text-warning')} />} <VariableIconWithColor
{isEnv && <Env className='h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />} variableCategory={variableCategory}
{isChatVar && <BubbleX className='h-3.5 w-3.5 shrink-0 text-util-colors-teal-teal-700' />} isExceptionVariable={isException}
{isLoopVar && <Loop className='h-3.5 w-3.5 shrink-0 text-util-colors-cyan-cyan-500' />} />
{!isEnv && !isChatVar && ( {!isEnv && !isChatVar && (
<div title={itemData.variable} className='system-sm-medium ml-1 w-0 grow truncate text-text-secondary'>{itemData.variable}</div> <div title={itemData.variable} className='system-sm-medium ml-1 w-0 grow truncate text-text-secondary'>{itemData.variable}</div>
)} )}
@ -219,11 +222,9 @@ const ObjectChildren: FC<ObjectChildrenProps> = ({
const isHovering = isItemHovering || isChildrenHovering const isHovering = isItemHovering || isChildrenHovering
useEffect(() => { useEffect(() => {
onHovering && onHovering(isHovering) onHovering && onHovering(isHovering)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isHovering]) }, [isHovering])
useEffect(() => { useEffect(() => {
onHovering && onHovering(isItemHovering) onHovering && onHovering(isItemHovering)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isItemHovering]) }, [isItemHovering])
// absolute top-[-2px] // absolute top-[-2px]
return ( return (

View file

@ -0,0 +1,28 @@
import { memo } from 'react'
import cn from '@/utils/classnames'
import { useVarIcon } from '../hooks'
import type { VarInInspectType } from '@/types/workflow'
export type VariableIconProps = {
className?: string
variables?: string[]
variableCategory?: VarInInspectType | string
}
const VariableIcon = ({
className,
variables = [],
variableCategory,
}: VariableIconProps) => {
const VarIcon = useVarIcon(variables, variableCategory)
return VarIcon && (
<VarIcon
className={cn(
'size-3.5 shrink-0',
className,
)}
/>
)
}
export default memo(VariableIcon)

View file

@ -0,0 +1,83 @@
import { memo } from 'react'
import { capitalize } from 'lodash-es'
import {
RiErrorWarningFill,
RiMoreLine,
} from '@remixicon/react'
import type { VariablePayload } from '../types'
import { useVarColor } from '../hooks'
import VariableNodeLabel from './variable-node-label'
import VariableIcon from './variable-icon'
import VariableName from './variable-name'
import cn from '@/utils/classnames'
import Tooltip from '@/app/components/base/tooltip'
const VariableLabel = ({
nodeType,
nodeTitle,
variables,
variableType,
className,
errorMsg,
onClick,
isExceptionVariable,
ref,
notShowFullPath,
rightSlot,
}: VariablePayload) => {
const varColorClassName = useVarColor(variables, isExceptionVariable)
return (
<div
className={cn(
'inline-flex h-6 max-w-full items-center space-x-0.5 rounded-md border-[0.5px] border-components-panel-border-subtle bg-components-badge-white-to-dark px-1.5 shadow-xs',
className,
)}
onClick={onClick}
ref={ref}
>
<VariableNodeLabel
nodeType={nodeType}
nodeTitle={nodeTitle}
/>
{
notShowFullPath && (
<>
<RiMoreLine className='h-3 w-3 shrink-0 text-text-secondary' />
<div className='system-xs-regular shrink-0 text-divider-deep'>/</div>
</>
)
}
<VariableIcon
variables={variables}
className={varColorClassName}
/>
<VariableName
variables={variables}
className={cn(varColorClassName)}
notShowFullPath={notShowFullPath}
/>
{
variableType && (
<div className='system-xs-regular shrink-0 text-text-tertiary'>
{capitalize(variableType)}
</div>
)
}
{
!!errorMsg && (
<Tooltip
popupContent={errorMsg}
asChild
>
<RiErrorWarningFill className='h-3 w-3 shrink-0 text-text-destructive' />
</Tooltip>
)
}
{
rightSlot
}
</div>
)
}
export default memo(VariableLabel)

View file

@ -0,0 +1,30 @@
import { memo } from 'react'
import { useVarName } from '../hooks'
import cn from '@/utils/classnames'
type VariableNameProps = {
variables: string[]
className?: string
notShowFullPath?: boolean
}
const VariableName = ({
variables,
className,
notShowFullPath,
}: VariableNameProps) => {
const varName = useVarName(variables, notShowFullPath)
return (
<div
className={cn(
'system-xs-medium truncate',
className,
)}
title={varName}
>
{varName}
</div>
)
}
export default memo(VariableName)

View file

@ -0,0 +1,37 @@
import { memo } from 'react'
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
import type { BlockEnum } from '@/app/components/workflow/types'
type VariableNodeLabelProps = {
nodeType?: BlockEnum
nodeTitle?: string
}
const VariableNodeLabel = ({
nodeType,
nodeTitle,
}: VariableNodeLabelProps) => {
if (!nodeType)
return null
return (
<>
<VarBlockIcon
type={nodeType}
className='shrink-0 text-text-secondary'
/>
{
nodeTitle && (
<div
className='system-xs-medium max-[60px] truncate text-text-secondary'
title={nodeTitle}
>
{nodeTitle}
</div>
)
}
<div className='system-xs-regular shrink-0 text-divider-deep'>/</div>
</>
)
}
export default memo(VariableNodeLabel)

View file

@ -0,0 +1,89 @@
import { useMemo } from 'react'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others'
import { Loop } from '@/app/components/base/icons/src/vender/workflow'
import {
isConversationVar,
isENV,
isSystemVar,
} from '../utils'
import { VarInInspectType } from '@/types/workflow'
export const useVarIcon = (variables: string[], variableCategory?: VarInInspectType | string) => {
if (variableCategory === 'loop')
return Loop
if (isENV(variables) || variableCategory === VarInInspectType.environment || variableCategory === 'environment')
return Env
if (isConversationVar(variables) || variableCategory === VarInInspectType.conversation || variableCategory === 'conversation')
return BubbleX
return Variable02
}
export const useVarColor = (variables: string[], isExceptionVariable?: boolean, variableCategory?: VarInInspectType | string) => {
return useMemo(() => {
if (isExceptionVariable)
return 'text-text-warning'
if (variableCategory === 'loop')
return 'text-util-colors-cyan-cyan-500'
if (isENV(variables) || variableCategory === VarInInspectType.environment || variableCategory === 'environment')
return 'text-util-colors-violet-violet-600'
if (isConversationVar(variables) || variableCategory === VarInInspectType.conversation || variableCategory === 'conversation')
return 'text-util-colors-teal-teal-700'
return 'text-text-accent'
}, [variables, isExceptionVariable])
}
export const useVarName = (variables: string[], notShowFullPath?: boolean) => {
const variableFullPathName = variables.slice(1).join('.')
const variablesLength = variables.length
const varName = useMemo(() => {
const isSystem = isSystemVar(variables)
const varName = notShowFullPath ? variables[variablesLength - 1] : variableFullPathName
return `${isSystem ? 'sys.' : ''}${varName}`
}, [variables, notShowFullPath])
return varName
}
export const useVarBgColorInEditor = (variables: string[], hasError?: boolean) => {
if (hasError) {
return {
hoverBorderColor: 'hover:border-state-destructive-active',
hoverBgColor: 'hover:bg-state-destructive-hover',
selectedBorderColor: '!border-state-destructive-solid',
selectedBgColor: '!bg-state-destructive-hover',
}
}
if (isENV(variables)) {
return {
hoverBorderColor: 'hover:border-util-colors-violet-violet-100',
hoverBgColor: 'hover:bg-util-colors-violet-violet-50',
selectedBorderColor: 'border-util-colors-violet-violet-600',
selectedBgColor: 'bg-util-colors-violet-violet-50',
}
}
if (isConversationVar(variables)) {
return {
hoverBorderColor: 'hover:border-util-colors-teal-teal-100',
hoverBgColor: 'hover:bg-util-colors-teal-teal-50',
selectedBorderColor: 'border-util-colors-teal-teal-600',
selectedBgColor: 'bg-util-colors-teal-teal-50',
}
}
return {
hoverBorderColor: 'hover:border-state-accent-alt',
hoverBgColor: 'hover:bg-state-accent-hover',
selectedBorderColor: 'border-state-accent-solid',
selectedBgColor: 'bg-state-accent-hover',
}
}

View file

@ -0,0 +1,5 @@
export { default as VariableLabelInSelect } from './variable-label-in-select'
export { default as VariableLabelInEditor } from './variable-label-in-editor'
export { default as VariableLabelInNode } from './variable-label-in-node'
export { default as VariableLabelInText } from './variable-label-in-text'
export { default as VariableIconWithColor } from './variable-icon-with-color'

View file

@ -0,0 +1,19 @@
import type { ReactNode } from 'react'
import type {
BlockEnum,
VarType,
} from '@/app/components/workflow/types'
export type VariablePayload = {
className?: string
nodeType?: BlockEnum
nodeTitle?: string
variables: string[]
variableType?: VarType
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void
errorMsg?: string
isExceptionVariable?: boolean
ref?: React.Ref<HTMLDivElement>
notShowFullPath?: boolean
rightSlot?: ReactNode
}

View file

@ -0,0 +1,30 @@
import { memo } from 'react'
import VariableIcon from './base/variable-icon'
import type { VariableIconProps } from './base/variable-icon'
import { useVarColor } from './hooks'
import cn from '@/utils/classnames'
type VariableIconWithColorProps = {
isExceptionVariable?: boolean
} & VariableIconProps
const VariableIconWithColor = ({
isExceptionVariable,
variableCategory,
variables = [],
className,
}: VariableIconWithColorProps) => {
const varColorClassName = useVarColor(variables, isExceptionVariable, variableCategory)
return (
<VariableIcon
variables={variables}
variableCategory={variableCategory}
className={cn(
varColorClassName,
className,
)}
/>
)
}
export default memo(VariableIconWithColor)

View file

@ -0,0 +1,40 @@
import { memo } from 'react'
import type { VariablePayload } from './types'
import VariableLabel from './base/variable-label'
import { useVarBgColorInEditor } from './hooks'
import cn from '@/utils/classnames'
type VariableLabelInEditorProps = {
isSelected?: boolean
} & VariablePayload
const VariableLabelInEditor = ({
isSelected,
variables,
errorMsg,
...rest
}: VariableLabelInEditorProps) => {
const {
hoverBorderColor,
hoverBgColor,
selectedBorderColor,
selectedBgColor,
} = useVarBgColorInEditor(variables, !!errorMsg)
return (
<VariableLabel
className={cn(
'h-[18px] space-x-[1px] rounded-[5px] px-1 shadow-xs',
!isSelected && hoverBgColor,
!isSelected && hoverBorderColor,
isSelected && 'border',
isSelected && selectedBorderColor,
isSelected && selectedBgColor,
)}
variables={variables}
errorMsg={errorMsg}
{...rest}
/>
)
}
export default memo(VariableLabelInEditor)

View file

@ -0,0 +1,17 @@
import { memo } from 'react'
import type { VariablePayload } from './types'
import VariableLabel from './base/variable-label'
import cn from '@/utils/classnames'
const VariableLabelInNode = (variablePayload: VariablePayload) => {
return (
<VariableLabel
className={cn(
'w-full space-x-[1px] bg-workflow-block-parma-bg px-1 shadow-none',
)}
{...variablePayload}
/>
)
}
export default memo(VariableLabelInNode)

View file

@ -0,0 +1,13 @@
import { memo } from 'react'
import type { VariablePayload } from './types'
import VariableLabel from './base/variable-label'
const VariableLabelInSelect = (variablePayload: VariablePayload) => {
return (
<VariableLabel
{...variablePayload}
/>
)
}
export default memo(VariableLabelInSelect)

View file

@ -0,0 +1,17 @@
import { memo } from 'react'
import type { VariablePayload } from './types'
import VariableLabel from './base/variable-label'
import cn from '@/utils/classnames'
const VariableLabelInText = (variablePayload: VariablePayload) => {
return (
<VariableLabel
className={cn(
'h-[18px] space-x-[1px] rounded-[5px] px-1 shadow-xs',
)}
{...variablePayload}
/>
)
}
export default memo(VariableLabelInText)

View file

@ -2,10 +2,13 @@ import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useNodes } from 'reactflow' import { useNodes } from 'reactflow'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import NodeVariableItem from '../variable-assigner/components/node-variable-item'
import type { AssignerNodeType } from './types' import type { AssignerNodeType } from './types'
import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils' import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import { BlockEnum, type Node, type NodeProps } from '@/app/components/workflow/types' import { BlockEnum, type Node, type NodeProps } from '@/app/components/workflow/types'
import {
VariableLabelInNode,
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
import Badge from '@/app/components/base/badge'
const i18nPrefix = 'workflow.nodes.assigner' const i18nPrefix = 'workflow.nodes.assigner'
@ -38,19 +41,16 @@ const NodeComponent: FC<NodeProps<AssignerNodeType>> = ({
if (!variable || variable.length === 0) if (!variable || variable.length === 0)
return null return null
const isSystem = isSystemVar(variable) const isSystem = isSystemVar(variable)
const isEnv = isENV(variable)
const isChatVar = isConversationVar(variable)
const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0]) const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0])
const varName = isSystem ? `sys.${variable[variable.length - 1]}` : variable.slice(1).join('.')
return ( return (
<NodeVariableItem <VariableLabelInNode
key={index} key={index}
node={node as Node} variables={variable}
isEnv={isEnv} nodeType={node?.data.type}
isChatVar={isChatVar} nodeTitle={node?.data.title}
writeMode={value.operation} rightSlot={
varName={varName} value.operation && <Badge className='!ml-auto shrink-0' text={t(`${i18nPrefix}.operations.${value.operation}`)} />
className='bg-workflow-block-parma-bg' }
/> />
) )
})} })}
@ -63,21 +63,17 @@ const NodeComponent: FC<NodeProps<AssignerNodeType>> = ({
if (!variable || variable.length === 0) if (!variable || variable.length === 0)
return null return null
const isSystem = isSystemVar(variable) const isSystem = isSystemVar(variable)
const isEnv = isENV(variable)
const isChatVar = isConversationVar(variable)
const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0]) const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0])
const varName = isSystem ? `sys.${variable[variable.length - 1]}` : variable.slice(1).join('.')
return ( return (
<div className='relative flex flex-col items-start gap-0.5 self-stretch px-3 py-1'> <div className='relative flex flex-col items-start gap-0.5 self-stretch px-3 py-1'>
<NodeVariableItem <VariableLabelInNode
node={node as Node} variables={variable}
isEnv={isEnv} nodeType={node?.data.type}
isChatVar={isChatVar} nodeTitle={node?.data.title}
varName={varName} rightSlot={
writeMode={writeMode} writeMode && <Badge className='!ml-auto shrink-0' text={t(`${i18nPrefix}.operations.${writeMode}`)} />
className='bg-workflow-block-parma-bg' }
/> />
</div> </div>
) )

View file

@ -2,10 +2,12 @@ import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useNodes } from 'reactflow' import { useNodes } from 'reactflow'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import NodeVariableItem from '../variable-assigner/components/node-variable-item'
import type { DocExtractorNodeType } from './types' import type { DocExtractorNodeType } from './types'
import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils' import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import { BlockEnum, type Node, type NodeProps } from '@/app/components/workflow/types' import { BlockEnum, type Node, type NodeProps } from '@/app/components/workflow/types'
import {
VariableLabelInNode,
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
const i18nPrefix = 'workflow.nodes.docExtractor' const i18nPrefix = 'workflow.nodes.docExtractor'
@ -21,19 +23,14 @@ const NodeComponent: FC<NodeProps<DocExtractorNodeType>> = ({
return null return null
const isSystem = isSystemVar(variable) const isSystem = isSystemVar(variable)
const isEnv = isENV(variable)
const isChatVar = isConversationVar(variable)
const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0]) const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0])
const varName = isSystem ? `sys.${variable[variable.length - 1]}` : variable.slice(1).join('.')
return ( return (
<div className='relative px-3'> <div className='relative px-3'>
<div className='system-2xs-medium-uppercase mb-1 text-text-tertiary'>{t(`${i18nPrefix}.inputVar`)}</div> <div className='system-2xs-medium-uppercase mb-1 text-text-tertiary'>{t(`${i18nPrefix}.inputVar`)}</div>
<NodeVariableItem <VariableLabelInNode
node={node as Node} variables={variable}
isEnv={isEnv} nodeType={node?.data.type}
isChatVar={isChatVar} nodeTitle={node?.data.title}
varName={varName}
className='bg-workflow-block-parma-bg'
/> />
</div> </div>
) )

View file

@ -1,19 +1,16 @@
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React from 'react'
import cn from 'classnames'
import type { EndNodeType } from './types' import type { EndNodeType } from './types'
import type { NodeProps, Variable } from '@/app/components/workflow/types' import type { NodeProps, Variable } from '@/app/components/workflow/types'
import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import { import {
useIsChatMode, useIsChatMode,
useWorkflow, useWorkflow,
useWorkflowVariables, useWorkflowVariables,
} from '@/app/components/workflow/hooks' } from '@/app/components/workflow/hooks'
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
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 { BlockEnum } from '@/app/components/workflow/types' import { BlockEnum } from '@/app/components/workflow/types'
import {
VariableLabelInNode,
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
const Node: FC<NodeProps<EndNodeType>> = ({ const Node: FC<NodeProps<EndNodeType>> = ({
id, id,
@ -42,42 +39,20 @@ const Node: FC<NodeProps<EndNodeType>> = ({
<div className='mb-1 space-y-0.5 px-3 py-1'> <div className='mb-1 space-y-0.5 px-3 py-1'>
{filteredOutputs.map(({ value_selector }, index) => { {filteredOutputs.map(({ value_selector }, index) => {
const node = getNode(value_selector[0]) const node = getNode(value_selector[0])
const isSystem = isSystemVar(value_selector)
const isEnv = isENV(value_selector)
const isChatVar = isConversationVar(value_selector)
const varName = isSystem ? `sys.${value_selector[value_selector.length - 1]}` : value_selector[value_selector.length - 1]
const varType = getCurrentVariableType({ const varType = getCurrentVariableType({
valueSelector: value_selector, valueSelector: value_selector,
availableNodes, availableNodes,
isChatMode, isChatMode,
}) })
return (
<div key={index} className='flex h-6 items-center justify-between space-x-1 rounded-md bg-workflow-block-parma-bg px-1 text-xs font-normal text-text-secondary'>
<div className='flex items-center text-xs font-medium text-text-tertiary'>
{!isEnv && !isChatVar && (
<>
<div className='p-[1px]'>
<VarBlockIcon
className='!text-text-primary'
type={node?.data.type || BlockEnum.Start}
/>
</div>
<div className='max-w-[75px] truncate'>{node?.data.title}</div>
<Line3 className='mr-0.5'></Line3>
</>
)}
<div className='flex items-center text-text-accent'>
{!isEnv && !isChatVar && <Variable02 className='h-3.5 w-3.5 shrink-0 text-text-accent' />}
{isEnv && <Env className='h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />}
{isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />}
<div className={cn('ml-0.5 max-w-[50px] truncate text-xs font-medium', (isEnv || isChatVar) && '!max-w-[70px] text-text-primary')}>{varName}</div> return (
</div> <VariableLabelInNode
</div> key={index}
<div className='text-xs font-normal text-text-secondary'> variables={value_selector}
<div className='ml-0.5 max-w-[42px] truncate text-xs font-normal capitalize text-text-tertiary' title={varType}>{varType}</div> nodeType={node?.data.type}
</div> nodeTitle={node?.data.title}
</div> variableType={varType}
/>
) )
})} })}

View file

@ -15,7 +15,7 @@ const Node: FC<NodeProps<HttpNodeType>> = ({
<div className='mb-1 px-3 py-1'> <div className='mb-1 px-3 py-1'>
<div className='flex items-center justify-start rounded-md bg-workflow-block-parma-bg p-1'> <div className='flex items-center justify-start rounded-md bg-workflow-block-parma-bg p-1'>
<div className='flex h-4 shrink-0 items-center rounded bg-components-badge-white-to-dark px-1 text-xs font-semibold uppercase text-text-secondary'>{method}</div> <div className='flex h-4 shrink-0 items-center rounded bg-components-badge-white-to-dark px-1 text-xs font-semibold uppercase text-text-secondary'>{method}</div>
<div className='pl-1 pt-1'> <div className='w-0 grow pl-1 pt-1'>
<ReadonlyInputWithSelectVar <ReadonlyInputWithSelectVar
className='text-text-secondary' className='text-text-secondary'
value={url} value={url}

View file

@ -11,10 +11,10 @@ import {
} from '../utils' } from '../utils'
import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from '../../constants' import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from '../../constants'
import type { ValueSelector } from '../../../types' import type { ValueSelector } from '../../../types'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others' import {
import cn from '@/utils/classnames' VariableLabelInNode,
import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils' } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
const i18nPrefix = 'workflow.nodes.ifElse' const i18nPrefix = 'workflow.nodes.ifElse'
type ConditionValueProps = { type ConditionValueProps = {
@ -32,11 +32,7 @@ const ConditionValue = ({
const variableSelector = variable_selector as ValueSelector const variableSelector = variable_selector as ValueSelector
const variableName = (isSystemVar(variableSelector) ? variableSelector.slice(0).join('.') : variableSelector.slice(1).join('.'))
const operatorName = isComparisonOperatorNeedTranslate(operator) ? t(`workflow.nodes.ifElse.comparisonOperator.${operator}`) : operator const operatorName = isComparisonOperatorNeedTranslate(operator) ? t(`workflow.nodes.ifElse.comparisonOperator.${operator}`) : operator
const notHasValue = comparisonOperatorNotRequireValue(operator)
const isEnvVar = isENV(variableSelector)
const isChatVar = isConversationVar(variableSelector)
const formatValue = useCallback((c: Condition) => { const formatValue = useCallback((c: Condition) => {
const notHasValue = comparisonOperatorNotRequireValue(c.comparison_operator) const notHasValue = comparisonOperatorNotRequireValue(c.comparison_operator)
if (notHasValue) if (notHasValue)
@ -76,19 +72,11 @@ const ConditionValue = ({
return ( return (
<div className='rounded-md bg-workflow-block-parma-bg'> <div className='rounded-md bg-workflow-block-parma-bg'>
<div className='flex h-6 items-center px-1 '> <div className='flex h-6 items-center px-1 '>
{!isEnvVar && !isChatVar && <Variable02 className='mr-1 h-3.5 w-3.5 shrink-0 text-text-accent' />} <VariableLabelInNode
{isEnvVar && <Env className='mr-1 h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />} className='w-0 grow'
{isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />} variables={variableSelector}
notShowFullPath
<div />
className={cn(
'shrink-0 truncate text-xs font-medium text-text-accent',
!notHasValue && 'max-w-[70px]',
)}
title={variableName}
>
{variableName}
</div>
<div <div
className='mx-1 shrink-0 text-xs font-medium text-text-primary' className='mx-1 shrink-0 text-xs font-medium text-text-primary'
title={operatorName} title={operatorName}

View file

@ -10,15 +10,15 @@ import {
isComparisonOperatorNeedTranslate, isComparisonOperatorNeedTranslate,
} from '../utils' } from '../utils'
import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from '../../constants' import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from '../../constants'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others'
import cn from '@/utils/classnames'
import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import { isExceptionVariable } from '@/app/components/workflow/utils' import { isExceptionVariable } from '@/app/components/workflow/utils'
import type { import type {
CommonNodeType, CommonNodeType,
Node, Node,
} from '@/app/components/workflow/types' } from '@/app/components/workflow/types'
import {
VariableLabelInText,
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
type ConditionValueProps = { type ConditionValueProps = {
variableSelector: string[] variableSelector: string[]
@ -37,8 +37,6 @@ const ConditionValue = ({
const variableName = labelName || (isSystemVar(variableSelector) ? variableSelector.slice(0).join('.') : variableSelector.slice(1).join('.')) const variableName = labelName || (isSystemVar(variableSelector) ? variableSelector.slice(0).join('.') : variableSelector.slice(1).join('.'))
const operatorName = isComparisonOperatorNeedTranslate(operator) ? t(`workflow.nodes.ifElse.comparisonOperator.${operator}`) : operator const operatorName = isComparisonOperatorNeedTranslate(operator) ? t(`workflow.nodes.ifElse.comparisonOperator.${operator}`) : operator
const notHasValue = comparisonOperatorNotRequireValue(operator) const notHasValue = comparisonOperatorNotRequireValue(operator)
const isEnvVar = isENV(variableSelector)
const isChatVar = isConversationVar(variableSelector)
const node: Node<CommonNodeType> | undefined = nodes.find(n => n.id === variableSelector[0]) as Node<CommonNodeType> const node: Node<CommonNodeType> | undefined = nodes.find(n => n.id === variableSelector[0]) as Node<CommonNodeType>
const isException = isExceptionVariable(variableName, node?.data.type) const isException = isExceptionVariable(variableName, node?.data.type)
const formatValue = useMemo(() => { const formatValue = useMemo(() => {
@ -76,20 +74,14 @@ const ConditionValue = ({
return ( return (
<div className='flex h-6 items-center rounded-md bg-workflow-block-parma-bg px-1'> <div className='flex h-6 items-center rounded-md bg-workflow-block-parma-bg px-1'>
{!isEnvVar && !isChatVar && <Variable02 className={cn('mr-1 h-3.5 w-3.5 shrink-0 text-text-accent', isException && 'text-text-warning')} />} <VariableLabelInText
{isEnvVar && <Env className='mr-1 h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />} className='w-0 grow'
{isChatVar && <BubbleX className='h-3.5 w-3.5 shrink-0 text-util-colors-teal-teal-700' />} variables={variableSelector}
nodeTitle={node?.data.title}
<div nodeType={node?.data.type}
className={cn( isExceptionVariable={isException}
'ml-0.5 shrink-[2] truncate text-xs font-medium text-text-accent', notShowFullPath
!notHasValue && 'max-w-[70px]', />
isException && 'text-text-warning',
)}
title={variableName}
>
{variableName}
</div>
<div <div
className='mx-1 shrink-0 text-xs font-medium text-text-primary' className='mx-1 shrink-0 text-xs font-medium text-text-primary'
title={operatorName} title={operatorName}

View file

@ -2,10 +2,12 @@ import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useNodes } from 'reactflow' import { useNodes } from 'reactflow'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import NodeVariableItem from '../variable-assigner/components/node-variable-item'
import type { ListFilterNodeType } from './types' import type { ListFilterNodeType } from './types'
import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils' import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import { BlockEnum, type Node, type NodeProps } from '@/app/components/workflow/types' import { BlockEnum, type Node, type NodeProps } from '@/app/components/workflow/types'
import {
VariableLabelInNode,
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
const i18nPrefix = 'workflow.nodes.listFilter' const i18nPrefix = 'workflow.nodes.listFilter'
@ -21,19 +23,14 @@ const NodeComponent: FC<NodeProps<ListFilterNodeType>> = ({
return null return null
const isSystem = isSystemVar(variable) const isSystem = isSystemVar(variable)
const isEnv = isENV(variable)
const isChatVar = isConversationVar(variable)
const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0]) const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0])
const varName = isSystem ? `sys.${variable[variable.length - 1]}` : variable.slice(1).join('.')
return ( return (
<div className='relative px-3'> <div className='relative px-3'>
<div className='system-2xs-medium-uppercase mb-1 text-text-tertiary'>{t(`${i18nPrefix}.inputVar`)}</div> <div className='system-2xs-medium-uppercase mb-1 text-text-tertiary'>{t(`${i18nPrefix}.inputVar`)}</div>
<NodeVariableItem <VariableLabelInNode
node={node as Node} variables={variable}
isEnv={isEnv} nodeType={node?.data.type}
isChatVar={isChatVar} nodeTitle={node?.data.title}
varName={varName}
className='bg-workflow-block-parma-bg'
/> />
</div> </div>
) )

View file

@ -11,10 +11,10 @@ import {
} from '../utils' } from '../utils'
import type { ValueSelector } from '../../../types' import type { ValueSelector } from '../../../types'
import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from './../default' import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from './../default'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others' import {
import cn from '@/utils/classnames' VariableLabelInNode,
import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils' } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
const i18nPrefix = 'workflow.nodes.ifElse' const i18nPrefix = 'workflow.nodes.ifElse'
type ConditionValueProps = { type ConditionValueProps = {
@ -32,11 +32,7 @@ const ConditionValue = ({
const variableSelector = variable_selector as ValueSelector const variableSelector = variable_selector as ValueSelector
const variableName = (isSystemVar(variableSelector) ? variableSelector.slice(0).join('.') : variableSelector.slice(1).join('.'))
const operatorName = isComparisonOperatorNeedTranslate(operator) ? t(`workflow.nodes.ifElse.comparisonOperator.${operator}`) : operator const operatorName = isComparisonOperatorNeedTranslate(operator) ? t(`workflow.nodes.ifElse.comparisonOperator.${operator}`) : operator
const notHasValue = comparisonOperatorNotRequireValue(operator)
const isEnvVar = isENV(variableSelector)
const isChatVar = isConversationVar(variableSelector)
const formatValue = useCallback((c: Condition) => { const formatValue = useCallback((c: Condition) => {
const notHasValue = comparisonOperatorNotRequireValue(c.comparison_operator) const notHasValue = comparisonOperatorNotRequireValue(c.comparison_operator)
if (notHasValue) if (notHasValue)
@ -76,19 +72,11 @@ const ConditionValue = ({
return ( return (
<div className='rounded-md bg-workflow-block-parma-bg'> <div className='rounded-md bg-workflow-block-parma-bg'>
<div className='flex h-6 items-center px-1 '> <div className='flex h-6 items-center px-1 '>
{!isEnvVar && !isChatVar && <Variable02 className='mr-1 h-3.5 w-3.5 shrink-0 text-text-accent' />} <VariableLabelInNode
{isEnvVar && <Env className='mr-1 h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />} className='w-0 grow'
{isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />} variables={variableSelector}
notShowFullPath
<div />
className={cn(
'shrink-0 truncate text-xs font-medium text-text-accent',
!notHasValue && 'max-w-[70px]',
)}
title={variableName}
>
{variableName}
</div>
<div <div
className='mx-1 shrink-0 text-xs font-medium text-text-primary' className='mx-1 shrink-0 text-xs font-medium text-text-primary'
title={operatorName} title={operatorName}

View file

@ -9,10 +9,10 @@ import {
isComparisonOperatorNeedTranslate, isComparisonOperatorNeedTranslate,
} from '../utils' } from '../utils'
import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from './../default' import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from './../default'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others' import {
import cn from '@/utils/classnames' VariableLabelInNode,
import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils' } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
type ConditionValueProps = { type ConditionValueProps = {
variableSelector: string[] variableSelector: string[]
@ -27,11 +27,8 @@ const ConditionValue = ({
value, value,
}: ConditionValueProps) => { }: ConditionValueProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const variableName = labelName || (isSystemVar(variableSelector) ? variableSelector.slice(0).join('.') : variableSelector.slice(1).join('.'))
const operatorName = isComparisonOperatorNeedTranslate(operator) ? t(`workflow.nodes.ifElse.comparisonOperator.${operator}`) : operator const operatorName = isComparisonOperatorNeedTranslate(operator) ? t(`workflow.nodes.ifElse.comparisonOperator.${operator}`) : operator
const notHasValue = comparisonOperatorNotRequireValue(operator) const notHasValue = comparisonOperatorNotRequireValue(operator)
const isEnvVar = isENV(variableSelector)
const isChatVar = isConversationVar(variableSelector)
const formatValue = useMemo(() => { const formatValue = useMemo(() => {
if (notHasValue) if (notHasValue)
return '' return ''
@ -67,19 +64,11 @@ const ConditionValue = ({
return ( return (
<div className='flex h-6 items-center rounded-md bg-workflow-block-parma-bg px-1'> <div className='flex h-6 items-center rounded-md bg-workflow-block-parma-bg px-1'>
{!isEnvVar && !isChatVar && <Variable02 className='mr-1 h-3.5 w-3.5 shrink-0 text-text-accent' />} <VariableLabelInNode
{isEnvVar && <Env className='mr-1 h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />} className='w-0 grow'
{isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />} variables={variableSelector}
notShowFullPath
<div />
className={cn(
'shrink-0 truncate text-xs font-medium text-text-accent',
!notHasValue && 'max-w-[70px]',
)}
title={variableName}
>
{variableName}
</div>
<div <div
className='mx-1 shrink-0 text-xs font-medium text-text-primary' className='mx-1 shrink-0 text-xs font-medium text-text-primary'
title={operatorName} title={operatorName}

View file

@ -18,10 +18,12 @@ import {
} from '../hooks' } from '../hooks'
import { filterVar } from '../utils' import { filterVar } from '../utils'
import AddVariable from './add-variable' import AddVariable from './add-variable'
import NodeVariableItem from './node-variable-item' import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { isExceptionVariable } from '@/app/components/workflow/utils' import { isExceptionVariable } from '@/app/components/workflow/utils'
import {
VariableLabelInNode,
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
const i18nPrefix = 'workflow.nodes.variableAssigner' const i18nPrefix = 'workflow.nodes.variableAssigner'
type GroupItem = { type GroupItem = {
@ -122,27 +124,29 @@ const NodeGroupItem = ({
) )
} }
{ {
!!item.variables.length && item.variables.map((variable = [], index) => { !!item.variables.length && (
const isSystem = isSystemVar(variable) <div className='space-y-0.5'>
const isEnv = isENV(variable) {
const isChatVar = isConversationVar(variable) item.variables.map((variable = [], index) => {
const isSystem = isSystemVar(variable)
const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0]) const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0])
const varName = isSystem ? `sys.${variable[variable.length - 1]}` : variable.slice(1).join('.') const varName = isSystem ? `sys.${variable[variable.length - 1]}` : variable.slice(1).join('.')
const isException = isExceptionVariable(varName, node?.data.type) const isException = isExceptionVariable(varName, node?.data.type)
return ( return (
<NodeVariableItem <VariableLabelInNode
key={index} key={index}
isEnv={isEnv} variables={variable}
isChatVar={isChatVar} nodeType={node?.data.type}
isException={isException} nodeTitle={node?.data.title}
node={node as Node} isExceptionVariable={isException}
varName={varName} />
showBorder={showSelectedBorder || showSelectionBorder} )
/> })
) }
}) </div>
)
} }
</div> </div>
) )

View file

@ -1,111 +0,0 @@
import {
memo,
useMemo,
} from 'react'
import { useTranslation } from 'react-i18next'
import cn from '@/utils/classnames'
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
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 Badge from '@/app/components/base/badge'
import type { Node } from '@/app/components/workflow/types'
type NodeVariableItemProps = {
isEnv: boolean
isChatVar: boolean
node: Node
varName: string
writeMode?: string
showBorder?: boolean
className?: string
isException?: boolean
}
const i18nPrefix = 'workflow.nodes.assigner'
const NodeVariableItem = ({
isEnv,
isChatVar,
node,
varName,
writeMode,
showBorder,
className,
isException,
}: NodeVariableItemProps) => {
const { t } = useTranslation()
const VariableIcon = useMemo(() => {
if (isEnv) {
return (
<Env className='h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />
)
}
if (isChatVar) {
return (
<BubbleX className='h-3.5 w-3.5 shrink-0 text-util-colors-teal-teal-700' />
)
}
return (
<Variable02
className={cn(
'h-3.5 w-3.5 shrink-0 text-text-accent',
isException && 'text-text-warning',
)}
/>
)
}, [isEnv, isChatVar, isException])
const VariableName = useMemo(() => {
return (
<div
className={cn(
'system-xs-medium ml-0.5 shrink truncate text-text-accent',
isEnv && 'text-text-primary',
isException && 'text-text-warning',
isChatVar && 'text-util-colors-teal-teal-700',
)}
title={varName}
>
{varName}
</div>
)
}, [isEnv, isChatVar, varName, isException])
return (
<div className={cn(
'relative flex items-center gap-1 self-stretch rounded-md bg-workflow-block-parma-bg p-[3px] pl-[5px]',
showBorder && '!bg-state-base-hover',
className,
)}>
<div className='flex w-0 grow items-center'>
{
node && (
<>
<div className='shrink-0 p-[1px]'>
<VarBlockIcon
className='!text-text-primary'
type={node.data.type}
/>
</div>
<div
className='mx-0.5 shrink-[1000] truncate text-xs font-medium text-text-secondary'
title={node?.data.title}
>
{node?.data.title}
</div>
<Line3 className='mr-0.5 shrink-0'></Line3>
</>
)
}
{VariableIcon}
{VariableName}
</div>
{writeMode && <Badge className='shrink-0' text={t(`${i18nPrefix}.operations.${writeMode}`)} />}
</div>
)
}
export default memo(NodeVariableItem)

View file

@ -11,16 +11,12 @@ import {
import ActionButton from '@/app/components/base/action-button' import ActionButton from '@/app/components/base/action-button'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
import BlockIcon from '@/app/components/workflow/block-icon' import BlockIcon from '@/app/components/workflow/block-icon'
import {
BubbleX,
Env,
} from '@/app/components/base/icons/src/vender/line/others'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import type { currentVarType } from './panel' import type { currentVarType } from './panel'
import { VarInInspectType } from '@/types/workflow' import { VarInInspectType } from '@/types/workflow'
import type { NodeWithVar, VarInInspect } from '@/types/workflow' import type { NodeWithVar, VarInInspect } from '@/types/workflow'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { useToolIcon } from '../hooks' import { useToolIcon } from '../hooks'
import { VariableIconWithColor } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
type Props = { type Props = {
nodeData?: NodeWithVar nodeData?: NodeWithVar
@ -158,9 +154,11 @@ const Group = ({
)} )}
onClick={() => handleSelectVar(varItem, varType)} onClick={() => handleSelectVar(varItem, varType)}
> >
{isEnv && <Env className='h-4 w-4 shrink-0 text-util-colors-violet-violet-600' />} <VariableIconWithColor
{isChatVar && <BubbleX className='h-4 w-4 shrink-0 text-util-colors-teal-teal-700' />} variableCategory={varType}
{(isSystem || nodeData) && <Variable02 className={cn('h-4 w-4 shrink-0 text-text-accent', ['error_type', 'error_message'].includes(varItem.name) && 'text-text-warning')} />} isExceptionVariable={['error_type', 'error_message'].includes(varItem.name)}
className='size-4'
/>
<div className='system-sm-medium grow truncate text-text-secondary'>{varItem.name}</div> <div className='system-sm-medium grow truncate text-text-secondary'>{varItem.name}</div>
<div className='system-xs-regular shrink-0 text-text-tertiary'>{varItem.value_type}</div> <div className='system-xs-regular shrink-0 text-text-tertiary'>{varItem.value_type}</div>
</div> </div>

View file

@ -14,12 +14,11 @@ import Badge from '@/app/components/base/badge'
import CopyFeedback from '@/app/components/base/copy-feedback' import CopyFeedback from '@/app/components/base/copy-feedback'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
import BlockIcon from '@/app/components/workflow/block-icon' import BlockIcon from '@/app/components/workflow/block-icon'
import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import Loading from '@/app/components/base/loading' import Loading from '@/app/components/base/loading'
import type { currentVarType } from './panel' import type { currentVarType } from './panel'
import { VarInInspectType } from '@/types/workflow' import { VarInInspectType } from '@/types/workflow'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { VariableIconWithColor } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
type Props = { type Props = {
currentNodeVar?: currentVarType currentNodeVar?: currentVarType
@ -86,15 +85,14 @@ const Right = ({
<div className='flex w-0 grow items-center gap-1'> <div className='flex w-0 grow items-center gap-1'>
{currentNodeVar && ( {currentNodeVar && (
<> <>
{currentNodeVar.nodeType === VarInInspectType.environment && ( {
<Env className='h-4 w-4 shrink-0 text-util-colors-violet-violet-600' /> [VarInInspectType.environment, VarInInspectType.conversation, VarInInspectType.system].includes(currentNodeVar.nodeType as VarInInspectType) && (
)} <VariableIconWithColor
{currentNodeVar.nodeType === VarInInspectType.conversation && ( variableCategory={currentNodeVar.nodeType as VarInInspectType}
<BubbleX className='h-4 w-4 shrink-0 text-util-colors-teal-teal-700' /> className='size-4'
)} />
{currentNodeVar.nodeType === VarInInspectType.system && ( )
<Variable02 className='h-4 w-4 shrink-0 text-text-accent' /> }
)}
{currentNodeVar.nodeType !== VarInInspectType.environment && currentNodeVar.nodeType !== VarInInspectType.conversation && currentNodeVar.nodeType !== VarInInspectType.system && ( {currentNodeVar.nodeType !== VarInInspectType.environment && currentNodeVar.nodeType !== VarInInspectType.conversation && currentNodeVar.nodeType !== VarInInspectType.system && (
<> <>
<BlockIcon <BlockIcon