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
- watchConnectionChanges();
43
- }, [watchConnectionChanges]);
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
- get().deletePreviousEdgeOfClassificationNode(connection);
 
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
- set({
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
  });