feat: can add sub variable

This commit is contained in:
Joel 2024-08-16 17:12:44 +08:00
parent eaa7d114dc
commit 4554ac3ef8
9 changed files with 227 additions and 113 deletions

View File

@ -5,19 +5,20 @@ import {
} 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,
HandleUpdateCondition,
} from '../../types'
import {
ComparisonOperator,
LogicalOperator,
} from '../../types'
import { comparisonOperatorNotRequireValue } from '../../utils'
import ConditionNumberInput from '../condition-number-input'
import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from '../../default'
import { FILE_TYPE_OPTIONS, SUB_VARIABLES, TRANSFER_METHOD } from '../../default'
import ConditionWrap from '../condition-wrap'
import ConditionOperator from './condition-operator'
import ConditionInput from './condition-input'
@ -29,7 +30,6 @@ import type {
import { VarType } from '@/app/components/workflow/types'
import cn from '@/utils/classnames'
import { SimpleSelect as Select } from '@/app/components/base/select'
const optionNameI18NPrefix = 'workflow.nodes.ifElse.optionName'
type ConditionItemProps = {
@ -37,22 +37,26 @@ type ConditionItemProps = {
caseId: string
condition: Condition
file?: { key: string }
isSubVariableKey?: boolean
onRemoveCondition: HandleRemoveCondition
onUpdateCondition: HandleUpdateCondition
nodesOutputVars: NodeOutPutVar[]
availableNodes: Node[]
numberVariables: NodeOutPutVar[]
onAddSubVariableCondition?: HandleAddSubVariableCondition
}
const ConditionItem = ({
disabled,
caseId,
condition,
file,
isSubVariableKey,
onRemoveCondition,
onUpdateCondition,
nodesOutputVars,
availableNodes,
numberVariables,
onAddSubVariableCondition,
}: ConditionItemProps) => {
const { t } = useTranslation()
@ -104,8 +108,21 @@ const ConditionItem = ({
}, [condition.comparison_operator, file?.key, isSelect, t])
const isSubVariable = condition.varType === VarType.arrayFile && [ComparisonOperator.contains, ComparisonOperator.notContains].includes(condition.comparison_operator!)
const isNotInput = isSelect || isSubVariable
const isSubVarSelect = isSubVariableKey
const subVarOptions = SUB_VARIABLES.map(item => ({
name: item,
value: item,
}))
const handleSubVarKeyChange = useCallback((key: string) => {
const newCondition = produce(condition, (draft) => {
draft.key = key
})
onUpdateCondition(caseId, condition.id, newCondition)
}, [caseId, condition, onUpdateCondition])
return (
<div className='flex mb-1 last-of-type:mb-0'>
<div className={cn(
@ -114,10 +131,23 @@ const ConditionItem = ({
)}>
<div className='flex items-center p-1'>
<div className='grow w-0'>
{isSubVarSelect
? (
<Select
wrapperClassName='h-6'
className='pl-0 text-xs'
defaultValue={condition.value}
items={subVarOptions}
onSelect={item => handleSubVarKeyChange(item.value as string)}
/>
)
: (
<VariableTag
valueSelector={condition.variable_selector}
valueSelector={condition.variable_selector || []}
varType={condition.varType}
/>
)}
</div>
<div className='mx-1 w-[1px] h-3 bg-divider-regular'></div>
<ConditionOperator
@ -172,13 +202,12 @@ const ConditionItem = ({
<div className='p-1'>
<ConditionWrap
isSubVariable
conditionId={condition.id}
caseId={caseId}
readOnly={!!disabled}
nodeId=''
cases={[{
case_id: '0',
conditions: [],
logical_operator: LogicalOperator.and,
}]}
cases={condition.sub_variable_condition ? [condition.sub_variable_condition] : []}
handleAddSubVariableCondition={onAddSubVariableCondition}
handleRemoveCase={() => { }}
handleAddCondition={() => { }}
handleUpdateCondition={() => { }}

View File

@ -2,6 +2,7 @@ import { RiLoopLeftLine } from '@remixicon/react'
import { LogicalOperator } from '../../types'
import type {
CaseItem,
HandleAddSubVariableCondition,
HandleRemoveCondition,
HandleUpdateCondition,
HandleUpdateConditionLogicalOperator,
@ -13,6 +14,7 @@ import type {
} from '@/app/components/workflow/types'
type ConditionListProps = {
isSubVariable?: boolean
disabled?: boolean
caseItem: CaseItem
onUpdateCondition: HandleUpdateCondition
@ -22,8 +24,10 @@ type ConditionListProps = {
availableNodes: Node[]
numberVariables: NodeOutPutVar[]
varsIsVarFileAttribute: Record<string, boolean>
onAddSubVariableCondition?: HandleAddSubVariableCondition
}
const ConditionList = ({
isSubVariable,
disabled,
caseItem,
onUpdateCondition,
@ -33,6 +37,7 @@ const ConditionList = ({
availableNodes,
numberVariables,
varsIsVarFileAttribute,
onAddSubVariableCondition,
}: ConditionListProps) => {
const { conditions, logical_operator } = caseItem
@ -67,7 +72,9 @@ const ConditionList = ({
nodesOutputVars={nodesOutputVars}
availableNodes={availableNodes}
numberVariables={numberVariables}
file={varsIsVarFileAttribute[condition.id] ? { key: condition.variable_selector.slice(-1)[0] } : undefined}
file={varsIsVarFileAttribute[condition.id] ? { key: (condition.variable_selector || []).slice(-1)[0] } : undefined}
isSubVariableKey={isSubVariable}
onAddSubVariableCondition={onAddSubVariableCondition}
/>
))
}

View File

@ -4,10 +4,11 @@ import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ReactSortable } from 'react-sortablejs'
import {
RiAddLine,
RiDeleteBinLine,
RiDraggable,
} from '@remixicon/react'
import type { CaseItem, HandleAddCondition, HandleRemoveCondition, HandleUpdateCondition, HandleUpdateConditionLogicalOperator } from '../types'
import type { CaseItem, HandleAddCondition, HandleAddSubVariableCondition, HandleRemoveCondition, HandleUpdateCondition, HandleUpdateConditionLogicalOperator } from '../types'
import type { Node, NodeOutPutVar, Var } from '../../../types'
import { VarType } from '../../../types'
import { useGetAvailableVars } from '../../variable-assigner/hooks'
@ -18,12 +19,15 @@ import Button from '@/app/components/base/button'
type Props = {
isSubVariable?: boolean
conditionId?: string
caseId?: string
nodeId: string
cases: CaseItem[]
readOnly: boolean
handleSortCase?: (sortedCases: (CaseItem & { id: string })[]) => void
handleRemoveCase: (caseId: string) => void
handleAddCondition: HandleAddCondition
handleAddCondition?: HandleAddCondition
handleAddSubVariableCondition?: HandleAddSubVariableCondition
handleUpdateCondition: HandleUpdateCondition
handleRemoveCondition: HandleRemoveCondition
handleUpdateConditionLogicalOperator: HandleUpdateConditionLogicalOperator
@ -35,19 +39,22 @@ type Props = {
const ConditionWrap: FC<Props> = ({
isSubVariable,
conditionId: parentConditionId,
caseId: conditionParentCaseId,
nodeId: id,
cases,
cases = [],
readOnly,
handleSortCase = () => { },
handleRemoveCase,
handleUpdateCondition,
handleAddCondition,
handleRemoveCondition,
handleAddSubVariableCondition,
handleUpdateConditionLogicalOperator,
nodesOutputVars,
availableNodes,
varsIsVarFileAttribute,
filterVar,
handleAddCondition,
handleRemoveCase,
}) => {
const { t } = useTranslation()
@ -61,6 +68,7 @@ const ConditionWrap: FC<Props> = ({
}, [])
return (
<>
<ReactSortable
list={cases.map(caseItem => ({ ...caseItem, id: caseItem.case_id }))}
setList={handleSortCase}
@ -74,10 +82,14 @@ const ConditionWrap: FC<Props> = ({
<div key={item.case_id}>
<div
className={cn(
'group relative py-1 px-3 min-h-[40px] rounded-[10px] bg-components-panel-bg',
'group relative rounded-[10px] bg-components-panel-bg',
willDeleteCaseId === item.case_id && 'bg-state-destructive-hover',
!isSubVariable && 'py-1 px-3 min-h-[40px] ',
isSubVariable && 'p-2 pr-1',
)}
>
{!isSubVariable && (
<>
<RiDraggable className={cn(
'hidden handle absolute top-2 left-1 w-3 h-3 text-text-quaternary cursor-pointer',
casesLength > 1 && 'group-hover:block',
@ -95,6 +107,9 @@ const ConditionWrap: FC<Props> = ({
)
}
</div>
</>
)}
{
!!item.conditions.length && (
<div className='mb-2'>
@ -108,20 +123,39 @@ const ConditionWrap: FC<Props> = ({
availableNodes={availableNodes}
numberVariables={getAvailableVars(id, '', filterNumberVar)}
varsIsVarFileAttribute={varsIsVarFileAttribute}
onAddSubVariableCondition={handleAddSubVariableCondition}
isSubVariable={isSubVariable}
/>
</div>
)
}
<div className={cn(
'flex items-center justify-between pl-[60px] pr-[30px]',
!item.conditions.length && 'mt-1',
'flex items-center justify-between pr-[30px]',
!item.conditions.length && !isSubVariable && 'mt-1',
!item.conditions.length && isSubVariable && 'mt-2',
!isSubVariable && ' pl-[60px]',
)}>
{isSubVariable
? (
<Button
size='small'
disabled={readOnly}
onClick={() => handleAddSubVariableCondition?.(conditionParentCaseId!, parentConditionId!)}
>
<RiAddLine className='mr-1 w-3.5 h-3.5' />
{t('workflow.nodes.ifElse.addSubVariable')}
</Button>
)
: (
<ConditionAdd
disabled={readOnly}
caseId={item.case_id}
variables={getAvailableVars(id, '', filterVar)}
onSelectVariable={handleAddCondition}
onSelectVariable={handleAddCondition!}
/>
)}
{
((index === 0 && casesLength > 1) || (index > 0)) && (
<Button
@ -140,11 +174,24 @@ const ConditionWrap: FC<Props> = ({
}
</div>
</div>
{!isSubVariable && (
<div className='my-2 mx-3 h-[1px] bg-divider-subtle'></div>
)}
</div>
))
}
</ReactSortable>
{(cases.length === 0) && (
<Button
size='small'
disabled={readOnly}
onClick={() => handleAddSubVariableCondition?.(conditionParentCaseId!, parentConditionId!)}
>
<RiAddLine className='mr-1 w-3.5 h-3.5' />
{t('workflow.nodes.ifElse.addSubVariable')}
</Button>
)}
</>
)
}
export default React.memo(ConditionWrap)

View File

@ -74,3 +74,5 @@ export const TRANSFER_METHOD = [
{ value: TransferMethod.local_file, i18nKey: 'localUpload' },
{ value: TransferMethod.remote_url, i18nKey: 'url' },
]
export const SUB_VARIABLES = ['type', 'size', 'name', 'url', 'extension', 'mime_type', 'transfer_method', 'url']

View File

@ -30,6 +30,7 @@ const Panel: FC<NodePanelProps<IfElseNodeType>> = ({
handleAddCondition,
handleUpdateCondition,
handleRemoveCondition,
handleAddSubVariableCondition,
handleUpdateConditionLogicalOperator,
nodesOutputVars,
availableNodes,
@ -49,6 +50,7 @@ const Panel: FC<NodePanelProps<IfElseNodeType>> = ({
handleUpdateCondition={handleUpdateCondition}
handleRemoveCondition={handleRemoveCondition}
handleUpdateConditionLogicalOperator={handleUpdateConditionLogicalOperator}
handleAddSubVariableCondition={handleAddSubVariableCondition}
nodesOutputVars={nodesOutputVars}
availableNodes={availableNodes}
varsIsVarFileAttribute={varsIsVarFileAttribute}

View File

@ -33,23 +33,15 @@ export enum ComparisonOperator {
allOf = 'all of',
}
export type SubVariableCondition = {
id: string
path: string
type: VarType
comparison_operator?: ComparisonOperator
value: string
numberVarType?: NumberVarType
}
export type Condition = {
id: string
varType: VarType
variable_selector: ValueSelector
variable_selector?: ValueSelector
key?: string // sub variable key
comparison_operator?: ComparisonOperator
value: string
numberVarType?: NumberVarType
sub_variable_condition?: SubVariableCondition[]
sub_variable_condition?: CaseItem
}
export type CaseItem = {
@ -66,6 +58,7 @@ export type IfElseNodeType = CommonNodeType & {
}
export type HandleAddCondition = (caseId: string, valueSelector: ValueSelector, varItem: Var) => void
export type HandleAddSubVariableCondition = (caseId: string, conditionId: string) => void
export type HandleRemoveCondition = (caseId: string, conditionId: string) => void
export type HandleUpdateCondition = (caseId: string, conditionId: string, newCondition: Condition) => void
export type HandleUpdateConditionLogicalOperator = (caseId: string, value: LogicalOperator) => void

View File

@ -9,6 +9,7 @@ import { LogicalOperator } from './types'
import type {
CaseItem,
HandleAddCondition,
HandleAddSubVariableCondition,
HandleRemoveCondition,
HandleUpdateCondition,
HandleUpdateConditionLogicalOperator,
@ -58,7 +59,7 @@ const useConfig = (id: string, payload: IfElseNodeType) => {
const conditions: Record<string, boolean> = {}
inputs.cases?.forEach((c) => {
c.conditions.forEach((condition) => {
conditions[condition.id] = getIsVarFileAttribute(condition.variable_selector)
conditions[condition.id] = getIsVarFileAttribute(condition.variable_selector!)
})
})
return conditions
@ -165,6 +166,36 @@ const useConfig = (id: string, payload: IfElseNodeType) => {
setInputs(newInputs)
}, [inputs, setInputs])
const handleAddSubVariableCondition = useCallback<HandleAddSubVariableCondition>((caseId: string, conditionId: string) => {
const newInputs = produce(inputs, (draft) => {
// debugger
const condition = draft.cases?.find(item => item.case_id === caseId)?.conditions.find(item => item.id === conditionId)
if (!condition)
return
if (!condition?.sub_variable_condition) {
condition.sub_variable_condition = {
case_id: uuid4(),
logical_operator: LogicalOperator.and,
conditions: [],
}
}
const subVarCondition = condition.sub_variable_condition
if (subVarCondition) {
if (!subVarCondition.conditions)
subVarCondition.conditions = []
subVarCondition.conditions.push({
id: uuid4(),
key: '',
varType: VarType.string,
comparison_operator: undefined,
value: '',
})
}
})
setInputs(newInputs)
}, [inputs, setInputs])
const handleUpdateConditionLogicalOperator = useCallback<HandleUpdateConditionLogicalOperator>((caseId, value) => {
const newInputs = produce(inputs, (draft) => {
const targetCase = draft.cases?.find(item => item.case_id === caseId)
@ -185,6 +216,7 @@ const useConfig = (id: string, payload: IfElseNodeType) => {
handleAddCondition,
handleRemoveCondition,
handleUpdateCondition,
handleAddSubVariableCondition,
handleUpdateConditionLogicalOperator,
nodesOutputVars: availableVars,
availableNodes: availableNodesWithParent,

View File

@ -434,6 +434,7 @@ const translation = {
addCondition: 'Add Condition',
conditionNotSetup: 'Condition NOT setup',
selectVariable: 'Select variable...',
addSubVariable: 'Sub Variable',
},
variableAssigner: {
title: 'Assign variables',

View File

@ -434,6 +434,7 @@ const translation = {
addCondition: '添加条件',
conditionNotSetup: '条件未设置',
selectVariable: '选择变量',
addSubVariable: '添加子变量',
},
variableAssigner: {
title: '变量赋值',