balibabu commited on
Commit
db19895
·
1 Parent(s): 06a1fe2

feat: set the edge as the data source to achieve two-way linkage betw… (#1299)

Browse files

### What problem does this PR solve?

feat: set the edge as the data source to achieve two-way linkage between
the edge and the to field. #918

### Type of change

- [x] New Feature (non-breaking change which adds functionality)

web/src/pages/flow/canvas/node/categorize-handle.tsx CHANGED
@@ -22,7 +22,8 @@ const CategorizeHandle = ({ top, right, text, idx }: IProps) => {
22
  <Handle
23
  type="source"
24
  position={Position.Right}
25
- id={`CategorizeHandle${idx}`}
 
26
  isConnectable
27
  style={{
28
  ...DEFAULT_HANDLE_STYLE,
 
22
  <Handle
23
  type="source"
24
  position={Position.Right}
25
+ // id={`CategorizeHandle${idx}`}
26
+ id={text}
27
  isConnectable
28
  style={{
29
  ...DEFAULT_HANDLE_STYLE,
web/src/pages/flow/categorize-form/dynamic-categorize.tsx CHANGED
@@ -11,10 +11,7 @@ const DynamicCategorize = ({ nodeId }: IProps) => {
11
  const updateNodeInternals = useUpdateNodeInternals();
12
  const form = Form.useFormInstance();
13
  const options = useBuildCategorizeToOptions();
14
- const { handleSelectChange } = useHandleToSelectChange(
15
- options.map((x) => x.value),
16
- nodeId,
17
- );
18
 
19
  return (
20
  <>
@@ -64,7 +61,9 @@ const DynamicCategorize = ({ nodeId }: IProps) => {
64
  <Select
65
  allowClear
66
  options={options}
67
- onChange={handleSelectChange}
 
 
68
  />
69
  </Form.Item>
70
  </Card>
 
11
  const updateNodeInternals = useUpdateNodeInternals();
12
  const form = Form.useFormInstance();
13
  const options = useBuildCategorizeToOptions();
14
+ const { handleSelectChange } = useHandleToSelectChange(nodeId);
 
 
 
15
 
16
  return (
17
  <>
 
61
  <Select
62
  allowClear
63
  options={options}
64
+ onChange={handleSelectChange(
65
+ form.getFieldValue(['items', field.name, 'name']),
66
+ )}
67
  />
68
  </Form.Item>
69
  </Card>
web/src/pages/flow/categorize-form/hooks.ts CHANGED
@@ -1,11 +1,13 @@
1
  import get from 'lodash/get';
2
  import omit from 'lodash/omit';
3
- import { useCallback, useEffect, useRef } from 'react';
 
4
  import { Operator } from '../constant';
5
  import {
6
  ICategorizeItem,
7
  ICategorizeItemResult,
8
  IOperatorForm,
 
9
  } from '../interface';
10
  import useGraphStore from '../store';
11
 
@@ -33,10 +35,18 @@ export const useBuildCategorizeToOptions = () => {
33
  */
34
  const buildCategorizeListFromObject = (
35
  categorizeItem: ICategorizeItemResult,
 
 
36
  ) => {
 
 
37
  return Object.keys(categorizeItem).reduce<Array<ICategorizeItem>>(
38
  (pre, cur) => {
39
- pre.push({ name: cur, ...categorizeItem[cur] });
 
 
 
 
40
  return pre;
41
  },
42
  [],
@@ -70,6 +80,8 @@ export const useHandleFormValuesChange = ({
70
  form,
71
  node,
72
  }: IOperatorForm) => {
 
 
73
  const handleValuesChange = useCallback(
74
  (changedValues: any, values: any) => {
75
  console.info(changedValues, values);
@@ -85,43 +97,29 @@ export const useHandleFormValuesChange = ({
85
  form?.setFieldsValue({
86
  items: buildCategorizeListFromObject(
87
  get(node, 'data.form.category_description', {}),
 
 
88
  ),
89
  });
90
- }, [form, node]);
91
 
92
  return { handleValuesChange };
93
  };
94
 
95
- export const useHandleToSelectChange = (
96
- opstionIds: string[],
97
- nodeId?: string,
98
- ) => {
99
- // const [previousTarget, setPreviousTarget] = useState('');
100
- const previousTarget = useRef('');
101
- const { addEdge, deleteEdgeBySourceAndTarget } = useGraphStore(
102
- (state) => state,
103
- );
104
  const handleSelectChange = useCallback(
105
- (value?: string) => {
106
- if (nodeId) {
107
- if (previousTarget.current) {
108
- // delete previous edge
109
- deleteEdgeBySourceAndTarget(nodeId, previousTarget.current);
110
- }
111
- if (value) {
112
- addEdge({
113
- source: nodeId,
114
- target: value,
115
- sourceHandle: 'b',
116
- targetHandle: 'd',
117
- });
118
- } else {
119
- // if the value is empty, delete the edges between the current node and all nodes in the drop-down box.
120
- }
121
- previousTarget.current = value;
122
  }
123
  },
124
- [addEdge, nodeId, deleteEdgeBySourceAndTarget],
125
  );
126
 
127
  return { handleSelectChange };
 
1
  import get from 'lodash/get';
2
  import omit from 'lodash/omit';
3
+ import { useCallback, useEffect } from 'react';
4
+ import { Edge, Node } from 'reactflow';
5
  import { Operator } from '../constant';
6
  import {
7
  ICategorizeItem,
8
  ICategorizeItemResult,
9
  IOperatorForm,
10
+ NodeData,
11
  } from '../interface';
12
  import useGraphStore from '../store';
13
 
 
35
  */
36
  const buildCategorizeListFromObject = (
37
  categorizeItem: ICategorizeItemResult,
38
+ edges: Edge[],
39
+ node?: Node<NodeData>,
40
  ) => {
41
+ // Categorize's to field has two data sources, with edges as the data source.
42
+ // Changes in the edge or to field need to be synchronized to the form field.
43
  return Object.keys(categorizeItem).reduce<Array<ICategorizeItem>>(
44
  (pre, cur) => {
45
+ // synchronize edge data to the to field
46
+ const edge = edges.find(
47
+ (x) => x.source === node?.id && x.sourceHandle === cur,
48
+ );
49
+ pre.push({ name: cur, ...categorizeItem[cur], to: edge?.target });
50
  return pre;
51
  },
52
  [],
 
80
  form,
81
  node,
82
  }: IOperatorForm) => {
83
+ const edges = useGraphStore((state) => state.edges);
84
+
85
  const handleValuesChange = useCallback(
86
  (changedValues: any, values: any) => {
87
  console.info(changedValues, values);
 
97
  form?.setFieldsValue({
98
  items: buildCategorizeListFromObject(
99
  get(node, 'data.form.category_description', {}),
100
+ edges,
101
+ node,
102
  ),
103
  });
104
+ }, [form, node, edges]);
105
 
106
  return { handleValuesChange };
107
  };
108
 
109
+ export const useHandleToSelectChange = (nodeId?: string) => {
110
+ const { addEdge } = useGraphStore((state) => state);
 
 
 
 
 
 
 
111
  const handleSelectChange = useCallback(
112
+ (name?: string) => (value?: string) => {
113
+ if (nodeId && value && name) {
114
+ addEdge({
115
+ source: nodeId,
116
+ target: value,
117
+ sourceHandle: name,
118
+ targetHandle: null,
119
+ });
 
 
 
 
 
 
 
 
 
120
  }
121
  },
122
+ [addEdge, nodeId],
123
  );
124
 
125
  return { handleSelectChange };
web/src/pages/flow/hooks.ts CHANGED
@@ -169,7 +169,7 @@ export const useWatchGraphChange = () => {
169
  const edges = useGraphStore((state) => state.edges);
170
  useDebounceEffect(
171
  () => {
172
- console.info('useDebounceEffect');
173
  },
174
  [nodes, edges],
175
  {
 
169
  const edges = useGraphStore((state) => state.edges);
170
  useDebounceEffect(
171
  () => {
172
+ // console.info('useDebounceEffect');
173
  },
174
  [nodes, edges],
175
  {
web/src/pages/flow/store.ts CHANGED
@@ -1,5 +1,6 @@
1
  import type {} from '@redux-devtools/extension';
2
  import { humanId } from 'human-id';
 
3
  import {
4
  Connection,
5
  Edge,
@@ -36,6 +37,7 @@ export type RFState = {
36
  addNode: (nodes: Node) => void;
37
  getNode: (id: string) => Node | undefined;
38
  addEdge: (connection: Connection) => void;
 
39
  deletePreviousEdgeOfClassificationNode: (connection: Connection) => void;
40
  duplicateNode: (id: string) => void;
41
  deleteEdge: () => void;
@@ -43,7 +45,7 @@ export type RFState = {
43
  deleteNodeById: (id: string) => void;
44
  deleteEdgeBySourceAndTarget: (source: string, target: string) => void;
45
  findNodeByName: (operatorName: Operator) => Node | undefined;
46
- findNodeById: (id: string) => Node | undefined;
47
  };
48
 
49
  // this is our useStore hook that we can use in our components to get parts of the store and call actions
@@ -92,6 +94,10 @@ const useGraphStore = create<RFState>()(
92
  set({
93
  edges: addEdge(connection, get().edges),
94
  });
 
 
 
 
95
  },
96
  deletePreviousEdgeOfClassificationNode: (connection: Connection) => {
97
  // Delete the edge on the classification node anchor when the anchor is connected to other nodes
@@ -164,9 +170,6 @@ const useGraphStore = create<RFState>()(
164
  findNodeByName: (name: Operator) => {
165
  return get().nodes.find((x) => x.data.label === name);
166
  },
167
- findNodeById: (id: string) => {
168
- return get().nodes.find((x) => x.id === id);
169
- },
170
  updateNodeForm: (nodeId: string, values: any) => {
171
  set({
172
  nodes: get().nodes.map((node) => {
@@ -178,6 +181,13 @@ const useGraphStore = create<RFState>()(
178
  }),
179
  });
180
  },
 
 
 
 
 
 
 
181
  }),
182
  { name: 'graph' },
183
  ),
 
1
  import type {} from '@redux-devtools/extension';
2
  import { humanId } from 'human-id';
3
+ import lodashSet from 'lodash/set';
4
  import {
5
  Connection,
6
  Edge,
 
37
  addNode: (nodes: Node) => void;
38
  getNode: (id: string) => Node | 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;
 
45
  deleteNodeById: (id: string) => void;
46
  deleteEdgeBySourceAndTarget: (source: string, target: string) => void;
47
  findNodeByName: (operatorName: Operator) => Node | undefined;
48
+ updateMutableNodeFormItem: (id: string, field: string, value: any) => void;
49
  };
50
 
51
  // this is our useStore hook that we can use in our components to get parts of the store and call actions
 
94
  set({
95
  edges: addEdge(connection, get().edges),
96
  });
97
+ get().deletePreviousEdgeOfClassificationNode(connection);
98
+ },
99
+ getEdge: (id: string) => {
100
+ return get().edges.find((x) => x.id === id);
101
  },
102
  deletePreviousEdgeOfClassificationNode: (connection: Connection) => {
103
  // Delete the edge on the classification node anchor when the anchor is connected to other nodes
 
170
  findNodeByName: (name: Operator) => {
171
  return get().nodes.find((x) => x.data.label === name);
172
  },
 
 
 
173
  updateNodeForm: (nodeId: string, values: any) => {
174
  set({
175
  nodes: get().nodes.map((node) => {
 
181
  }),
182
  });
183
  },
184
+ updateMutableNodeFormItem: (id: string, field: string, value: any) => {
185
+ const { nodes } = get();
186
+ const idx = nodes.findIndex((x) => x.id === id);
187
+ if (idx) {
188
+ lodashSet(nodes, [idx, 'data', 'form', field], value);
189
+ }
190
+ },
191
  }),
192
  { name: 'graph' },
193
  ),