mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-14 03:35:52 +08:00
### What problem does this PR solve? feat: Build the edges of Switch by form data #1739 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
7927d80a84
commit
96438ca821
@ -4,7 +4,11 @@ import { useEffect, useMemo, useState } from 'react';
|
||||
import { useUpdateNodeInternals } from 'reactflow';
|
||||
import { Operator } from '../../constant';
|
||||
import { IPosition, NodeData } from '../../interface';
|
||||
import { buildNewPositionMap, isKeysEqual } from '../../utils';
|
||||
import {
|
||||
buildNewPositionMap,
|
||||
generateSwitchHandleText,
|
||||
isKeysEqual,
|
||||
} from '../../utils';
|
||||
|
||||
export const useBuildCategorizeHandlePositions = ({
|
||||
data,
|
||||
@ -32,7 +36,7 @@ export const useBuildCategorizeHandlePositions = ({
|
||||
const position = positionMap[x];
|
||||
let text = x;
|
||||
if (operatorName === Operator.Switch) {
|
||||
text = `Item ${idx + 1}`;
|
||||
text = generateSwitchHandleText(idx);
|
||||
}
|
||||
return { text, ...position };
|
||||
})
|
||||
|
@ -28,14 +28,15 @@ interface INameInputProps {
|
||||
|
||||
const getOtherFieldValues = (
|
||||
form: FormInstance,
|
||||
formListName: string = 'items',
|
||||
field: FormListFieldData,
|
||||
latestField: string,
|
||||
) =>
|
||||
(form.getFieldValue(['items']) ?? [])
|
||||
(form.getFieldValue([formListName]) ?? [])
|
||||
.map((x: any) => x[latestField])
|
||||
.filter(
|
||||
(x: string) =>
|
||||
x !== form.getFieldValue(['items', field.name, latestField]),
|
||||
x !== form.getFieldValue([formListName, field.name, latestField]),
|
||||
);
|
||||
|
||||
const NameInput = ({
|
||||
@ -132,7 +133,12 @@ const DynamicCategorize = ({ nodeId }: IProps) => {
|
||||
]}
|
||||
>
|
||||
<NameInput
|
||||
otherNames={getOtherFieldValues(form, field, 'name')}
|
||||
otherNames={getOtherFieldValues(
|
||||
form,
|
||||
'items',
|
||||
field,
|
||||
'name',
|
||||
)}
|
||||
validate={(errors: string[]) =>
|
||||
form.setFields([
|
||||
{
|
||||
@ -159,7 +165,7 @@ const DynamicCategorize = ({ nodeId }: IProps) => {
|
||||
<Select
|
||||
allowClear
|
||||
options={buildCategorizeToOptions(
|
||||
getOtherFieldValues(form, field, 'to'),
|
||||
getOtherFieldValues(form, 'items', field, 'to'),
|
||||
)}
|
||||
/>
|
||||
</Form.Item>
|
||||
@ -173,14 +179,6 @@ const DynamicCategorize = ({ nodeId }: IProps) => {
|
||||
);
|
||||
}}
|
||||
</Form.List>
|
||||
|
||||
{/* <Form.Item noStyle shouldUpdate>
|
||||
{() => (
|
||||
<Typography>
|
||||
<pre>{JSON.stringify(form.getFieldsValue(), null, 2)}</pre>
|
||||
</Typography>
|
||||
)}
|
||||
</Form.Item> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -53,10 +53,11 @@ import {
|
||||
initialSwitchValues,
|
||||
initialWikipediaValues,
|
||||
} from './constant';
|
||||
import { ICategorizeForm, IRelevantForm } from './interface';
|
||||
import { ICategorizeForm, IRelevantForm, ISwitchForm } from './interface';
|
||||
import useGraphStore, { RFState } from './store';
|
||||
import {
|
||||
buildDslComponentsByGraph,
|
||||
generateSwitchHandleText,
|
||||
receiveMessageError,
|
||||
replaceIdWithText,
|
||||
} from './utils';
|
||||
@ -498,6 +499,31 @@ export const useWatchNodeFormDataChange = () => {
|
||||
[setEdgesByNodeId],
|
||||
);
|
||||
|
||||
const buildSwitchEdgesByFormData = useCallback(
|
||||
(nodeId: string, form: ISwitchForm) => {
|
||||
// add
|
||||
// delete
|
||||
// edit
|
||||
const conditions = form.conditions;
|
||||
const downstreamEdges = conditions.reduce<Edge[]>((pre, _, idx) => {
|
||||
const target = conditions[idx]?.to;
|
||||
if (target) {
|
||||
pre.push({
|
||||
id: uuid(),
|
||||
source: nodeId,
|
||||
target,
|
||||
sourceHandle: generateSwitchHandleText(idx),
|
||||
});
|
||||
}
|
||||
|
||||
return pre;
|
||||
}, []);
|
||||
|
||||
setEdgesByNodeId(nodeId, downstreamEdges);
|
||||
},
|
||||
[setEdgesByNodeId],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
nodes.forEach((node) => {
|
||||
const currentNode = getNode(node.id);
|
||||
@ -510,6 +536,9 @@ export const useWatchNodeFormDataChange = () => {
|
||||
case Operator.Categorize:
|
||||
buildCategorizeEdgesByFormData(node.id, form as ICategorizeForm);
|
||||
break;
|
||||
case Operator.Switch:
|
||||
buildSwitchEdgesByFormData(node.id, form as ISwitchForm);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -519,5 +548,6 @@ export const useWatchNodeFormDataChange = () => {
|
||||
buildCategorizeEdgesByFormData,
|
||||
getNode,
|
||||
buildRelevantEdgesByFormData,
|
||||
buildSwitchEdgesByFormData,
|
||||
]);
|
||||
};
|
||||
|
@ -23,7 +23,7 @@ import { devtools } from 'zustand/middleware';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
import { Operator } from './constant';
|
||||
import { NodeData } from './interface';
|
||||
import { isEdgeEqual } from './utils';
|
||||
import { getOperatorIndex, isEdgeEqual } from './utils';
|
||||
|
||||
export type RFState = {
|
||||
nodes: Node<NodeData>[];
|
||||
@ -184,14 +184,19 @@ const useGraphStore = create<RFState>()(
|
||||
'to',
|
||||
]);
|
||||
break;
|
||||
// case Operator.Switch:
|
||||
// if (sourceHandle)
|
||||
// updateNodeForm(source, target, [
|
||||
// 'conditions',
|
||||
// sourceHandle,
|
||||
// 'to',
|
||||
// ]);
|
||||
// break;
|
||||
case Operator.Switch: {
|
||||
if (sourceHandle) {
|
||||
const operatorIndex = getOperatorIndex(sourceHandle);
|
||||
if (operatorIndex) {
|
||||
updateNodeForm(source, target, [
|
||||
'conditions',
|
||||
operatorIndex,
|
||||
'to',
|
||||
]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -201,7 +206,11 @@ const useGraphStore = create<RFState>()(
|
||||
// Delete the edge on the classification node or relevant node anchor when the anchor is connected to other nodes
|
||||
const { edges, getOperatorTypeFromId, deleteEdgeById } = get();
|
||||
// the node containing the anchor
|
||||
const anchoredNodes = [Operator.Categorize, Operator.Relevant];
|
||||
const anchoredNodes = [
|
||||
Operator.Categorize,
|
||||
Operator.Relevant,
|
||||
Operator.Switch,
|
||||
];
|
||||
if (
|
||||
anchoredNodes.some(
|
||||
(x) => x === getOperatorTypeFromId(connection.source),
|
||||
@ -265,6 +274,19 @@ const useGraphStore = create<RFState>()(
|
||||
'to',
|
||||
]);
|
||||
break;
|
||||
case Operator.Switch: {
|
||||
if (sourceHandle) {
|
||||
const operatorIndex = getOperatorIndex(sourceHandle);
|
||||
if (operatorIndex) {
|
||||
updateNodeForm(source, undefined, [
|
||||
'conditions',
|
||||
operatorIndex,
|
||||
'to',
|
||||
]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
import { Button, Card, Form, Input, Select, Typography } from 'antd';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Operator } from '../constant';
|
||||
import { useBuildFormSelectOptions } from '../form-hooks';
|
||||
import { IOperatorForm } from '../interface';
|
||||
import { IOperatorForm, ISwitchForm } from '../interface';
|
||||
import { getOtherFieldValues } from '../utils';
|
||||
|
||||
const subLabelCol = {
|
||||
span: 7,
|
||||
@ -14,17 +14,20 @@ const subWrapperCol = {
|
||||
span: 17,
|
||||
};
|
||||
|
||||
const SwitchForm: React.FC = ({
|
||||
form,
|
||||
onValuesChange,
|
||||
nodeId,
|
||||
}: IOperatorForm) => {
|
||||
const SwitchForm = ({ onValuesChange, node, form }: IOperatorForm) => {
|
||||
const { t } = useTranslation();
|
||||
const buildCategorizeToOptions = useBuildFormSelectOptions(
|
||||
Operator.Categorize,
|
||||
nodeId,
|
||||
Operator.Switch,
|
||||
node?.id,
|
||||
);
|
||||
|
||||
const getSelectedConditionTos = () => {
|
||||
const conditions: ISwitchForm['conditions'] =
|
||||
form?.getFieldValue('conditions');
|
||||
|
||||
return conditions?.filter((x) => !!x).map((x) => x?.to) ?? [];
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
labelCol={{ span: 8 }}
|
||||
@ -36,7 +39,10 @@ const SwitchForm: React.FC = ({
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<Form.Item label={t('flow.to')} name={['end_cpn_id']}>
|
||||
<Select options={buildCategorizeToOptions([])} />
|
||||
<Select
|
||||
allowClear
|
||||
options={buildCategorizeToOptions(getSelectedConditionTos())}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('flow.no')} name={['no']}>
|
||||
<Input />
|
||||
@ -65,7 +71,13 @@ const SwitchForm: React.FC = ({
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label={t('flow.to')} name={[field.name, 'to']}>
|
||||
<Select options={buildCategorizeToOptions([])} />
|
||||
<Select
|
||||
allowClear
|
||||
options={buildCategorizeToOptions([
|
||||
form?.getFieldValue('end_cpn_id'),
|
||||
...getOtherFieldValues(form!, 'conditions', field, 'to'),
|
||||
])}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="Items">
|
||||
<Form.List name={[field.name, 'items']}>
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { DSLComponents } from '@/interfaces/database/flow';
|
||||
import { removeUselessFieldsFromValues } from '@/utils/form';
|
||||
import { FormInstance, FormListFieldData } from 'antd';
|
||||
import { humanId } from 'human-id';
|
||||
import { curry, intersectionWith, isEqual, sample } from 'lodash';
|
||||
import { curry, get, intersectionWith, isEqual, sample } from 'lodash';
|
||||
import pipe from 'lodash/fp/pipe';
|
||||
import isObject from 'lodash/isObject';
|
||||
import { Edge, Node, Position } from 'reactflow';
|
||||
@ -209,3 +210,27 @@ export const buildNewPositionMap = (
|
||||
export const isKeysEqual = (currentKeys: string[], previousKeys: string[]) => {
|
||||
return isEqual(currentKeys.sort(), previousKeys.sort());
|
||||
};
|
||||
|
||||
export const getOperatorIndex = (handleTitle: string) => {
|
||||
return handleTitle.split(' ').at(-1);
|
||||
};
|
||||
|
||||
// Get the value of other forms except itself
|
||||
export const getOtherFieldValues = (
|
||||
form: FormInstance,
|
||||
formListName: string = 'items',
|
||||
field: FormListFieldData,
|
||||
latestField: string,
|
||||
) =>
|
||||
(form.getFieldValue([formListName]) ?? [])
|
||||
.map((x: any) => {
|
||||
return get(x, latestField);
|
||||
})
|
||||
.filter(
|
||||
(x: string) =>
|
||||
x !== form.getFieldValue([formListName, field.name, latestField]),
|
||||
);
|
||||
|
||||
export const generateSwitchHandleText = (idx: number) => {
|
||||
return `Item ${idx + 1}`;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user