mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 01:18:05 +08:00
chore(web): new lint setup (#30020)
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
This commit is contained in:
@ -1,26 +1,26 @@
|
||||
import type { LoopNodeType } from './types'
|
||||
import type {
|
||||
OnSelectBlock,
|
||||
} from '@/app/components/workflow/types'
|
||||
import {
|
||||
RiAddLine,
|
||||
} from '@remixicon/react'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
} from 'react'
|
||||
import {
|
||||
RiAddLine,
|
||||
} from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||
import {
|
||||
BlockEnum,
|
||||
} from '@/app/components/workflow/types'
|
||||
|
||||
import { cn } from '@/utils/classnames'
|
||||
import {
|
||||
useAvailableBlocks,
|
||||
useNodesInteractions,
|
||||
useNodesReadOnly,
|
||||
} from '../../hooks'
|
||||
import type { LoopNodeType } from './types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||
|
||||
import type {
|
||||
OnSelectBlock,
|
||||
} from '@/app/components/workflow/types'
|
||||
import {
|
||||
BlockEnum,
|
||||
} from '@/app/components/workflow/types'
|
||||
|
||||
type AddBlockProps = {
|
||||
loopNodeId: string
|
||||
@ -53,24 +53,25 @@ const AddBlock = ({
|
||||
'system-sm-medium relative inline-flex h-8 cursor-pointer items-center rounded-lg border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-3 text-components-button-secondary-text shadow-xs backdrop-blur-[5px] hover:bg-components-button-secondary-bg-hover',
|
||||
`${nodesReadOnly && '!cursor-not-allowed bg-components-button-secondary-bg-disabled'}`,
|
||||
open && 'bg-components-button-secondary-bg-hover',
|
||||
)}>
|
||||
<RiAddLine className='mr-1 h-4 w-4' />
|
||||
)}
|
||||
>
|
||||
<RiAddLine className="mr-1 h-4 w-4" />
|
||||
{t('workflow.common.addBlock')}
|
||||
</div>
|
||||
)
|
||||
}, [nodesReadOnly, t])
|
||||
|
||||
return (
|
||||
<div className='absolute left-14 top-7 z-10 flex h-8 items-center'>
|
||||
<div className='group/insert relative h-0.5 w-16 bg-gray-300'>
|
||||
<div className='absolute right-0 top-1/2 h-2 w-0.5 -translate-y-1/2 bg-primary-500'></div>
|
||||
<div className="absolute left-14 top-7 z-10 flex h-8 items-center">
|
||||
<div className="group/insert relative h-0.5 w-16 bg-gray-300">
|
||||
<div className="absolute right-0 top-1/2 h-2 w-0.5 -translate-y-1/2 bg-primary-500"></div>
|
||||
</div>
|
||||
<BlockSelector
|
||||
disabled={nodesReadOnly}
|
||||
onSelect={handleSelect}
|
||||
trigger={renderTriggerElement}
|
||||
triggerInnerClassName='inline-flex'
|
||||
popupClassName='!min-w-[256px]'
|
||||
triggerInnerClassName="inline-flex"
|
||||
popupClassName="!min-w-[256px]"
|
||||
availableBlocksTypes={availableNextBlocks}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
import type { HandleAddCondition } from '../types'
|
||||
import type {
|
||||
NodeOutPutVar,
|
||||
ValueSelector,
|
||||
Var,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { RiAddLine } from '@remixicon/react'
|
||||
import {
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiAddLine } from '@remixicon/react'
|
||||
import type { HandleAddCondition } from '../types'
|
||||
import Button from '@/app/components/base/button'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
@ -12,11 +17,6 @@ import {
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||
import type {
|
||||
NodeOutPutVar,
|
||||
ValueSelector,
|
||||
Var,
|
||||
} from '@/app/components/workflow/types'
|
||||
|
||||
type ConditionAddProps = {
|
||||
className?: string
|
||||
@ -42,7 +42,7 @@ const ConditionAdd = ({
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement='bottom-start'
|
||||
placement="bottom-start"
|
||||
offset={{
|
||||
mainAxis: 4,
|
||||
crossAxis: 0,
|
||||
@ -50,16 +50,16 @@ const ConditionAdd = ({
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(!open)}>
|
||||
<Button
|
||||
size='small'
|
||||
size="small"
|
||||
className={className}
|
||||
disabled={disabled}
|
||||
>
|
||||
<RiAddLine className='mr-1 h-3.5 w-3.5' />
|
||||
<RiAddLine className="mr-1 h-3.5 w-3.5" />
|
||||
{t('workflow.nodes.ifElse.addCondition')}
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[1000]'>
|
||||
<div className='w-[296px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg'>
|
||||
<PortalToFollowElemContent className="z-[1000]">
|
||||
<div className="w-[296px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg">
|
||||
<VarReferenceVars
|
||||
vars={variables}
|
||||
isSupportFileVar
|
||||
|
||||
@ -1,20 +1,22 @@
|
||||
import type { ValueSelector } from '../../../types'
|
||||
import type { Condition } from '../types'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ComparisonOperator, type Condition } from '../types'
|
||||
import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
|
||||
import {
|
||||
VariableLabelInNode,
|
||||
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
|
||||
import { ComparisonOperator } from '../types'
|
||||
import {
|
||||
comparisonOperatorNotRequireValue,
|
||||
isComparisonOperatorNeedTranslate,
|
||||
isEmptyRelatedOperator,
|
||||
} from '../utils'
|
||||
import type { ValueSelector } from '../../../types'
|
||||
import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from './../default'
|
||||
import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
|
||||
import {
|
||||
VariableLabelInNode,
|
||||
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
|
||||
|
||||
const i18nPrefix = 'workflow.nodes.ifElse'
|
||||
|
||||
type ConditionValueProps = {
|
||||
@ -39,7 +41,7 @@ const ConditionValue = ({
|
||||
return ''
|
||||
|
||||
const value = c.value as string
|
||||
return value.replace(/{{#([^#]*)#}}/g, (a, b) => {
|
||||
return value.replace(/\{\{#([^#]*)#\}\}/g, (a, b) => {
|
||||
const arr: string[] = b.split('.')
|
||||
if (isSystemVar(arr))
|
||||
return `{{${b}}}`
|
||||
@ -57,41 +59,41 @@ const ConditionValue = ({
|
||||
if (isSelect) {
|
||||
const name = [...FILE_TYPE_OPTIONS, ...TRANSFER_METHOD].filter(item => item.value === (Array.isArray(c.value) ? c.value[0] : c.value))[0]
|
||||
return name
|
||||
? t(`workflow.nodes.ifElse.optionName.${name.i18nKey}`).replace(/{{#([^#]*)#}}/g, (a, b) => {
|
||||
const arr: string[] = b.split('.')
|
||||
if (isSystemVar(arr))
|
||||
return `{{${b}}}`
|
||||
? t(`workflow.nodes.ifElse.optionName.${name.i18nKey}`).replace(/\{\{#([^#]*)#\}\}/g, (a, b) => {
|
||||
const arr: string[] = b.split('.')
|
||||
if (isSystemVar(arr))
|
||||
return `{{${b}}}`
|
||||
|
||||
return `{{${arr.slice(1).join('.')}}}`
|
||||
})
|
||||
return `{{${arr.slice(1).join('.')}}}`
|
||||
})
|
||||
: ''
|
||||
}
|
||||
return ''
|
||||
}, [t])
|
||||
|
||||
return (
|
||||
<div className='rounded-md bg-workflow-block-parma-bg'>
|
||||
<div className='flex h-6 items-center px-1 '>
|
||||
<div className="rounded-md bg-workflow-block-parma-bg">
|
||||
<div className="flex h-6 items-center px-1 ">
|
||||
<VariableLabelInNode
|
||||
className='w-0 grow'
|
||||
className="w-0 grow"
|
||||
variables={variableSelector}
|
||||
notShowFullPath
|
||||
/>
|
||||
<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}
|
||||
>
|
||||
{operatorName}
|
||||
</div>
|
||||
</div>
|
||||
<div className='ml-[10px] border-l border-divider-regular pl-[10px]'>
|
||||
<div className="ml-[10px] border-l border-divider-regular pl-[10px]">
|
||||
{
|
||||
sub_variable_condition?.conditions.map((c: Condition, index) => (
|
||||
<div className='relative flex h-6 items-center space-x-1' key={c.id}>
|
||||
<div className='system-xs-medium text-text-accent'>{c.key}</div>
|
||||
<div className='system-xs-medium text-text-primary'>{isComparisonOperatorNeedTranslate(c.comparison_operator) ? t(`workflow.nodes.ifElse.comparisonOperator.${c.comparison_operator}`) : c.comparison_operator}</div>
|
||||
{c.comparison_operator && !isEmptyRelatedOperator(c.comparison_operator) && <div className='system-xs-regular text-text-secondary'>{isSelect(c) ? selectName(c) : formatValue(c)}</div>}
|
||||
{index !== sub_variable_condition.conditions.length - 1 && (<div className='absolute bottom-[-10px] right-1 z-10 text-[10px] font-medium uppercase leading-4 text-text-accent'>{t(`${i18nPrefix}.${sub_variable_condition.logical_operator}`)}</div>)}
|
||||
<div className="relative flex h-6 items-center space-x-1" key={c.id}>
|
||||
<div className="system-xs-medium text-text-accent">{c.key}</div>
|
||||
<div className="system-xs-medium text-text-primary">{isComparisonOperatorNeedTranslate(c.comparison_operator) ? t(`workflow.nodes.ifElse.comparisonOperator.${c.comparison_operator}`) : c.comparison_operator}</div>
|
||||
{c.comparison_operator && !isEmptyRelatedOperator(c.comparison_operator) && <div className="system-xs-regular text-text-secondary">{isSelect(c) ? selectName(c) : formatValue(c)}</div>}
|
||||
{index !== sub_variable_condition.conditions.length - 1 && (<div className="absolute bottom-[-10px] right-1 z-10 text-[10px] font-medium uppercase leading-4 text-text-accent">{t(`${i18nPrefix}.${sub_variable_condition.logical_operator}`)}</div>)}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import PromptEditor from '@/app/components/base/prompt-editor'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import type {
|
||||
Node,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import PromptEditor from '@/app/components/base/prompt-editor'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
||||
type ConditionInputProps = {
|
||||
disabled?: boolean
|
||||
|
||||
@ -1,42 +1,42 @@
|
||||
import {
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiDeleteBinLine } from '@remixicon/react'
|
||||
import { produce } from 'immer'
|
||||
import type { VarType as NumberVarType } from '../../../tool/types'
|
||||
import type {
|
||||
Condition,
|
||||
HandleAddSubVariableCondition,
|
||||
HandleRemoveCondition,
|
||||
handleRemoveSubVariableCondition,
|
||||
HandleToggleSubVariableConditionLogicalOperator,
|
||||
HandleUpdateCondition,
|
||||
HandleUpdateSubVariableCondition,
|
||||
handleRemoveSubVariableCondition,
|
||||
} from '../../types'
|
||||
import {
|
||||
ComparisonOperator,
|
||||
} from '../../types'
|
||||
import ConditionNumberInput from '../condition-number-input'
|
||||
import ConditionWrap from '../condition-wrap'
|
||||
import { comparisonOperatorNotRequireValue, getOperators } from './../../utils'
|
||||
import ConditionOperator from './condition-operator'
|
||||
import ConditionInput from './condition-input'
|
||||
import { FILE_TYPE_OPTIONS, SUB_VARIABLES, TRANSFER_METHOD } from './../../default'
|
||||
import type {
|
||||
Node,
|
||||
NodeOutPutVar,
|
||||
ValueSelector,
|
||||
Var,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { RiDeleteBinLine } from '@remixicon/react'
|
||||
import { produce } from 'immer'
|
||||
import {
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import { SimpleSelect as Select } from '@/app/components/base/select'
|
||||
import BoolValue from '@/app/components/workflow/panel/chat-variable-panel/components/bool-value'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { SimpleSelect as Select } from '@/app/components/base/select'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import {
|
||||
ComparisonOperator,
|
||||
} from '../../types'
|
||||
import ConditionNumberInput from '../condition-number-input'
|
||||
import ConditionWrap from '../condition-wrap'
|
||||
import { FILE_TYPE_OPTIONS, SUB_VARIABLES, TRANSFER_METHOD } from './../../default'
|
||||
import { comparisonOperatorNotRequireValue, getOperators } from './../../utils'
|
||||
import ConditionInput from './condition-input'
|
||||
import ConditionOperator from './condition-operator'
|
||||
import ConditionVarSelector from './condition-var-selector'
|
||||
import BoolValue from '@/app/components/workflow/panel/chat-variable-panel/components/bool-value'
|
||||
|
||||
const optionNameI18NPrefix = 'workflow.nodes.ifElse.optionName'
|
||||
|
||||
@ -209,45 +209,48 @@ const ConditionItem = ({
|
||||
<div className={cn(
|
||||
'grow rounded-lg bg-components-input-bg-normal',
|
||||
isHovered && 'bg-state-destructive-hover',
|
||||
)}>
|
||||
<div className='flex items-center p-1'>
|
||||
<div className='w-0 grow'>
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center p-1">
|
||||
<div className="w-0 grow">
|
||||
{isSubVarSelect
|
||||
? (
|
||||
<Select
|
||||
wrapperClassName='h-6'
|
||||
className='pl-0 text-xs'
|
||||
optionWrapClassName='w-[165px] max-h-none'
|
||||
defaultValue={condition.key}
|
||||
items={subVarOptions}
|
||||
onSelect={item => handleSubVarKeyChange(item.value as string)}
|
||||
renderTrigger={item => (
|
||||
item
|
||||
? <div className='flex cursor-pointer justify-start'>
|
||||
<div className='inline-flex h-6 max-w-full items-center rounded-md border-[0.5px] border-components-panel-border-subtle bg-components-badge-white-to-dark px-1.5 text-text-accent shadow-xs'>
|
||||
<Variable02 className='h-3.5 w-3.5 shrink-0 text-text-accent' />
|
||||
<div className='system-xs-medium ml-0.5 truncate'>{item?.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
: <div className='system-sm-regular text-left text-components-input-text-placeholder'>{t('common.placeholder.select')}</div>
|
||||
)}
|
||||
hideChecked
|
||||
/>
|
||||
)
|
||||
<Select
|
||||
wrapperClassName="h-6"
|
||||
className="pl-0 text-xs"
|
||||
optionWrapClassName="w-[165px] max-h-none"
|
||||
defaultValue={condition.key}
|
||||
items={subVarOptions}
|
||||
onSelect={item => handleSubVarKeyChange(item.value as string)}
|
||||
renderTrigger={item => (
|
||||
item
|
||||
? (
|
||||
<div className="flex cursor-pointer justify-start">
|
||||
<div className="inline-flex h-6 max-w-full items-center rounded-md border-[0.5px] border-components-panel-border-subtle bg-components-badge-white-to-dark px-1.5 text-text-accent shadow-xs">
|
||||
<Variable02 className="h-3.5 w-3.5 shrink-0 text-text-accent" />
|
||||
<div className="system-xs-medium ml-0.5 truncate">{item?.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
: <div className="system-sm-regular text-left text-components-input-text-placeholder">{t('common.placeholder.select')}</div>
|
||||
)}
|
||||
hideChecked
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<ConditionVarSelector
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
valueSelector={condition.variable_selector || []}
|
||||
varType={condition.varType}
|
||||
availableNodes={availableNodes}
|
||||
nodesOutputVars={availableVars}
|
||||
onChange={handleVarChange}
|
||||
/>
|
||||
)}
|
||||
<ConditionVarSelector
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
valueSelector={condition.variable_selector || []}
|
||||
varType={condition.varType}
|
||||
availableNodes={availableNodes}
|
||||
nodesOutputVars={availableVars}
|
||||
onChange={handleVarChange}
|
||||
/>
|
||||
)}
|
||||
|
||||
</div>
|
||||
<div className='mx-1 h-3 w-[1px] bg-divider-regular'></div>
|
||||
<div className="mx-1 h-3 w-[1px] bg-divider-regular"></div>
|
||||
<ConditionOperator
|
||||
disabled={!canChooseOperator}
|
||||
varType={condition.varType}
|
||||
@ -258,7 +261,7 @@ const ConditionItem = ({
|
||||
</div>
|
||||
{
|
||||
!comparisonOperatorNotRequireValue(condition.comparison_operator) && !isNotInput && condition.varType !== VarType.number && condition.varType !== VarType.boolean && (
|
||||
<div className='max-h-[100px] overflow-y-auto border-t border-t-divider-subtle px-2 py-1'>
|
||||
<div className="max-h-[100px] overflow-y-auto border-t border-t-divider-subtle px-2 py-1">
|
||||
<ConditionInput
|
||||
disabled={disabled}
|
||||
value={condition.value as string}
|
||||
@ -269,16 +272,17 @@ const ConditionItem = ({
|
||||
)
|
||||
}
|
||||
{!comparisonOperatorNotRequireValue(condition.comparison_operator) && condition.varType === VarType.boolean
|
||||
&& <div className='p-1'>
|
||||
<BoolValue
|
||||
value={condition.value as boolean}
|
||||
onChange={handleUpdateConditionValue}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
&& (
|
||||
<div className="p-1">
|
||||
<BoolValue
|
||||
value={condition.value as boolean}
|
||||
onChange={handleUpdateConditionValue}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{
|
||||
!comparisonOperatorNotRequireValue(condition.comparison_operator) && !isNotInput && condition.varType === VarType.number && (
|
||||
<div className='border-t border-t-divider-subtle px-2 py-1 pt-[3px]'>
|
||||
<div className="border-t border-t-divider-subtle px-2 py-1 pt-[3px]">
|
||||
<ConditionNumberInput
|
||||
numberVarType={condition.numberVarType}
|
||||
onNumberVarTypeChange={handleUpdateConditionNumberVarType}
|
||||
@ -293,10 +297,10 @@ const ConditionItem = ({
|
||||
}
|
||||
{
|
||||
!comparisonOperatorNotRequireValue(condition.comparison_operator) && isSelect && (
|
||||
<div className='border-t border-t-divider-subtle'>
|
||||
<div className="border-t border-t-divider-subtle">
|
||||
<Select
|
||||
wrapperClassName='h-8'
|
||||
className='rounded-t-none px-2 text-xs'
|
||||
wrapperClassName="h-8"
|
||||
className="rounded-t-none px-2 text-xs"
|
||||
defaultValue={isArrayValue ? (condition.value as string[])?.[0] : (condition.value as string)}
|
||||
items={selectOptions}
|
||||
onSelect={item => handleUpdateConditionValue(item.value as string)}
|
||||
@ -308,7 +312,7 @@ const ConditionItem = ({
|
||||
}
|
||||
{
|
||||
!comparisonOperatorNotRequireValue(condition.comparison_operator) && isSubVariable && (
|
||||
<div className='p-1'>
|
||||
<div className="p-1">
|
||||
<ConditionWrap
|
||||
isSubVariable
|
||||
conditions={condition.sub_variable_condition?.conditions || []}
|
||||
@ -328,12 +332,12 @@ const ConditionItem = ({
|
||||
}
|
||||
</div>
|
||||
<div
|
||||
className='ml-1 mt-1 flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded-lg text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive'
|
||||
className="ml-1 mt-1 flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded-lg text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive"
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
onClick={doRemoveCondition}
|
||||
>
|
||||
<RiDeleteBinLine className='h-4 w-4' />
|
||||
<RiDeleteBinLine className="h-4 w-4" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,19 +1,20 @@
|
||||
import type { ComparisonOperator } from '../../types'
|
||||
import type { VarType } from '@/app/components/workflow/types'
|
||||
import { RiArrowDownSLine } from '@remixicon/react'
|
||||
import {
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiArrowDownSLine } from '@remixicon/react'
|
||||
import { getOperators, isComparisonOperatorNeedTranslate } from '../../utils'
|
||||
import type { ComparisonOperator } from '../../types'
|
||||
import Button from '@/app/components/base/button'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import type { VarType } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { getOperators, isComparisonOperatorNeedTranslate } from '../../utils'
|
||||
|
||||
const i18nPrefix = 'workflow.nodes.ifElse'
|
||||
|
||||
type ConditionOperatorProps = {
|
||||
@ -48,7 +49,7 @@ const ConditionOperator = ({
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement='bottom-end'
|
||||
placement="bottom-end"
|
||||
offset={{
|
||||
mainAxis: 4,
|
||||
crossAxis: 0,
|
||||
@ -57,8 +58,8 @@ const ConditionOperator = ({
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
|
||||
<Button
|
||||
className={cn('shrink-0', !selectedOption && 'opacity-50', className)}
|
||||
size='small'
|
||||
variant='ghost'
|
||||
size="small"
|
||||
variant="ghost"
|
||||
disabled={disabled}
|
||||
>
|
||||
{
|
||||
@ -66,16 +67,16 @@ const ConditionOperator = ({
|
||||
? selectedOption.label
|
||||
: t(`${i18nPrefix}.select`)
|
||||
}
|
||||
<RiArrowDownSLine className='ml-1 h-3.5 w-3.5' />
|
||||
<RiArrowDownSLine className="ml-1 h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-10'>
|
||||
<div className='rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg'>
|
||||
<PortalToFollowElemContent className="z-10">
|
||||
<div className="rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg">
|
||||
{
|
||||
options.map(option => (
|
||||
<div
|
||||
key={option.value}
|
||||
className='flex h-7 cursor-pointer items-center rounded-lg px-3 py-1.5 text-[13px] font-medium text-text-secondary hover:bg-state-base-hover'
|
||||
className="flex h-7 cursor-pointer items-center rounded-lg px-3 py-1.5 text-[13px] font-medium text-text-secondary hover:bg-state-base-hover"
|
||||
onClick={() => {
|
||||
onSelect(option.value)
|
||||
setOpen(false)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { Node, NodeOutPutVar, ValueSelector, Var, VarType } from '@/app/components/workflow/types'
|
||||
import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
|
||||
import VariableTag from '@/app/components/workflow/nodes/_base/components/variable-tag'
|
||||
import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||
import type { Node, NodeOutPutVar, ValueSelector, Var, VarType } from '@/app/components/workflow/types'
|
||||
|
||||
type ConditionVarSelectorProps = {
|
||||
open: boolean
|
||||
@ -26,7 +26,7 @@ const ConditionVarSelector = ({
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={onOpenChange}
|
||||
placement='bottom-start'
|
||||
placement="bottom-start"
|
||||
offset={{
|
||||
mainAxis: 4,
|
||||
crossAxis: 0,
|
||||
@ -42,8 +42,8 @@ const ConditionVarSelector = ({
|
||||
/>
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[1000]'>
|
||||
<div className='w-[296px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg'>
|
||||
<PortalToFollowElemContent className="z-[1000]">
|
||||
<div className="w-[296px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg">
|
||||
<VarReferenceVars
|
||||
vars={nodesOutputVars}
|
||||
isSupportFileVar
|
||||
|
||||
@ -1,22 +1,17 @@
|
||||
import { RiLoopLeftLine } from '@remixicon/react'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import {
|
||||
type Condition,
|
||||
type HandleAddSubVariableCondition,
|
||||
type HandleRemoveCondition,
|
||||
type HandleToggleConditionLogicalOperator,
|
||||
type HandleToggleSubVariableConditionLogicalOperator,
|
||||
type HandleUpdateCondition,
|
||||
type HandleUpdateSubVariableCondition,
|
||||
LogicalOperator,
|
||||
type handleRemoveSubVariableCondition,
|
||||
} from '../../types'
|
||||
import ConditionItem from './condition-item'
|
||||
import type { Condition, HandleAddSubVariableCondition, HandleRemoveCondition, handleRemoveSubVariableCondition, HandleToggleConditionLogicalOperator, HandleToggleSubVariableConditionLogicalOperator, HandleUpdateCondition, HandleUpdateSubVariableCondition } from '../../types'
|
||||
import type {
|
||||
Node,
|
||||
NodeOutPutVar,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { RiLoopLeftLine } from '@remixicon/react'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import {
|
||||
|
||||
LogicalOperator,
|
||||
|
||||
} from '../../types'
|
||||
import ConditionItem from './condition-item'
|
||||
|
||||
type ConditionListProps = {
|
||||
isSubVariable?: boolean
|
||||
@ -83,15 +78,16 @@ const ConditionList = ({
|
||||
'absolute bottom-0 left-0 top-0 w-[60px]',
|
||||
isSubVariable && logicalOperator === LogicalOperator.and && 'left-[-10px]',
|
||||
isSubVariable && logicalOperator === LogicalOperator.or && 'left-[-18px]',
|
||||
)}>
|
||||
<div className='absolute bottom-4 left-[46px] top-4 w-2.5 rounded-l-[8px] border border-r-0 border-divider-deep'></div>
|
||||
<div className='absolute right-0 top-1/2 h-[29px] w-4 -translate-y-1/2 bg-components-panel-bg'></div>
|
||||
)}
|
||||
>
|
||||
<div className="absolute bottom-4 left-[46px] top-4 w-2.5 rounded-l-[8px] border border-r-0 border-divider-deep"></div>
|
||||
<div className="absolute right-0 top-1/2 h-[29px] w-4 -translate-y-1/2 bg-components-panel-bg"></div>
|
||||
<div
|
||||
className='absolute right-1 top-1/2 flex h-[21px] -translate-y-1/2 cursor-pointer select-none items-center rounded-md border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-1 text-[10px] font-semibold text-text-accent-secondary shadow-xs'
|
||||
className="absolute right-1 top-1/2 flex h-[21px] -translate-y-1/2 cursor-pointer select-none items-center rounded-md border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-1 text-[10px] font-semibold text-text-accent-secondary shadow-xs"
|
||||
onClick={() => doToggleConditionLogicalOperator(conditionId)}
|
||||
>
|
||||
{logicalOperator && logicalOperator.toUpperCase()}
|
||||
<RiLoopLeftLine className='ml-0.5 h-3 w-3' />
|
||||
<RiLoopLeftLine className="ml-0.5 h-3 w-3" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,29 +1,29 @@
|
||||
import type {
|
||||
NodeOutPutVar,
|
||||
ValueSelector,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { RiArrowDownSLine } from '@remixicon/react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { capitalize } from 'lodash-es'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiArrowDownSLine } from '@remixicon/react'
|
||||
import { capitalize } from 'lodash-es'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { VarType as NumberVarType } from '../../tool/types'
|
||||
import VariableTag from '../../_base/components/variable-tag'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||
import type {
|
||||
NodeOutPutVar,
|
||||
ValueSelector,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { variableTransformer } from '@/app/components/workflow/utils'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import VariableTag from '../../_base/components/variable-tag'
|
||||
import { VarType as NumberVarType } from '../../tool/types'
|
||||
|
||||
const options = [
|
||||
NumberVarType.variable,
|
||||
@ -62,25 +62,25 @@ const ConditionNumberInput = ({
|
||||
}, [onValueChange])
|
||||
|
||||
return (
|
||||
<div className='flex cursor-pointer items-center'>
|
||||
<div className="flex cursor-pointer items-center">
|
||||
<PortalToFollowElem
|
||||
open={numberVarTypeVisible}
|
||||
onOpenChange={setNumberVarTypeVisible}
|
||||
placement='bottom-start'
|
||||
placement="bottom-start"
|
||||
offset={{ mainAxis: 2, crossAxis: 0 }}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={() => setNumberVarTypeVisible(v => !v)}>
|
||||
<Button
|
||||
className='shrink-0'
|
||||
variant='ghost'
|
||||
size='small'
|
||||
className="shrink-0"
|
||||
variant="ghost"
|
||||
size="small"
|
||||
>
|
||||
{capitalize(numberVarType)}
|
||||
<RiArrowDownSLine className='ml-[1px] h-3.5 w-3.5' />
|
||||
<RiArrowDownSLine className="ml-[1px] h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[1000]'>
|
||||
<div className='w-[112px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg'>
|
||||
<PortalToFollowElemContent className="z-[1000]">
|
||||
<div className="w-[112px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg">
|
||||
{
|
||||
options.map(option => (
|
||||
<div
|
||||
@ -102,19 +102,20 @@ const ConditionNumberInput = ({
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
<div className='mx-1 h-4 w-[1px] bg-divider-regular'></div>
|
||||
<div className='ml-0.5 w-0 grow'>
|
||||
<div className="mx-1 h-4 w-[1px] bg-divider-regular"></div>
|
||||
<div className="ml-0.5 w-0 grow">
|
||||
{
|
||||
numberVarType === NumberVarType.variable && (
|
||||
<PortalToFollowElem
|
||||
open={variableSelectorVisible}
|
||||
onOpenChange={setVariableSelectorVisible}
|
||||
placement='bottom-start'
|
||||
placement="bottom-start"
|
||||
offset={{ mainAxis: 2, crossAxis: 0 }}
|
||||
>
|
||||
<PortalToFollowElemTrigger
|
||||
className='w-full'
|
||||
onClick={() => setVariableSelectorVisible(v => !v)}>
|
||||
className="w-full"
|
||||
onClick={() => setVariableSelectorVisible(v => !v)}
|
||||
>
|
||||
{
|
||||
value && (
|
||||
<VariableTag
|
||||
@ -126,14 +127,14 @@ const ConditionNumberInput = ({
|
||||
}
|
||||
{
|
||||
!value && (
|
||||
<div className='flex h-6 items-center p-1 text-[13px] text-components-input-text-placeholder'>
|
||||
<Variable02 className='mr-1 h-4 w-4 shrink-0' />
|
||||
<div className='w-0 grow truncate'>{t('workflow.nodes.ifElse.selectVariable')}</div>
|
||||
<div className="flex h-6 items-center p-1 text-[13px] text-components-input-text-placeholder">
|
||||
<Variable02 className="mr-1 h-4 w-4 shrink-0" />
|
||||
<div className="w-0 grow truncate">{t('workflow.nodes.ifElse.selectVariable')}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[1000]'>
|
||||
<PortalToFollowElemContent className="z-[1000]">
|
||||
<div className={cn('w-[296px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur pt-1 shadow-lg', isShort && 'w-[200px]')}>
|
||||
<VarReferenceVars
|
||||
vars={variables}
|
||||
@ -146,17 +147,17 @@ const ConditionNumberInput = ({
|
||||
}
|
||||
{
|
||||
numberVarType === NumberVarType.constant && (
|
||||
<div className=' relative'>
|
||||
<div className=" relative">
|
||||
<input
|
||||
className={cn('block w-full appearance-none bg-transparent px-2 text-[13px] text-components-input-text-filled outline-none placeholder:text-components-input-text-placeholder', unit && 'pr-6')}
|
||||
type='number'
|
||||
type="number"
|
||||
value={value}
|
||||
onChange={e => onValueChange(e.target.value)}
|
||||
placeholder={t('workflow.nodes.ifElse.enterValue') || ''}
|
||||
onFocus={setFocus}
|
||||
onBlur={setBlur}
|
||||
/>
|
||||
{!isFocus && unit && <div className='system-sm-regular absolute right-2 top-[50%] translate-y-[-50%] text-text-tertiary'>{unit}</div>}
|
||||
{!isFocus && unit && <div className="system-sm-regular absolute right-2 top-[50%] translate-y-[-50%] text-text-tertiary">{unit}</div>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -3,16 +3,16 @@ import {
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
|
||||
import {
|
||||
VariableLabelInNode,
|
||||
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
|
||||
import { ComparisonOperator } from '../types'
|
||||
import {
|
||||
comparisonOperatorNotRequireValue,
|
||||
isComparisonOperatorNeedTranslate,
|
||||
} from '../utils'
|
||||
import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from './../default'
|
||||
import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
|
||||
import {
|
||||
VariableLabelInNode,
|
||||
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
|
||||
|
||||
type ConditionValueProps = {
|
||||
variableSelector: string[]
|
||||
@ -36,7 +36,7 @@ const ConditionValue = ({
|
||||
if (Array.isArray(value)) // transfer method
|
||||
return value[0]
|
||||
|
||||
return value.replace(/{{#([^#]*)#}}/g, (a, b) => {
|
||||
return value.replace(/\{\{#([^#]*)#\}\}/g, (a, b) => {
|
||||
const arr: string[] = b.split('.')
|
||||
if (isSystemVar(arr))
|
||||
return `{{${b}}}`
|
||||
@ -50,34 +50,34 @@ const ConditionValue = ({
|
||||
if (isSelect) {
|
||||
const name = [...FILE_TYPE_OPTIONS, ...TRANSFER_METHOD].filter(item => item.value === (Array.isArray(value) ? value[0] : value))[0]
|
||||
return name
|
||||
? t(`workflow.nodes.ifElse.optionName.${name.i18nKey}`).replace(/{{#([^#]*)#}}/g, (a, b) => {
|
||||
const arr: string[] = b.split('.')
|
||||
if (isSystemVar(arr))
|
||||
return `{{${b}}}`
|
||||
? t(`workflow.nodes.ifElse.optionName.${name.i18nKey}`).replace(/\{\{#([^#]*)#\}\}/g, (a, b) => {
|
||||
const arr: string[] = b.split('.')
|
||||
if (isSystemVar(arr))
|
||||
return `{{${b}}}`
|
||||
|
||||
return `{{${arr.slice(1).join('.')}}}`
|
||||
})
|
||||
return `{{${arr.slice(1).join('.')}}}`
|
||||
})
|
||||
: ''
|
||||
}
|
||||
return ''
|
||||
}, [isSelect, t, value])
|
||||
|
||||
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">
|
||||
<VariableLabelInNode
|
||||
className='w-0 grow'
|
||||
className="w-0 grow"
|
||||
variables={variableSelector}
|
||||
notShowFullPath
|
||||
/>
|
||||
<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}
|
||||
>
|
||||
{operatorName}
|
||||
</div>
|
||||
{
|
||||
!notHasValue && (
|
||||
<div className='truncate text-xs text-text-secondary' title={formatValue}>{isSelect ? selectName : formatValue}</div>
|
||||
<div className="truncate text-xs text-text-secondary" title={formatValue}>{isSelect ? selectName : formatValue}</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { Node, NodeOutPutVar, Var } from '../../../types'
|
||||
import type { Condition, HandleAddCondition, HandleAddSubVariableCondition, HandleRemoveCondition, handleRemoveSubVariableCondition, HandleToggleConditionLogicalOperator, HandleToggleSubVariableConditionLogicalOperator, HandleUpdateCondition, HandleUpdateSubVariableCondition, LogicalOperator } from '../types'
|
||||
import {
|
||||
RiAddLine,
|
||||
} from '@remixicon/react'
|
||||
import type { Condition, HandleAddCondition, HandleAddSubVariableCondition, HandleRemoveCondition, HandleToggleConditionLogicalOperator, HandleToggleSubVariableConditionLogicalOperator, HandleUpdateCondition, HandleUpdateSubVariableCondition, LogicalOperator, handleRemoveSubVariableCondition } from '../types'
|
||||
import type { Node, NodeOutPutVar, Var } from '../../../types'
|
||||
import { VarType } from '../../../types'
|
||||
import { useGetAvailableVars } from '../../variable-assigner/hooks'
|
||||
import ConditionList from './condition-list'
|
||||
import ConditionAdd from './condition-add'
|
||||
import { SUB_VARIABLES } from './../default'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { PortalSelect as Select } from '@/app/components/base/select'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { VarType } from '../../../types'
|
||||
import { useGetAvailableVars } from '../../variable-assigner/hooks'
|
||||
import { SUB_VARIABLES } from './../default'
|
||||
import ConditionAdd from './condition-add'
|
||||
import ConditionList from './condition-list'
|
||||
|
||||
type Props = {
|
||||
isSubVariable?: boolean
|
||||
@ -81,7 +81,7 @@ const ConditionWrap: FC<Props> = ({
|
||||
>
|
||||
{
|
||||
conditions && !!conditions.length && (
|
||||
<div className='mb-2'>
|
||||
<div className="mb-2">
|
||||
<ConditionList
|
||||
disabled={readOnly}
|
||||
conditionId={conditionId}
|
||||
@ -109,33 +109,34 @@ const ConditionWrap: FC<Props> = ({
|
||||
!conditions.length && !isSubVariable && 'mt-1',
|
||||
!conditions.length && isSubVariable && 'mt-2',
|
||||
conditions.length > 1 && !isSubVariable && 'ml-[60px]',
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
{isSubVariable
|
||||
? (
|
||||
<Select
|
||||
popupInnerClassName='w-[165px] max-h-none'
|
||||
onSelect={value => handleAddSubVariableCondition?.(conditionId!, value.value as string)}
|
||||
items={subVarOptions}
|
||||
value=''
|
||||
renderTrigger={() => (
|
||||
<Button
|
||||
size='small'
|
||||
disabled={readOnly}
|
||||
>
|
||||
<RiAddLine className='mr-1 h-3.5 w-3.5' />
|
||||
{t('workflow.nodes.ifElse.addSubVariable')}
|
||||
</Button>
|
||||
)}
|
||||
hideChecked
|
||||
/>
|
||||
)
|
||||
<Select
|
||||
popupInnerClassName="w-[165px] max-h-none"
|
||||
onSelect={value => handleAddSubVariableCondition?.(conditionId!, value.value as string)}
|
||||
items={subVarOptions}
|
||||
value=""
|
||||
renderTrigger={() => (
|
||||
<Button
|
||||
size="small"
|
||||
disabled={readOnly}
|
||||
>
|
||||
<RiAddLine className="mr-1 h-3.5 w-3.5" />
|
||||
{t('workflow.nodes.ifElse.addSubVariable')}
|
||||
</Button>
|
||||
)}
|
||||
hideChecked
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<ConditionAdd
|
||||
disabled={readOnly}
|
||||
variables={availableVars}
|
||||
onSelectVariable={handleAddCondition!}
|
||||
/>
|
||||
)}
|
||||
<ConditionAdd
|
||||
disabled={readOnly}
|
||||
variables={availableVars}
|
||||
onSelectVariable={handleAddCondition!}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -4,7 +4,7 @@ const Empty = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className='system-xs-regular flex h-10 items-center justify-center rounded-[10px] bg-background-section text-text-tertiary'>
|
||||
<div className="system-xs-regular flex h-10 items-center justify-center rounded-[10px] bg-background-section text-text-tertiary">
|
||||
{t('workflow.nodes.loop.setLoopVariables')}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,13 +1,3 @@
|
||||
import {
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import type {
|
||||
LoopVariable,
|
||||
} from '@/app/components/workflow/nodes/loop/types'
|
||||
@ -15,9 +5,16 @@ import type {
|
||||
Var,
|
||||
} from '@/app/components/workflow/types'
|
||||
import {
|
||||
ValueType,
|
||||
VarType,
|
||||
} from '@/app/components/workflow/types'
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||
import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import ArrayBoolList from '@/app/components/workflow/panel/chat-variable-panel/components/array-bool-list'
|
||||
import BoolValue from '@/app/components/workflow/panel/chat-variable-panel/components/bool-value'
|
||||
|
||||
import {
|
||||
@ -27,7 +24,10 @@ import {
|
||||
arrayStringPlaceholder,
|
||||
objectPlaceholder,
|
||||
} from '@/app/components/workflow/panel/chat-variable-panel/utils'
|
||||
import ArrayBoolList from '@/app/components/workflow/panel/chat-variable-panel/components/array-bool-list'
|
||||
import {
|
||||
ValueType,
|
||||
VarType,
|
||||
} from '@/app/components/workflow/types'
|
||||
|
||||
type FormItemProps = {
|
||||
nodeId: string
|
||||
@ -91,7 +91,7 @@ const FormItem = ({
|
||||
<Textarea
|
||||
value={value}
|
||||
onChange={handleInputChange}
|
||||
className='min-h-12 w-full'
|
||||
className="min-h-12 w-full"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -101,7 +101,7 @@ const FormItem = ({
|
||||
type="number"
|
||||
value={value}
|
||||
onChange={handleInputChange}
|
||||
className='w-full'
|
||||
className="w-full"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -117,15 +117,15 @@ const FormItem = ({
|
||||
value_type === ValueType.constant
|
||||
&& (var_type === VarType.object || var_type === VarType.arrayString || var_type === VarType.arrayNumber || var_type === VarType.arrayObject)
|
||||
&& (
|
||||
<div className='w-full rounded-[10px] bg-components-input-bg-normal py-2 pl-3 pr-1' style={{ height: editorMinHeight }}>
|
||||
<div className="w-full rounded-[10px] bg-components-input-bg-normal py-2 pl-3 pr-1" style={{ height: editorMinHeight }}>
|
||||
<CodeEditor
|
||||
value={value}
|
||||
isExpand
|
||||
noWrapper
|
||||
language={CodeLanguage.json}
|
||||
onChange={handleChange}
|
||||
className='w-full'
|
||||
placeholder={<div className='whitespace-pre'>{placeholder}</div>}
|
||||
className="w-full"
|
||||
placeholder={<div className="whitespace-pre">{placeholder}</div>}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
@ -133,7 +133,7 @@ const FormItem = ({
|
||||
{
|
||||
value_type === ValueType.constant && var_type === VarType.arrayBoolean && (
|
||||
<ArrayBoolList
|
||||
className='mt-2'
|
||||
className="mt-2"
|
||||
list={value || [false]}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import Empty from './empty'
|
||||
import Item from './item'
|
||||
import type {
|
||||
LoopVariable,
|
||||
LoopVariablesComponentShape,
|
||||
} from '@/app/components/workflow/nodes/loop/types'
|
||||
import Empty from './empty'
|
||||
import Item from './item'
|
||||
|
||||
type LoopVariableProps = {
|
||||
variables?: LoopVariable[]
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import { useCallback } from 'react'
|
||||
import { RiDeleteBinLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import InputModeSelect from './input-mode-selec'
|
||||
import VariableTypeSelect from './variable-type-select'
|
||||
import FormItem from './form-item'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import Input from '@/app/components/base/input'
|
||||
import type {
|
||||
LoopVariable,
|
||||
LoopVariablesComponentShape,
|
||||
} from '@/app/components/workflow/nodes/loop/types'
|
||||
import { checkKeys, replaceSpaceWithUnderscoreInVarNameInput } from '@/utils/var'
|
||||
import { RiDeleteBinLine } from '@remixicon/react'
|
||||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { ValueType, VarType } from '@/app/components/workflow/types'
|
||||
import { checkKeys, replaceSpaceWithUnderscoreInVarNameInput } from '@/utils/var'
|
||||
import FormItem from './form-item'
|
||||
import InputModeSelect from './input-mode-selec'
|
||||
import VariableTypeSelect from './variable-type-select'
|
||||
|
||||
type ItemProps = {
|
||||
item: LoopVariable
|
||||
@ -44,7 +44,7 @@ const Item = ({
|
||||
}, [item.id, handleUpdateLoopVariable])
|
||||
|
||||
const getDefaultValue = useCallback((varType: VarType, valueType: ValueType) => {
|
||||
if(valueType === ValueType.variable)
|
||||
if (valueType === ValueType.variable)
|
||||
return undefined
|
||||
switch (varType) {
|
||||
case VarType.boolean:
|
||||
@ -69,9 +69,9 @@ const Item = ({
|
||||
}, [item.id, handleUpdateLoopVariable])
|
||||
|
||||
return (
|
||||
<div className='mb-4 flex last-of-type:mb-0'>
|
||||
<div className='w-0 grow'>
|
||||
<div className='mb-1 grid grid-cols-3 gap-1'>
|
||||
<div className="mb-4 flex last-of-type:mb-0">
|
||||
<div className="w-0 grow">
|
||||
<div className="mb-1 grid grid-cols-3 gap-1">
|
||||
<Input
|
||||
value={item.label}
|
||||
onChange={handleUpdateItemLabel}
|
||||
@ -97,11 +97,11 @@ const Item = ({
|
||||
</div>
|
||||
</div>
|
||||
<ActionButton
|
||||
className='shrink-0'
|
||||
size='l'
|
||||
className="shrink-0"
|
||||
size="l"
|
||||
onClick={() => handleRemoveLoopVariable(item.id)}
|
||||
>
|
||||
<RiDeleteBinLine className='h-4 w-4 text-text-tertiary' />
|
||||
<RiDeleteBinLine className="h-4 w-4 text-text-tertiary" />
|
||||
</ActionButton>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import { VarType } from '../../types'
|
||||
import type { NodeDefault } from '../../types'
|
||||
import { ComparisonOperator, LogicalOperator, type LoopNodeType } from './types'
|
||||
import { isEmptyRelatedOperator } from './utils'
|
||||
import { TransferMethod } from '@/types/app'
|
||||
import { LOOP_NODE_MAX_COUNT } from '@/config'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import type { LoopNodeType } from './types'
|
||||
import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { LOOP_NODE_MAX_COUNT } from '@/config'
|
||||
import { TransferMethod } from '@/types/app'
|
||||
import { VarType } from '../../types'
|
||||
import { ComparisonOperator, LogicalOperator } from './types'
|
||||
import { isEmptyRelatedOperator } from './utils'
|
||||
|
||||
const i18nPrefix = 'workflow.errorMsg'
|
||||
|
||||
const metaData = genNodeMetaData({
|
||||
@ -66,8 +68,9 @@ const nodeDefault: NodeDefault<LoopNodeType> = {
|
||||
|| !Number.isInteger(Number(payload.loop_count))
|
||||
|| payload.loop_count < 1
|
||||
|| payload.loop_count > LOOP_NODE_MAX_COUNT
|
||||
))
|
||||
)) {
|
||||
errorMessages = t('workflow.nodes.loop.loopMaxCountError', { maxCount: LOOP_NODE_MAX_COUNT })
|
||||
}
|
||||
|
||||
return {
|
||||
isValid: !errorMessages,
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import type {
|
||||
BlockEnum,
|
||||
OnSelectBlock,
|
||||
} from '../../types'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useNodesInteractions } from '../../hooks'
|
||||
import type {
|
||||
BlockEnum,
|
||||
OnSelectBlock,
|
||||
} from '../../types'
|
||||
import BlockSelector from '../../block-selector'
|
||||
import { useNodesInteractions } from '../../hooks'
|
||||
|
||||
type InsertBlockProps = {
|
||||
startNodeId: string
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import type { FC } from 'react'
|
||||
import type { LoopNodeType } from './types'
|
||||
import type { NodeProps } from '@/app/components/workflow/types'
|
||||
import {
|
||||
memo,
|
||||
useEffect,
|
||||
@ -8,13 +10,11 @@ import {
|
||||
useNodesInitialized,
|
||||
useViewport,
|
||||
} from 'reactflow'
|
||||
import { LoopStartNodeDumb } from '../loop-start'
|
||||
import { useNodeLoopInteractions } from './use-interactions'
|
||||
import type { LoopNodeType } from './types'
|
||||
import AddBlock from './add-block'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { LoopStartNodeDumb } from '../loop-start'
|
||||
import AddBlock from './add-block'
|
||||
|
||||
import type { NodeProps } from '@/app/components/workflow/types'
|
||||
import { useNodeLoopInteractions } from './use-interactions'
|
||||
|
||||
const Node: FC<NodeProps<LoopNodeType>> = ({
|
||||
id,
|
||||
@ -32,13 +32,14 @@ const Node: FC<NodeProps<LoopNodeType>> = ({
|
||||
return (
|
||||
<div className={cn(
|
||||
'relative h-full min-h-[90px] w-full min-w-[240px] rounded-2xl bg-workflow-canvas-workflow-bg',
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
<Background
|
||||
id={`loop-background-${id}`}
|
||||
className='!z-0 rounded-2xl'
|
||||
className="!z-0 rounded-2xl"
|
||||
gap={[14 / zoom, 14 / zoom]}
|
||||
size={2 / zoom}
|
||||
color='var(--color-workflow-canvas-workflow-dot-color)'
|
||||
color="var(--color-workflow-canvas-workflow-dot-color)"
|
||||
/>
|
||||
{
|
||||
data._isCandidate && (
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import type { FC } from 'react'
|
||||
import type { LoopNodeType } from './types'
|
||||
import type { NodePanelProps } from '@/app/components/workflow/types'
|
||||
import { RiAddLine } from '@remixicon/react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiAddLine } from '@remixicon/react'
|
||||
import Split from '../_base/components/split'
|
||||
import Field from '@/app/components/workflow/nodes/_base/components/field'
|
||||
import { LOOP_NODE_MAX_COUNT } from '@/config'
|
||||
import InputNumberWithSlider from '../_base/components/input-number-with-slider'
|
||||
import type { LoopNodeType } from './types'
|
||||
import useConfig from './use-config'
|
||||
import Split from '../_base/components/split'
|
||||
import ConditionWrap from './components/condition-wrap'
|
||||
import LoopVariable from './components/loop-variables'
|
||||
import type { NodePanelProps } from '@/app/components/workflow/types'
|
||||
import Field from '@/app/components/workflow/nodes/_base/components/field'
|
||||
|
||||
import { LOOP_NODE_MAX_COUNT } from '@/config'
|
||||
import useConfig from './use-config'
|
||||
|
||||
const i18nPrefix = 'workflow.nodes.loop'
|
||||
|
||||
@ -41,20 +41,20 @@ const Panel: FC<NodePanelProps<LoopNodeType>> = ({
|
||||
} = useConfig(id, data)
|
||||
|
||||
return (
|
||||
<div className='mt-2'>
|
||||
<div className="mt-2">
|
||||
<div>
|
||||
<Field
|
||||
title={<div className='pl-3'>{t('workflow.nodes.loop.loopVariables')}</div>}
|
||||
operations={
|
||||
title={<div className="pl-3">{t('workflow.nodes.loop.loopVariables')}</div>}
|
||||
operations={(
|
||||
<div
|
||||
className='mr-4 flex h-5 w-5 cursor-pointer items-center justify-center'
|
||||
className="mr-4 flex h-5 w-5 cursor-pointer items-center justify-center"
|
||||
onClick={handleAddLoopVariable}
|
||||
>
|
||||
<RiAddLine className='h-4 w-4 text-text-tertiary' />
|
||||
<RiAddLine className="h-4 w-4 text-text-tertiary" />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
>
|
||||
<div className='px-4'>
|
||||
<div className="px-4">
|
||||
<LoopVariable
|
||||
variables={inputs.loop_variables}
|
||||
nodeId={id}
|
||||
@ -63,9 +63,9 @@ const Panel: FC<NodePanelProps<LoopNodeType>> = ({
|
||||
/>
|
||||
</div>
|
||||
</Field>
|
||||
<Split className='my-2' />
|
||||
<Split className="my-2" />
|
||||
<Field
|
||||
title={<div className='pl-3'>{t(`${i18nPrefix}.breakCondition`)}</div>}
|
||||
title={<div className="pl-3">{t(`${i18nPrefix}.breakCondition`)}</div>}
|
||||
tooltip={t(`${i18nPrefix}.breakConditionTip`)}
|
||||
>
|
||||
<ConditionWrap
|
||||
@ -85,12 +85,12 @@ const Panel: FC<NodePanelProps<LoopNodeType>> = ({
|
||||
logicalOperator={inputs.logical_operator!}
|
||||
/>
|
||||
</Field>
|
||||
<Split className='mt-2' />
|
||||
<div className='mt-2'>
|
||||
<Split className="mt-2" />
|
||||
<div className="mt-2">
|
||||
<Field
|
||||
title={<div className='pl-3'>{t(`${i18nPrefix}.loopMaxCount`)}</div>}
|
||||
title={<div className="pl-3">{t(`${i18nPrefix}.loopMaxCount`)}</div>}
|
||||
>
|
||||
<div className='px-3 py-2'>
|
||||
<div className="px-3 py-2">
|
||||
<InputNumberWithSlider
|
||||
min={1}
|
||||
max={LOOP_NODE_MAX_COUNT}
|
||||
|
||||
@ -1,20 +1,4 @@
|
||||
import {
|
||||
useCallback,
|
||||
useRef,
|
||||
} from 'react'
|
||||
import { produce } from 'immer'
|
||||
import { v4 as uuid4 } from 'uuid'
|
||||
import {
|
||||
useIsChatMode,
|
||||
useNodesReadOnly,
|
||||
useWorkflow,
|
||||
} from '../../hooks'
|
||||
import { ValueType, VarType } from '../../types'
|
||||
import type { ErrorHandleMode, Var } from '../../types'
|
||||
import useNodeCrud from '../_base/hooks/use-node-crud'
|
||||
import { toNodeOutputVars } from '../_base/components/variable/utils'
|
||||
import { getOperators } from './utils'
|
||||
import { LogicalOperator } from './types'
|
||||
import type {
|
||||
HandleAddCondition,
|
||||
HandleAddSubVariableCondition,
|
||||
@ -25,7 +9,12 @@ import type {
|
||||
HandleUpdateSubVariableCondition,
|
||||
LoopNodeType,
|
||||
} from './types'
|
||||
import useIsVarFileAttribute from './use-is-var-file-attribute'
|
||||
import { produce } from 'immer'
|
||||
import {
|
||||
useCallback,
|
||||
useRef,
|
||||
} from 'react'
|
||||
import { v4 as uuid4 } from 'uuid'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import {
|
||||
useAllBuiltInTools,
|
||||
@ -33,6 +22,17 @@ import {
|
||||
useAllMCPTools,
|
||||
useAllWorkflowTools,
|
||||
} from '@/service/use-tools'
|
||||
import {
|
||||
useIsChatMode,
|
||||
useNodesReadOnly,
|
||||
useWorkflow,
|
||||
} from '../../hooks'
|
||||
import { ValueType, VarType } from '../../types'
|
||||
import { toNodeOutputVars } from '../_base/components/variable/utils'
|
||||
import useNodeCrud from '../_base/hooks/use-node-crud'
|
||||
import { LogicalOperator } from './types'
|
||||
import useIsVarFileAttribute from './use-is-var-file-attribute'
|
||||
import { getOperators } from './utils'
|
||||
|
||||
const useConfig = (id: string, payload: LoopNodeType) => {
|
||||
const { nodesReadOnly: readOnly } = useNodesReadOnly()
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
import { useCallback } from 'react'
|
||||
import { produce } from 'immer'
|
||||
import { useStoreApi } from 'reactflow'
|
||||
import type {
|
||||
BlockEnum,
|
||||
Node,
|
||||
} from '../../types'
|
||||
import { produce } from 'immer'
|
||||
import { useCallback } from 'react'
|
||||
import { useStoreApi } from 'reactflow'
|
||||
import { useNodesMetaData } from '@/app/components/workflow/hooks'
|
||||
import {
|
||||
LOOP_PADDING,
|
||||
} from '../../constants'
|
||||
import {
|
||||
generateNewNode,
|
||||
getNodeCustomTypeByNodeDataType,
|
||||
} from '../../utils'
|
||||
import {
|
||||
LOOP_PADDING,
|
||||
} from '../../constants'
|
||||
import { CUSTOM_LOOP_START_NODE } from '../loop-start/constants'
|
||||
import { useNodesMetaData } from '@/app/components/workflow/hooks'
|
||||
|
||||
export const useNodeLoopInteractions = () => {
|
||||
const store = useStoreApi()
|
||||
@ -75,7 +75,7 @@ export const useNodeLoopInteractions = () => {
|
||||
const { getNodes } = store.getState()
|
||||
const nodes = getNodes()
|
||||
|
||||
const restrictPosition: { x?: number; y?: number } = { x: undefined, y: undefined }
|
||||
const restrictPosition: { x?: number, y?: number } = { x: undefined, y: undefined }
|
||||
|
||||
if (node.data.isInLoop) {
|
||||
const parentNode = nodes.find(n => n.id === node.parentId)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { ValueSelector } from '../../types'
|
||||
import { useMemo } from 'react'
|
||||
import { useIsChatMode, useWorkflow, useWorkflowVariables } from '../../hooks'
|
||||
import type { ValueSelector } from '../../types'
|
||||
import { VarType } from '../../types'
|
||||
|
||||
type Params = {
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import type { NodeTracing } from '@/types/workflow'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import formatTracing from '@/app/components/workflow/run/utils/format-log'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useIsNodeInLoop, useWorkflow } from '../../hooks'
|
||||
import { getNodeInfoById, getNodeUsedVarPassToServerKey, getNodeUsedVars, isSystemVar } from '../_base/components/variable/utils'
|
||||
import type { InputVar, ValueSelector, Variable } from '../../types'
|
||||
import type { CaseItem, Condition, LoopNodeType } from './types'
|
||||
import type { NodeTracing } from '@/types/workflow'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import formatTracing from '@/app/components/workflow/run/utils/format-log'
|
||||
import { ValueType } from '@/app/components/workflow/types'
|
||||
import { VALUE_SELECTOR_DELIMITER as DELIMITER } from '@/config'
|
||||
import { useIsNodeInLoop, useWorkflow } from '../../hooks'
|
||||
import { getNodeInfoById, getNodeUsedVarPassToServerKey, getNodeUsedVars, isSystemVar } from '../_base/components/variable/utils'
|
||||
|
||||
type Params = {
|
||||
id: string
|
||||
|
||||
@ -1,15 +1,18 @@
|
||||
import { ComparisonOperator } from './types'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import type { Branch } from '@/app/components/workflow/types'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { ComparisonOperator } from './types'
|
||||
|
||||
export const isEmptyRelatedOperator = (operator: ComparisonOperator) => {
|
||||
return [ComparisonOperator.empty, ComparisonOperator.notEmpty, ComparisonOperator.isNull, ComparisonOperator.isNotNull, ComparisonOperator.exists, ComparisonOperator.notExists].includes(operator)
|
||||
}
|
||||
|
||||
const notTranslateKey = [
|
||||
ComparisonOperator.equal, ComparisonOperator.notEqual,
|
||||
ComparisonOperator.largerThan, ComparisonOperator.largerThanOrEqual,
|
||||
ComparisonOperator.lessThan, ComparisonOperator.lessThanOrEqual,
|
||||
ComparisonOperator.equal,
|
||||
ComparisonOperator.notEqual,
|
||||
ComparisonOperator.largerThan,
|
||||
ComparisonOperator.largerThanOrEqual,
|
||||
ComparisonOperator.lessThan,
|
||||
ComparisonOperator.lessThanOrEqual,
|
||||
]
|
||||
|
||||
export const isComparisonOperatorNeedTranslate = (operator?: ComparisonOperator) => {
|
||||
|
||||
Reference in New Issue
Block a user