balibabu
commited on
Commit
·
f8510ae
1
Parent(s):
ba19dbf
feat: after deleting the edge, set the corresponding field in the node's form field to undefined #918 (#1393)
Browse files### What problem does this PR solve?
feat: after deleting the edge, set the corresponding field in the node's
form field to undefined #918
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
web/src/locales/en.ts
CHANGED
@@ -573,9 +573,8 @@ The above is the content you need to summarize.`,
|
|
573 |
relevantDescription: `This component is used to judge if the output of upstream is relevent to user's latest question. 'Yes' represents that they're relevant. 'No' represents they're irrelevant.`,
|
574 |
rewriteQuestionDescription: `This component is used to refine user's quesion. Typically, when a user's original question can't retrieve relevant information from knowledge base, this component help you change the question into a proper one which might be more consistant with the expressions in knowledge base. Only 'Retrieval' can be its downstreams.`,
|
575 |
messageDescription:
|
576 |
-
'This component is used to send user static information.',
|
577 |
-
keywordDescription:
|
578 |
-
'This component is used to send user static information.',
|
579 |
promptText: `Please summarize the following paragraphs. Be careful with the numbers, do not make things up. Paragraphs as following:
|
580 |
{input}
|
581 |
The above is the content you need to summarize.`,
|
|
|
573 |
relevantDescription: `This component is used to judge if the output of upstream is relevent to user's latest question. 'Yes' represents that they're relevant. 'No' represents they're irrelevant.`,
|
574 |
rewriteQuestionDescription: `This component is used to refine user's quesion. Typically, when a user's original question can't retrieve relevant information from knowledge base, this component help you change the question into a proper one which might be more consistant with the expressions in knowledge base. Only 'Retrieval' can be its downstreams.`,
|
575 |
messageDescription:
|
576 |
+
'This component is used to send user static information. You can prepare several messages which will be chosen randomly.',
|
577 |
+
keywordDescription: `This component is used to extract keywords from user's question. Top N specifies the number of keywords you need to extract.`,
|
|
|
578 |
promptText: `Please summarize the following paragraphs. Be careful with the numbers, do not make things up. Paragraphs as following:
|
579 |
{input}
|
580 |
The above is the content you need to summarize.`,
|
web/src/locales/zh.ts
CHANGED
@@ -537,6 +537,27 @@ export default {
|
|
537 |
messageMsg: '请输入消息或删除此字段。',
|
538 |
addField: '新增字段',
|
539 |
loop: '环',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
540 |
},
|
541 |
footer: {
|
542 |
profile: 'All rights reserved @ React',
|
|
|
537 |
messageMsg: '请输入消息或删除此字段。',
|
538 |
addField: '新增字段',
|
539 |
loop: '环',
|
540 |
+
createFlow: 'Create a workflow',
|
541 |
+
yes: 'Yes',
|
542 |
+
no: 'No',
|
543 |
+
key: 'key',
|
544 |
+
componentId: 'component id',
|
545 |
+
add: 'Add',
|
546 |
+
operation: 'operation',
|
547 |
+
beginDescription: 'This is where the flow begin',
|
548 |
+
answerDescription: `This component is used as an interface between bot and human. It receives input of user and display the result of the computation of the bot.`,
|
549 |
+
retrievalDescription: `This component is for the process of retrieving relevent information from knowledge base. So, knowledgebases should be selected. If there's nothing retrieved, the 'Empty response' will be returned.`,
|
550 |
+
generateDescription: `This component is used to call LLM to generate text. Be careful about the prompt setting.`,
|
551 |
+
categorizeDescription: `This component is used to categorize text. Please specify the name, description and examples of the category. Every single category leads to different downstream components.`,
|
552 |
+
relevantDescription: `This component is used to judge if the output of upstream is relevent to user's latest question. 'Yes' represents that they're relevant. 'No' represents they're irrelevant.`,
|
553 |
+
rewriteQuestionDescription: `This component is used to refine user's quesion. Typically, when a user's original question can't retrieve relevant information from knowledge base, this component help you change the question into a proper one which might be more consistant with the expressions in knowledge base. Only 'Retrieval' can be its downstreams.`,
|
554 |
+
messageDescription:
|
555 |
+
'This component is used to send user static information.',
|
556 |
+
keywordDescription:
|
557 |
+
'This component is used to send user static information.',
|
558 |
+
promptText: `Please summarize the following paragraphs. Be careful with the numbers, do not make things up. Paragraphs as following:
|
559 |
+
{input}
|
560 |
+
The above is the content you need to summarize.`,
|
561 |
},
|
562 |
footer: {
|
563 |
profile: 'All rights reserved @ React',
|
web/src/pages/flow/flow-sider/index.tsx
CHANGED
@@ -2,6 +2,7 @@ import { useTranslate } from '@/hooks/commonHooks';
|
|
2 |
import { Card, Divider, Flex, Layout, Tooltip } from 'antd';
|
3 |
import classNames from 'classnames';
|
4 |
import lowerFirst from 'lodash/lowerFirst';
|
|
|
5 |
import { Operator, componentMenuList } from '../constant';
|
6 |
import { useHandleDrag } from '../hooks';
|
7 |
import OperatorIcon from '../operator-icon';
|
@@ -29,7 +30,7 @@ const FlowSide = ({ setCollapsed, collapsed }: IProps) => {
|
|
29 |
<Flex vertical gap={10} className={styles.siderContent}>
|
30 |
{componentMenuList.map((x) => {
|
31 |
return (
|
32 |
-
|
33 |
{x.name === Operator.DuckDuckGo && (
|
34 |
<Divider
|
35 |
style={{
|
@@ -57,7 +58,7 @@ const FlowSide = ({ setCollapsed, collapsed }: IProps) => {
|
|
57 |
</section>
|
58 |
</Flex>
|
59 |
</Card>
|
60 |
-
|
61 |
);
|
62 |
})}
|
63 |
</Flex>
|
|
|
2 |
import { Card, Divider, Flex, Layout, Tooltip } from 'antd';
|
3 |
import classNames from 'classnames';
|
4 |
import lowerFirst from 'lodash/lowerFirst';
|
5 |
+
import React from 'react';
|
6 |
import { Operator, componentMenuList } from '../constant';
|
7 |
import { useHandleDrag } from '../hooks';
|
8 |
import OperatorIcon from '../operator-icon';
|
|
|
30 |
<Flex vertical gap={10} className={styles.siderContent}>
|
31 |
{componentMenuList.map((x) => {
|
32 |
return (
|
33 |
+
<React.Fragment key={x.name}>
|
34 |
{x.name === Operator.DuckDuckGo && (
|
35 |
<Divider
|
36 |
style={{
|
|
|
58 |
</section>
|
59 |
</Flex>
|
60 |
</Card>
|
61 |
+
</React.Fragment>
|
62 |
);
|
63 |
})}
|
64 |
</Flex>
|
web/src/pages/flow/relevant-form/hooks.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
import { useCallback, useEffect } from 'react';
|
2 |
import { Edge } from 'reactflow';
|
3 |
import { IOperatorForm } from '../interface';
|
@@ -30,6 +31,14 @@ const getTargetOfEdge = (edges: Edge[], sourceHandle: string) =>
|
|
30 |
*/
|
31 |
export const useWatchConnectionChanges = ({ nodeId, form }: IOperatorForm) => {
|
32 |
const edges = useGraphStore((state) => state.edges);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
|
34 |
const watchConnectionChanges = useCallback(() => {
|
35 |
const edgeList = edges.filter((x) => x.source === nodeId);
|
@@ -39,6 +48,6 @@ export const useWatchConnectionChanges = ({ nodeId, form }: IOperatorForm) => {
|
|
39 |
}, [edges, nodeId, form]);
|
40 |
|
41 |
useEffect(() => {
|
42 |
-
|
43 |
-
}, [
|
44 |
};
|
|
|
1 |
+
import pick from 'lodash/pick';
|
2 |
import { useCallback, useEffect } from 'react';
|
3 |
import { Edge } from 'reactflow';
|
4 |
import { IOperatorForm } from '../interface';
|
|
|
31 |
*/
|
32 |
export const useWatchConnectionChanges = ({ nodeId, form }: IOperatorForm) => {
|
33 |
const edges = useGraphStore((state) => state.edges);
|
34 |
+
const getNode = useGraphStore((state) => state.getNode);
|
35 |
+
const node = getNode(nodeId);
|
36 |
+
|
37 |
+
const watchFormChanges = useCallback(() => {
|
38 |
+
if (node) {
|
39 |
+
form?.setFieldsValue(pick(node, ['yes', 'no']));
|
40 |
+
}
|
41 |
+
}, [node, form]);
|
42 |
|
43 |
const watchConnectionChanges = useCallback(() => {
|
44 |
const edgeList = edges.filter((x) => x.source === nodeId);
|
|
|
48 |
}, [edges, nodeId, form]);
|
49 |
|
50 |
useEffect(() => {
|
51 |
+
watchFormChanges();
|
52 |
+
}, [watchFormChanges]);
|
53 |
};
|
web/src/pages/flow/store.ts
CHANGED
@@ -38,6 +38,7 @@ export type RFState = {
|
|
38 |
getNode: (id?: string | null) => Node<NodeData> | undefined;
|
39 |
addEdge: (connection: Connection) => void;
|
40 |
getEdge: (id: string) => Edge | undefined;
|
|
|
41 |
deletePreviousEdgeOfClassificationNode: (connection: Connection) => void;
|
42 |
duplicateNode: (id: string) => void;
|
43 |
deleteEdge: () => void;
|
@@ -71,10 +72,15 @@ const useGraphStore = create<RFState>()(
|
|
71 |
});
|
72 |
},
|
73 |
onConnect: (connection: Connection) => {
|
|
|
|
|
|
|
|
|
74 |
set({
|
75 |
edges: addEdge(connection, get().edges),
|
76 |
});
|
77 |
-
|
|
|
78 |
},
|
79 |
onSelectionChange: ({ nodes, edges }: OnSelectionChangeParams) => {
|
80 |
set({
|
@@ -106,9 +112,16 @@ const useGraphStore = create<RFState>()(
|
|
106 |
getEdge: (id: string) => {
|
107 |
return get().edges.find((x) => x.id === id);
|
108 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
deletePreviousEdgeOfClassificationNode: (connection: Connection) => {
|
110 |
// Delete the edge on the classification node or relevant node anchor when the anchor is connected to other nodes
|
111 |
-
const { edges, getOperatorTypeFromId } = get();
|
112 |
// the node containing the anchor
|
113 |
const anchoredNodes = [Operator.Categorize, Operator.Relevant];
|
114 |
if (
|
@@ -123,9 +136,7 @@ const useGraphStore = create<RFState>()(
|
|
123 |
x.target !== connection.target,
|
124 |
);
|
125 |
if (previousEdge) {
|
126 |
-
|
127 |
-
edges: edges.filter((edge) => edge !== previousEdge),
|
128 |
-
});
|
129 |
}
|
130 |
}
|
131 |
},
|
@@ -155,7 +166,14 @@ const useGraphStore = create<RFState>()(
|
|
155 |
});
|
156 |
},
|
157 |
deleteEdgeById: (id: string) => {
|
158 |
-
const { edges } = get();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
set({
|
160 |
edges: edges.filter((edge) => edge.id !== id),
|
161 |
});
|
|
|
38 |
getNode: (id?: string | null) => Node<NodeData> | undefined;
|
39 |
addEdge: (connection: Connection) => void;
|
40 |
getEdge: (id: string) => Edge | undefined;
|
41 |
+
updateFormDataOnConnect: (connection: Connection) => void;
|
42 |
deletePreviousEdgeOfClassificationNode: (connection: Connection) => void;
|
43 |
duplicateNode: (id: string) => void;
|
44 |
deleteEdge: () => void;
|
|
|
72 |
});
|
73 |
},
|
74 |
onConnect: (connection: Connection) => {
|
75 |
+
const {
|
76 |
+
deletePreviousEdgeOfClassificationNode,
|
77 |
+
updateFormDataOnConnect,
|
78 |
+
} = get();
|
79 |
set({
|
80 |
edges: addEdge(connection, get().edges),
|
81 |
});
|
82 |
+
deletePreviousEdgeOfClassificationNode(connection);
|
83 |
+
updateFormDataOnConnect(connection);
|
84 |
},
|
85 |
onSelectionChange: ({ nodes, edges }: OnSelectionChangeParams) => {
|
86 |
set({
|
|
|
112 |
getEdge: (id: string) => {
|
113 |
return get().edges.find((x) => x.id === id);
|
114 |
},
|
115 |
+
updateFormDataOnConnect: (connection: Connection) => {
|
116 |
+
const { getOperatorTypeFromId, updateNodeForm } = get();
|
117 |
+
const { source, target, sourceHandle } = connection;
|
118 |
+
if (source && getOperatorTypeFromId(source) === Operator.Relevant) {
|
119 |
+
updateNodeForm(source, { [sourceHandle as string]: target });
|
120 |
+
}
|
121 |
+
},
|
122 |
deletePreviousEdgeOfClassificationNode: (connection: Connection) => {
|
123 |
// Delete the edge on the classification node or relevant node anchor when the anchor is connected to other nodes
|
124 |
+
const { edges, getOperatorTypeFromId, deleteEdgeById } = get();
|
125 |
// the node containing the anchor
|
126 |
const anchoredNodes = [Operator.Categorize, Operator.Relevant];
|
127 |
if (
|
|
|
136 |
x.target !== connection.target,
|
137 |
);
|
138 |
if (previousEdge) {
|
139 |
+
deleteEdgeById(previousEdge.id);
|
|
|
|
|
140 |
}
|
141 |
}
|
142 |
},
|
|
|
166 |
});
|
167 |
},
|
168 |
deleteEdgeById: (id: string) => {
|
169 |
+
const { edges, updateNodeForm } = get();
|
170 |
+
const currentEdge = edges.find((x) => x.id === id);
|
171 |
+
if (currentEdge) {
|
172 |
+
// After deleting the edge, set the corresponding field in the node's form field to undefined
|
173 |
+
updateNodeForm(currentEdge.source, {
|
174 |
+
[currentEdge.sourceHandle as string]: undefined,
|
175 |
+
});
|
176 |
+
}
|
177 |
set({
|
178 |
edges: edges.filter((edge) => edge.id !== id),
|
179 |
});
|