mirror of
https://github.com/langgenius/dify.git
synced 2026-04-05 10:12:43 +08:00
feat: workflow knowledge retrieval metadata
This commit is contained in:
@@ -4,6 +4,7 @@ const useNodeCrud = <T>(id: string, data: CommonNodeType<T>) => {
|
||||
const { handleNodeDataUpdateWithSyncDraft } = useNodeDataUpdate()
|
||||
|
||||
const setInputs = (newInputs: CommonNodeType<T>) => {
|
||||
console.log(newInputs, 'xx')
|
||||
handleNodeDataUpdateWithSyncDraft({
|
||||
id,
|
||||
data: newInputs,
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import {
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {
|
||||
RiAddLine,
|
||||
} from '@remixicon/react'
|
||||
import MetadataIcon from './metadata-icon'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
@@ -13,6 +15,7 @@ import {
|
||||
import Button from '@/app/components/base/button'
|
||||
import Input from '@/app/components/base/input'
|
||||
import type { MetadataShape } from '@/app/components/workflow/nodes/knowledge-retrieval/types'
|
||||
import type { MetadataInDoc } from '@/models/datasets'
|
||||
|
||||
const AddCondition = ({
|
||||
metadataList,
|
||||
@@ -25,6 +28,11 @@ const AddCondition = ({
|
||||
return metadataList?.filter(metadata => metadata.name.includes(searchText))
|
||||
}, [metadataList, searchText])
|
||||
|
||||
const handleAddConditionWrapped = useCallback((item: MetadataInDoc) => {
|
||||
handleAddCondition?.(item)
|
||||
setOpen(false)
|
||||
}, [handleAddCondition])
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
@@ -61,10 +69,13 @@ const AddCondition = ({
|
||||
key={metadata.id}
|
||||
className='flex items-center px-3 h-6 rounded-md system-sm-medium text-text-secondary cursor-pointer hover:bg-state-base-hover'
|
||||
>
|
||||
<div className='mr-1 p-[1px]'>
|
||||
<MetadataIcon type={metadata.type} />
|
||||
</div>
|
||||
<div
|
||||
className='grow truncate'
|
||||
title={metadata.name}
|
||||
onClick={() => handleAddCondition?.(metadata.name)}
|
||||
onClick={() => handleAddConditionWrapped(metadata)}
|
||||
>
|
||||
{metadata.name}
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,10 @@ import {
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { RiDeleteBinLine } from '@remixicon/react'
|
||||
import {
|
||||
RiDeleteBinLine,
|
||||
} from '@remixicon/react'
|
||||
import MetadataIcon from '../metadata-icon'
|
||||
import {
|
||||
VARIABLE_REGEX,
|
||||
comparisonOperatorNotRequireValue,
|
||||
@@ -12,7 +15,6 @@ import ConditionOperator from './condition-operator'
|
||||
import ConditionString from './condition-string'
|
||||
import ConditionNumber from './condition-number'
|
||||
import ConditionDate from './condition-date'
|
||||
import { useCondition } from './hooks'
|
||||
import type {
|
||||
ComparisonOperator,
|
||||
HandleRemoveCondition,
|
||||
@@ -21,11 +23,6 @@ import type {
|
||||
MetadataShape,
|
||||
} from '@/app/components/workflow/nodes/knowledge-retrieval/types'
|
||||
import { MetadataFilteringVariableType } from '@/app/components/workflow/nodes/knowledge-retrieval/types'
|
||||
|
||||
import type {
|
||||
Node,
|
||||
NodeOutPutVar,
|
||||
} from '@/app/components/workflow/types'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type ConditionItemProps = {
|
||||
@@ -34,9 +31,7 @@ type ConditionItemProps = {
|
||||
condition: MetadataFilteringCondition // condition may the condition of case or condition of sub variable
|
||||
onRemoveCondition?: HandleRemoveCondition
|
||||
onUpdateCondition?: HandleUpdateCondition
|
||||
nodesOutputVars: NodeOutPutVar[]
|
||||
availableNodes: Node[]
|
||||
} & Pick<MetadataShape, 'metadataList'>
|
||||
} & Pick<MetadataShape, 'metadataList' | 'availableStringVars' | 'availableStringNodesWithParent' | 'availableNumberVars' | 'availableNumberNodesWithParent'>
|
||||
const ConditionItem = ({
|
||||
className,
|
||||
disabled,
|
||||
@@ -44,11 +39,12 @@ const ConditionItem = ({
|
||||
onRemoveCondition,
|
||||
onUpdateCondition,
|
||||
metadataList = [],
|
||||
nodesOutputVars,
|
||||
availableNodes,
|
||||
availableStringVars = [],
|
||||
availableStringNodesWithParent = [],
|
||||
availableNumberVars = [],
|
||||
availableNumberNodesWithParent = [],
|
||||
}: ConditionItemProps) => {
|
||||
const [isHovered, setIsHovered] = useState(false)
|
||||
const { getConditionVariableType } = useCondition()
|
||||
|
||||
const canChooseOperator = useMemo(() => {
|
||||
if (disabled)
|
||||
@@ -66,7 +62,13 @@ const ConditionItem = ({
|
||||
}, [metadataList, condition.name])
|
||||
|
||||
const handleConditionOperatorChange = useCallback((operator: ComparisonOperator) => {
|
||||
onUpdateCondition?.(condition.name, { ...condition, comparison_operator: operator })
|
||||
onUpdateCondition?.(
|
||||
condition.name,
|
||||
{
|
||||
...condition,
|
||||
value: comparisonOperatorNotRequireValue(condition.comparison_operator) ? undefined : condition.value,
|
||||
comparison_operator: operator,
|
||||
})
|
||||
}, [onUpdateCondition, condition])
|
||||
|
||||
const valueAndValueMethod = useMemo(() => {
|
||||
@@ -95,7 +97,7 @@ const ConditionItem = ({
|
||||
valueMethod: 'constant',
|
||||
}
|
||||
}, [currentMetadata, condition.value])
|
||||
const [localValueMethod, setLocalValueMethod] = useState(valueAndValueMethod.value)
|
||||
const [localValueMethod, setLocalValueMethod] = useState(valueAndValueMethod.valueMethod)
|
||||
|
||||
const handleValueMethodChange = useCallback((v: string) => {
|
||||
setLocalValueMethod(v)
|
||||
@@ -114,9 +116,12 @@ const ConditionItem = ({
|
||||
)}>
|
||||
<div className='flex items-center p-1'>
|
||||
<div className='grow w-0'>
|
||||
<div className='inline-flex items-center h-6 border-[0.5px] border-components-panel-border-subtle bg-components-badge-white-to-dark rounded-md shadow-xs'>
|
||||
<div className='mr-0.5 system-xs-medium text-text-secondary'>Language</div>
|
||||
<div className='system-xs-regular text-text-tertiary'>string</div>
|
||||
<div className='inline-flex items-center pl-1 pr-1.5 h-6 border-[0.5px] border-components-panel-border-subtle bg-components-badge-white-to-dark rounded-md shadow-xs'>
|
||||
<div className='mr-0.5 p-[1px]'>
|
||||
<MetadataIcon type={currentMetadata?.type} className='w-3 h-3' />
|
||||
</div>
|
||||
<div className='mr-0.5 system-xs-medium text-text-secondary'>{currentMetadata?.name}</div>
|
||||
<div className='system-xs-regular text-text-tertiary'>{currentMetadata?.type}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mx-1 w-[1px] h-3 bg-divider-regular'></div>
|
||||
@@ -127,38 +132,40 @@ const ConditionItem = ({
|
||||
onSelect={handleConditionOperatorChange}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
!comparisonOperatorNotRequireValue(condition.comparison_operator) && getConditionVariableType(condition.name) === MetadataFilteringVariableType.string && (
|
||||
<ConditionString
|
||||
valueMethod={localValueMethod}
|
||||
onValueMethodChange={handleValueMethodChange}
|
||||
nodesOutputVars={nodesOutputVars}
|
||||
availableNodes={availableNodes}
|
||||
value={valueAndValueMethod.value}
|
||||
onChange={handleValueChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
!comparisonOperatorNotRequireValue(condition.comparison_operator) && getConditionVariableType(condition.name) === MetadataFilteringVariableType.number && (
|
||||
<ConditionNumber
|
||||
valueMethod={localValueMethod}
|
||||
onValueMethodChange={handleValueMethodChange}
|
||||
nodesOutputVars={nodesOutputVars}
|
||||
availableNodes={availableNodes}
|
||||
value={valueAndValueMethod.value}
|
||||
onChange={handleValueChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
!comparisonOperatorNotRequireValue(condition.comparison_operator) && getConditionVariableType(condition.name) === MetadataFilteringVariableType.date && (
|
||||
<ConditionDate
|
||||
value={condition.value}
|
||||
onChange={handleValueChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<div className='border-t border-t-divider-subtle'>
|
||||
{
|
||||
!comparisonOperatorNotRequireValue(condition.comparison_operator) && currentMetadata?.type === MetadataFilteringVariableType.string && (
|
||||
<ConditionString
|
||||
valueMethod={localValueMethod}
|
||||
onValueMethodChange={handleValueMethodChange}
|
||||
nodesOutputVars={availableStringVars}
|
||||
availableNodes={availableStringNodesWithParent}
|
||||
value={valueAndValueMethod.value}
|
||||
onChange={handleValueChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
!comparisonOperatorNotRequireValue(condition.comparison_operator) && currentMetadata?.type === MetadataFilteringVariableType.number && (
|
||||
<ConditionNumber
|
||||
valueMethod={localValueMethod}
|
||||
onValueMethodChange={handleValueMethodChange}
|
||||
nodesOutputVars={availableNumberVars}
|
||||
availableNodes={availableNumberNodesWithParent}
|
||||
value={valueAndValueMethod.value}
|
||||
onChange={handleValueChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
!comparisonOperatorNotRequireValue(condition.comparison_operator) && currentMetadata?.type === MetadataFilteringVariableType.time && (
|
||||
<ConditionDate
|
||||
value={condition.value}
|
||||
onChange={handleValueChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className='shrink-0 flex items-center justify-center ml-1 mt-1 w-6 h-6 rounded-lg cursor-pointer hover:bg-state-destructive-hover text-text-tertiary hover:text-text-destructive'
|
||||
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
NodeOutPutVar,
|
||||
ValueSelector,
|
||||
} from '@/app/components/workflow/types'
|
||||
import Input from '@/app/components/base/input'
|
||||
|
||||
type ConditionNumberProps = {
|
||||
value?: string | number
|
||||
@@ -36,7 +37,7 @@ const ConditionNumber = ({
|
||||
{
|
||||
valueMethod === 'variable' && (
|
||||
<ConditionVariableSelector
|
||||
valueSelector={(value as string).split('.')}
|
||||
valueSelector={value ? (value as string).split('.') : []}
|
||||
onChange={handleVariableValueChange}
|
||||
nodesOutputVars={nodesOutputVars}
|
||||
availableNodes={availableNodes}
|
||||
@@ -45,10 +46,12 @@ const ConditionNumber = ({
|
||||
}
|
||||
{
|
||||
valueMethod === 'constant' && (
|
||||
<input
|
||||
<Input
|
||||
className='bg-transparent hover:bg-transparent outline-none border-none focus:shadow-none focus:bg-transparent'
|
||||
value={value}
|
||||
type='number'
|
||||
onChange={e => onChange(e.target.value)}
|
||||
placeholder='Enter value'
|
||||
type='number'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
NodeOutPutVar,
|
||||
ValueSelector,
|
||||
} from '@/app/components/workflow/types'
|
||||
import Input from '@/app/components/base/input'
|
||||
|
||||
type ConditionStringProps = {
|
||||
value?: string
|
||||
@@ -17,7 +18,7 @@ type ConditionStringProps = {
|
||||
const ConditionString = ({
|
||||
value,
|
||||
onChange,
|
||||
valueMethod,
|
||||
valueMethod = 'constant',
|
||||
onValueMethodChange,
|
||||
nodesOutputVars,
|
||||
availableNodes,
|
||||
@@ -36,7 +37,7 @@ const ConditionString = ({
|
||||
{
|
||||
valueMethod === 'variable' && (
|
||||
<ConditionVariableSelector
|
||||
valueSelector={value!.split('.')}
|
||||
valueSelector={value ? value!.split('.') : []}
|
||||
onChange={handleVariableValueChange}
|
||||
nodesOutputVars={nodesOutputVars}
|
||||
availableNodes={availableNodes}
|
||||
@@ -45,9 +46,11 @@ const ConditionString = ({
|
||||
}
|
||||
{
|
||||
valueMethod === 'constant' && (
|
||||
<input
|
||||
<Input
|
||||
className='bg-transparent hover:bg-transparent outline-none border-none focus:shadow-none focus:bg-transparent'
|
||||
value={value}
|
||||
onChange={e => onChange(e.target.value)}
|
||||
placeholder='Enter value'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ const ConditionValueMethod = ({
|
||||
placement='bottom-start'
|
||||
offset={{ mainAxis: 4, crossAxis: 0 }}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
|
||||
<PortalToFollowElemTrigger asChild onClick={() => setOpen(v => !v)}>
|
||||
<Button
|
||||
className='shrink-0'
|
||||
variant='ghost'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react'
|
||||
import { useCallback, useState } from 'react'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
@@ -13,6 +13,7 @@ import type {
|
||||
Var,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
|
||||
type ConditionVariableSelectorProps = {
|
||||
valueSelector?: ValueSelector
|
||||
@@ -31,6 +32,11 @@ const ConditionVariableSelector = ({
|
||||
}: ConditionVariableSelectorProps) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const handleChange = useCallback((valueSelector: ValueSelector, varItem: Var) => {
|
||||
onChange(valueSelector, varItem)
|
||||
setOpen(false)
|
||||
}, [onChange])
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
@@ -41,14 +47,31 @@ const ConditionVariableSelector = ({
|
||||
crossAxis: 0,
|
||||
}}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(!open)}>
|
||||
<div className="cursor-pointer">
|
||||
<VariableTag
|
||||
valueSelector={valueSelector}
|
||||
varType={varType}
|
||||
availableNodes={availableNodes}
|
||||
isShort
|
||||
/>
|
||||
<PortalToFollowElemTrigger asChild onClick={() => setOpen(!open)}>
|
||||
<div className="grow flex items-center cursor-pointer h-6">
|
||||
{
|
||||
!!valueSelector.length && (
|
||||
<VariableTag
|
||||
valueSelector={valueSelector}
|
||||
varType={varType}
|
||||
availableNodes={availableNodes}
|
||||
isShort
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
!valueSelector.length && (
|
||||
<>
|
||||
<div className='grow flex items-center text-components-input-text-placeholder system-sm-regular'>
|
||||
<Variable02 className='mr-1 w-4 h-4' />
|
||||
Select variable...
|
||||
</div>
|
||||
<div className='shrink-0 flex items-center px-[5px] h-5 border border-divider-deep rounded-[5px] system-2xs-medium text-text-tertiary'>
|
||||
string
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[1000]'>
|
||||
@@ -56,7 +79,7 @@ const ConditionVariableSelector = ({
|
||||
<VarReferenceVars
|
||||
vars={nodesOutputVars}
|
||||
isSupportFileVar
|
||||
onChange={onChange}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
import { RiLoopLeftLine } from '@remixicon/react'
|
||||
import { useMemo } from 'react'
|
||||
import ConditionItem from './condition-item'
|
||||
import type {
|
||||
Node,
|
||||
NodeOutPutVar,
|
||||
} from '@/app/components/workflow/types'
|
||||
import cn from '@/utils/classnames'
|
||||
import type { MetadataShape } from '@/app/components/workflow/nodes/knowledge-retrieval/types'
|
||||
import { LogicalOperator } from '@/app/components/workflow/nodes/knowledge-retrieval/types'
|
||||
|
||||
type ConditionListProps = {
|
||||
disabled?: boolean
|
||||
nodesOutputVars?: NodeOutPutVar[]
|
||||
availableNodes?: Node[]
|
||||
} & Omit<MetadataShape, 'handleAddCondition'>
|
||||
|
||||
const ConditionList = ({
|
||||
disabled,
|
||||
metadataList = [],
|
||||
@@ -24,25 +18,21 @@ const ConditionList = ({
|
||||
handleRemoveCondition,
|
||||
handleToggleConditionLogicalOperator,
|
||||
handleUpdateCondition,
|
||||
nodesOutputVars = [],
|
||||
availableNodes = [],
|
||||
availableStringVars,
|
||||
availableStringNodesWithParent,
|
||||
availableNumberVars,
|
||||
availableNumberNodesWithParent,
|
||||
}: ConditionListProps) => {
|
||||
const { conditions, logical_operator } = metadataFilteringConditions
|
||||
|
||||
const conditionItemClassName = useMemo(() => {
|
||||
if (conditions.length < 2)
|
||||
return ''
|
||||
return logical_operator === LogicalOperator.and ? 'pl-[51px]' : 'pl-[42px]'
|
||||
}, [conditions.length, logical_operator])
|
||||
|
||||
return (
|
||||
<div className={cn('relative')}>
|
||||
{
|
||||
conditions.length > 1 && (
|
||||
<div className={cn(
|
||||
'absolute top-0 bottom-0 left-0 w-[60px]',
|
||||
'absolute top-0 bottom-0 left-0 w-[44px]',
|
||||
)}>
|
||||
<div className='absolute top-4 bottom-4 left-[46px] w-2.5 border border-divider-deep rounded-l-[8px] border-r-0'></div>
|
||||
<div className='absolute top-4 bottom-4 right-1 w-2.5 border border-divider-deep rounded-l-[8px] border-r-0'></div>
|
||||
<div className='absolute top-1/2 -translate-y-1/2 right-0 w-4 h-[29px] bg-components-panel-bg'></div>
|
||||
<div
|
||||
className='absolute top-1/2 right-1 -translate-y-1/2 flex items-center px-1 h-[21px] rounded-md border-[0.5px] border-components-button-secondary-border shadow-xs bg-components-button-secondary-bg text-text-accent-secondary text-[10px] font-semibold cursor-pointer select-none'
|
||||
@@ -54,21 +44,24 @@ const ConditionList = ({
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
conditions.map(condition => (
|
||||
<ConditionItem
|
||||
key={condition.name}
|
||||
className={conditionItemClassName}
|
||||
disabled={disabled}
|
||||
condition={condition}
|
||||
onUpdateCondition={handleUpdateCondition}
|
||||
onRemoveCondition={handleRemoveCondition}
|
||||
nodesOutputVars={nodesOutputVars}
|
||||
availableNodes={availableNodes}
|
||||
metadataList={metadataList}
|
||||
/>
|
||||
))
|
||||
}
|
||||
<div className={cn(conditions.length > 1 && 'pl-[44px]')}>
|
||||
{
|
||||
conditions.map(condition => (
|
||||
<ConditionItem
|
||||
key={condition.name}
|
||||
disabled={disabled}
|
||||
condition={condition}
|
||||
onUpdateCondition={handleUpdateCondition}
|
||||
onRemoveCondition={handleRemoveCondition}
|
||||
metadataList={metadataList}
|
||||
availableStringVars={availableStringVars}
|
||||
availableStringNodesWithParent={availableStringNodesWithParent}
|
||||
availableNumberVars={availableNumberVars}
|
||||
availableNumberNodesWithParent={availableNumberNodesWithParent}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -23,12 +23,12 @@ export const getOperators = (type?: MetadataFilteringVariableType) => {
|
||||
switch (type) {
|
||||
case MetadataFilteringVariableType.string:
|
||||
return [
|
||||
ComparisonOperator.is,
|
||||
ComparisonOperator.isNot,
|
||||
ComparisonOperator.contains,
|
||||
ComparisonOperator.notContains,
|
||||
ComparisonOperator.startWith,
|
||||
ComparisonOperator.endWith,
|
||||
ComparisonOperator.is,
|
||||
ComparisonOperator.isNot,
|
||||
ComparisonOperator.empty,
|
||||
ComparisonOperator.notEmpty,
|
||||
]
|
||||
@@ -46,7 +46,8 @@ export const getOperators = (type?: MetadataFilteringVariableType) => {
|
||||
default:
|
||||
return [
|
||||
ComparisonOperator.is,
|
||||
ComparisonOperator.isNot,
|
||||
ComparisonOperator.before,
|
||||
ComparisonOperator.after,
|
||||
ComparisonOperator.empty,
|
||||
ComparisonOperator.notEmpty,
|
||||
]
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import {
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import MetadataTrigger from '../metadata-trigger'
|
||||
import MetadataFilterSelector from './metadata-filter-selector'
|
||||
import Collapse from '@/app/components/workflow/nodes/_base/components/collapse'
|
||||
@@ -12,7 +15,7 @@ type MetadataFilterProps = {
|
||||
handleMetadataFilterModeChange: (mode: MetadataFilteringModeEnum) => void
|
||||
} & MetadataShape
|
||||
const MetadataFilter = ({
|
||||
metadataFilterMode,
|
||||
metadataFilterMode = MetadataFilteringModeEnum.disabled,
|
||||
handleMetadataFilterModeChange,
|
||||
metadataModelConfig,
|
||||
handleMetadataModelChange,
|
||||
@@ -21,6 +24,13 @@ const MetadataFilter = ({
|
||||
}: MetadataFilterProps) => {
|
||||
const [collapsed, setCollapsed] = useState(true)
|
||||
|
||||
const handleMetadataFilterModeChangeWrapped = useCallback((mode: MetadataFilteringModeEnum) => {
|
||||
if (mode === MetadataFilteringModeEnum.automatic)
|
||||
setCollapsed(false)
|
||||
|
||||
handleMetadataFilterModeChange(mode)
|
||||
}, [handleMetadataFilterModeChange])
|
||||
|
||||
return (
|
||||
<Collapse
|
||||
disabled={metadataFilterMode === MetadataFilteringModeEnum.disabled || metadataFilterMode === MetadataFilteringModeEnum.manual}
|
||||
@@ -43,7 +53,7 @@ const MetadataFilter = ({
|
||||
<div className='flex items-center'>
|
||||
<MetadataFilterSelector
|
||||
value={metadataFilterMode}
|
||||
onSelect={handleMetadataFilterModeChange}
|
||||
onSelect={handleMetadataFilterModeChangeWrapped}
|
||||
/>
|
||||
{
|
||||
metadataFilterMode === MetadataFilteringModeEnum.manual && (
|
||||
|
||||
@@ -55,6 +55,7 @@ const MetadataFilterSelector = ({
|
||||
e.stopPropagation()
|
||||
setOpen(!open)
|
||||
}}
|
||||
asChild
|
||||
>
|
||||
<Button
|
||||
variant='secondary'
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { memo } from 'react'
|
||||
import {
|
||||
RiHashtag,
|
||||
RiTextSnippet,
|
||||
RiTimeLine,
|
||||
} from '@remixicon/react'
|
||||
import { MetadataFilteringVariableType } from '@/app/components/workflow/nodes/knowledge-retrieval/types'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type MetadataIconProps = {
|
||||
type?: MetadataFilteringVariableType
|
||||
className?: string
|
||||
}
|
||||
const MetadataIcon = ({
|
||||
type,
|
||||
className,
|
||||
}: MetadataIconProps) => {
|
||||
return (
|
||||
<>
|
||||
{
|
||||
type === MetadataFilteringVariableType.string && (
|
||||
<RiTextSnippet className={cn('w-3.5 h-3.5', className)} />
|
||||
)
|
||||
}
|
||||
{
|
||||
type === MetadataFilteringVariableType.number && (
|
||||
<RiHashtag className={cn('w-3.5 h-3.5', className)} />
|
||||
)
|
||||
}
|
||||
{
|
||||
type === MetadataFilteringVariableType.time && (
|
||||
<RiTimeLine className={cn('w-3.5 h-3.5', className)} />
|
||||
)
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(MetadataIcon)
|
||||
@@ -28,11 +28,13 @@ const MetadataPanel = ({
|
||||
</div>
|
||||
<div className='px-1 py-2'>
|
||||
<div className='px-3 py-1'>
|
||||
<ConditionList
|
||||
metadataList={metadataList}
|
||||
metadataFilteringConditions={metadataFilteringConditions}
|
||||
{...restProps}
|
||||
/>
|
||||
<div className='pb-2'>
|
||||
<ConditionList
|
||||
metadataList={metadataList}
|
||||
metadataFilteringConditions={metadataFilteringConditions}
|
||||
{...restProps}
|
||||
/>
|
||||
</div>
|
||||
<AddCondition
|
||||
metadataList={metadataList}
|
||||
handleAddCondition={handleAddCondition}
|
||||
|
||||
@@ -30,7 +30,7 @@ const MetadataTrigger = ({
|
||||
<RiFilter3Line className='mr-1 w-3.5 h-3.5' />
|
||||
Conditions
|
||||
<div className='flex items-center ml-1 px-1 rounded-[5px] border border-divider-deep system-2xs-medium-uppercase text-text-tertiary'>
|
||||
{metadataFilteringConditions?.conditions.length}
|
||||
{metadataFilteringConditions?.conditions.length || 0}
|
||||
</div>
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
|
||||
@@ -55,6 +55,10 @@ const Panel: FC<NodePanelProps<KnowledgeRetrievalNodeType>> = ({
|
||||
handleUpdateCondition,
|
||||
handleMetadataModelChange,
|
||||
handleMetadataCompletionParamsChange,
|
||||
availableStringVars,
|
||||
availableStringNodesWithParent,
|
||||
availableNumberVars,
|
||||
availableNumberNodesWithParent,
|
||||
} = useConfig(id, data)
|
||||
|
||||
const handleOpenFromPropsChange = useCallback((openFromProps: boolean) => {
|
||||
@@ -71,7 +75,7 @@ const Panel: FC<NodePanelProps<KnowledgeRetrievalNodeType>> = ({
|
||||
|
||||
return (
|
||||
<div className='pt-2'>
|
||||
<div className='px-4 pb-4 space-y-4'>
|
||||
<div className='px-4 pb-2 space-y-4'>
|
||||
{/* {JSON.stringify(inputs, null, 2)} */}
|
||||
<Field
|
||||
title={t(`${i18nPrefix}.queryVariable`)}
|
||||
@@ -123,7 +127,7 @@ const Panel: FC<NodePanelProps<KnowledgeRetrievalNodeType>> = ({
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
<div className='py-2'>
|
||||
<div className='mb-2 py-2'>
|
||||
<MetadataFilter
|
||||
metadataList={metadataList}
|
||||
metadataFilterMode={inputs.metadata_filtering_mode}
|
||||
@@ -136,6 +140,10 @@ const Panel: FC<NodePanelProps<KnowledgeRetrievalNodeType>> = ({
|
||||
metadataModelConfig={inputs.metadata_model_config}
|
||||
handleMetadataModelChange={handleMetadataModelChange}
|
||||
handleMetadataCompletionParamsChange={handleMetadataCompletionParamsChange}
|
||||
availableStringVars={availableStringVars}
|
||||
availableStringNodesWithParent={availableStringNodesWithParent}
|
||||
availableNumberVars={availableNumberVars}
|
||||
availableNumberNodesWithParent={availableNumberNodesWithParent}
|
||||
/>
|
||||
</div>
|
||||
<Split />
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import type { CommonNodeType, ModelConfig, ValueSelector } from '@/app/components/workflow/types'
|
||||
import type {
|
||||
CommonNodeType,
|
||||
ModelConfig,
|
||||
Node,
|
||||
NodeOutPutVar,
|
||||
ValueSelector,
|
||||
} from '@/app/components/workflow/types'
|
||||
import type { RETRIEVE_TYPE } from '@/types/app'
|
||||
import type {
|
||||
DataSet,
|
||||
@@ -58,6 +64,8 @@ export enum ComparisonOperator {
|
||||
allOf = 'all of',
|
||||
exists = 'exists',
|
||||
notExists = 'not exists',
|
||||
before = 'before',
|
||||
after = 'after',
|
||||
}
|
||||
|
||||
export enum MetadataFilteringModeEnum {
|
||||
@@ -69,7 +77,7 @@ export enum MetadataFilteringModeEnum {
|
||||
export enum MetadataFilteringVariableType {
|
||||
string = 'string',
|
||||
number = 'number',
|
||||
date = 'date',
|
||||
time = 'time',
|
||||
}
|
||||
|
||||
export type MetadataFilteringCondition = {
|
||||
@@ -95,7 +103,7 @@ export type KnowledgeRetrievalNodeType = CommonNodeType & {
|
||||
metadata_model_config?: ModelConfig
|
||||
}
|
||||
|
||||
export type HandleAddCondition = (name: string) => void
|
||||
export type HandleAddCondition = (metadataItem: MetadataInDoc) => void
|
||||
export type HandleRemoveCondition = (name: string) => void
|
||||
export type HandleUpdateCondition = (name: string, newCondition: MetadataFilteringCondition) => void
|
||||
export type HandleToggleConditionLogicalOperator = () => void
|
||||
@@ -110,4 +118,8 @@ export type MetadataShape = {
|
||||
metadataModelConfig?: ModelConfig
|
||||
handleMetadataModelChange?: (model: { modelId: string; provider: string; mode?: string; features?: string[] }) => void
|
||||
handleMetadataCompletionParamsChange?: (params: Record<string, any>) => void
|
||||
availableStringVars?: NodeOutPutVar[]
|
||||
availableStringNodesWithParent?: Node[]
|
||||
availableNumberVars?: NodeOutPutVar[]
|
||||
availableNumberNodesWithParent?: Node[]
|
||||
}
|
||||
|
||||
@@ -22,7 +22,11 @@ import type {
|
||||
MetadataFilteringModeEnum,
|
||||
MultipleRetrievalConfig,
|
||||
} from './types'
|
||||
import { ComparisonOperator, LogicalOperator } from './types'
|
||||
import {
|
||||
ComparisonOperator,
|
||||
LogicalOperator,
|
||||
MetadataFilteringVariableType,
|
||||
} from './types'
|
||||
import {
|
||||
getMultipleRetrievalConfig,
|
||||
getSelectedDatasetsMode,
|
||||
@@ -35,6 +39,7 @@ import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-cr
|
||||
import useOneStepRun from '@/app/components/workflow/nodes/_base/hooks/use-one-step-run'
|
||||
import { useCurrentProviderAndModel, useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import useAvailableVarList from '@/app/components/workflow/nodes/_base/hooks/use-available-var-list'
|
||||
|
||||
const useConfig = (id: string, payload: KnowledgeRetrievalNodeType) => {
|
||||
const { nodesReadOnly: readOnly } = useNodesReadOnly()
|
||||
@@ -303,18 +308,34 @@ const useConfig = (id: string, payload: KnowledgeRetrievalNodeType) => {
|
||||
}))
|
||||
}, [setInputs])
|
||||
|
||||
const handleAddCondition = useCallback<HandleAddCondition>((name) => {
|
||||
const handleAddCondition = useCallback<HandleAddCondition>(({ name, type }) => {
|
||||
let operator: ComparisonOperator = ComparisonOperator.is
|
||||
|
||||
if (type === MetadataFilteringVariableType.number)
|
||||
operator = ComparisonOperator.equal
|
||||
|
||||
const newCondition = {
|
||||
name,
|
||||
comparison_operator: operator,
|
||||
}
|
||||
|
||||
const newInputs = produce(inputRef.current, (draft) => {
|
||||
draft.metadata_filtering_conditions?.conditions.push({
|
||||
name,
|
||||
comparison_operator: ComparisonOperator.is,
|
||||
})
|
||||
if (draft.metadata_filtering_conditions) {
|
||||
draft.metadata_filtering_conditions.conditions.push(newCondition)
|
||||
}
|
||||
else {
|
||||
draft.metadata_filtering_conditions = {
|
||||
logical_operator: LogicalOperator.and,
|
||||
conditions: [newCondition],
|
||||
}
|
||||
}
|
||||
})
|
||||
setInputs(newInputs)
|
||||
}, [setInputs])
|
||||
|
||||
const handleRemoveCondition = useCallback<HandleRemoveCondition>((name) => {
|
||||
const index = inputRef.current.metadata_filtering_conditions?.conditions.findIndex(c => c.name === name) || -1
|
||||
const conditions = inputRef.current.metadata_filtering_conditions?.conditions || []
|
||||
const index = conditions.findIndex(c => c.name === name)
|
||||
const newInputs = produce(inputRef.current, (draft) => {
|
||||
if (index > -1)
|
||||
draft.metadata_filtering_conditions?.conditions.splice(index, 1)
|
||||
@@ -323,7 +344,8 @@ const useConfig = (id: string, payload: KnowledgeRetrievalNodeType) => {
|
||||
}, [setInputs])
|
||||
|
||||
const handleUpdateCondition = useCallback<HandleUpdateCondition>((name, newCondition) => {
|
||||
const index = inputRef.current.metadata_filtering_conditions?.conditions.findIndex(c => c.name === name) || -1
|
||||
const conditions = inputRef.current.metadata_filtering_conditions?.conditions || []
|
||||
const index = conditions.findIndex(c => c.name === name)
|
||||
const newInputs = produce(inputRef.current, (draft) => {
|
||||
if (index > -1)
|
||||
draft.metadata_filtering_conditions!.conditions[index] = newCondition
|
||||
@@ -362,6 +384,30 @@ const useConfig = (id: string, payload: KnowledgeRetrievalNodeType) => {
|
||||
setInputs(newInputs)
|
||||
}, [setInputs])
|
||||
|
||||
const filterStringVar = useCallback((varPayload: Var) => {
|
||||
return [VarType.string].includes(varPayload.type)
|
||||
}, [])
|
||||
|
||||
const {
|
||||
availableVars: availableStringVars,
|
||||
availableNodesWithParent: availableStringNodesWithParent,
|
||||
} = useAvailableVarList(id, {
|
||||
onlyLeafNodeVar: false,
|
||||
filterVar: filterStringVar,
|
||||
})
|
||||
|
||||
const filterNumberVar = useCallback((varPayload: Var) => {
|
||||
return [VarType.number].includes(varPayload.type)
|
||||
}, [])
|
||||
|
||||
const {
|
||||
availableVars: availableNumberVars,
|
||||
availableNodesWithParent: availableNumberNodesWithParent,
|
||||
} = useAvailableVarList(id, {
|
||||
onlyLeafNodeVar: false,
|
||||
filterVar: filterNumberVar,
|
||||
})
|
||||
|
||||
return {
|
||||
readOnly,
|
||||
inputs,
|
||||
@@ -390,6 +436,10 @@ const useConfig = (id: string, payload: KnowledgeRetrievalNodeType) => {
|
||||
handleToggleConditionLogicalOperator,
|
||||
handleMetadataModelChange,
|
||||
handleMetadataCompletionParamsChange,
|
||||
availableStringVars,
|
||||
availableStringNodesWithParent,
|
||||
availableNumberVars,
|
||||
availableNumberNodesWithParent,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user