balibabu commited on
Commit
2653e84
·
1 Parent(s): 0442b90

feat: modify the name of an operator #918 (#1333)

Browse files

### What problem does this PR solve?

feat: modify the name of an operator #918

### Type of change


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

web/src/pages/flow/answer-form/index.tsx CHANGED
@@ -1,5 +1,5 @@
1
  const AnswerForm = () => {
2
- return <div>AnswerForm</div>;
3
  };
4
 
5
  export default AnswerForm;
 
1
  const AnswerForm = () => {
2
+ return <div></div>;
3
  };
4
 
5
  export default AnswerForm;
web/src/pages/flow/canvas/node/begin-node.tsx CHANGED
@@ -32,7 +32,7 @@ export function BeginNode({ id, data, selected }: NodeProps<NodeData>) {
32
  </Space>
33
  </Flex>
34
  <section className={styles.bottomBox}>
35
- <div className={styles.nodeName}>{id}</div>
36
  </section>
37
  </section>
38
  );
 
32
  </Space>
33
  </Flex>
34
  <section className={styles.bottomBox}>
35
+ <div className={styles.nodeName}>{data.name}</div>
36
  </section>
37
  </section>
38
  );
web/src/pages/flow/canvas/node/categorize-node.tsx CHANGED
@@ -59,7 +59,7 @@ export function CategorizeNode({ id, data, selected }: NodeProps<NodeData>) {
59
  </Space>
60
  </Flex>
61
  <section className={styles.bottomBox}>
62
- <div className={styles.nodeName}>{id}</div>
63
  </section>
64
  </section>
65
  );
 
59
  </Space>
60
  </Flex>
61
  <section className={styles.bottomBox}>
62
+ <div className={styles.nodeName}>{data.name}</div>
63
  </section>
64
  </section>
65
  );
web/src/pages/flow/canvas/node/index.tsx CHANGED
@@ -62,7 +62,7 @@ export function RagNode({
62
  </Flex>
63
 
64
  <section className={styles.bottomBox}>
65
- <div className={styles.nodeName}>{id}</div>
66
  </section>
67
  </section>
68
  );
 
62
  </Flex>
63
 
64
  <section className={styles.bottomBox}>
65
+ <div className={styles.nodeName}>{data.name}</div>
66
  </section>
67
  </section>
68
  );
web/src/pages/flow/categorize-form/dynamic-categorize.tsx CHANGED
@@ -42,7 +42,7 @@ const DynamicCategorize = ({ nodeId }: IProps) => {
42
  }
43
  >
44
  <Form.Item
45
- label={t('name')}
46
  name={[field.name, 'name']}
47
  rules={[{ required: true, message: t('nameMessage') }]}
48
  >
 
42
  }
43
  >
44
  <Form.Item
45
+ label={t('name')} // TODO: repeatability check
46
  name={[field.name, 'name']}
47
  rules={[{ required: true, message: t('nameMessage') }]}
48
  >
web/src/pages/flow/categorize-form/hooks.ts CHANGED
@@ -25,7 +25,7 @@ export const useBuildCategorizeToOptions = () => {
25
  excludedNodes.every((y) => y !== x.data.label) &&
26
  !toList.some((y) => y === x.id), // filter out selected values ​​in other to fields from the current drop-down box options
27
  )
28
- .map((x) => ({ label: x.id, value: x.id }));
29
  },
30
  [nodes],
31
  );
 
25
  excludedNodes.every((y) => y !== x.data.label) &&
26
  !toList.some((y) => y === x.id), // filter out selected values ​​in other to fields from the current drop-down box options
27
  )
28
+ .map((x) => ({ label: x.data.name, value: x.id }));
29
  },
30
  [nodes],
31
  );
web/src/pages/flow/flow-drawer/index.tsx CHANGED
@@ -1,5 +1,5 @@
1
  import { IModalProps } from '@/interfaces/common';
2
- import { Drawer, Form } from 'antd';
3
  import { useEffect } from 'react';
4
  import { Node } from 'reactflow';
5
  import AnswerForm from '../answer-form';
@@ -7,7 +7,7 @@ import BeginForm from '../begin-form';
7
  import CategorizeForm from '../categorize-form';
8
  import { Operator } from '../constant';
9
  import GenerateForm from '../generate-form';
10
- import { useHandleFormValuesChange } from '../hooks';
11
  import MessageForm from '../message-form';
12
  import RelevantForm from '../relevant-form';
13
  import RetrievalForm from '../retrieval-form';
@@ -36,6 +36,8 @@ const FlowDrawer = ({
36
  const operatorName: Operator = node?.data.label;
37
  const OperatorForm = FormMap[operatorName];
38
  const [form] = Form.useForm();
 
 
39
 
40
  const { handleValuesChange } = useHandleFormValuesChange(node?.id);
41
 
@@ -47,7 +49,13 @@ const FlowDrawer = ({
47
 
48
  return (
49
  <Drawer
50
- title={node?.data.label}
 
 
 
 
 
 
51
  placement="right"
52
  onClose={hideModal}
53
  open={visible}
 
1
  import { IModalProps } from '@/interfaces/common';
2
+ import { Drawer, Form, Input } from 'antd';
3
  import { useEffect } from 'react';
4
  import { Node } from 'reactflow';
5
  import AnswerForm from '../answer-form';
 
7
  import CategorizeForm from '../categorize-form';
8
  import { Operator } from '../constant';
9
  import GenerateForm from '../generate-form';
10
+ import { useHandleFormValuesChange, useHandleNodeNameChange } from '../hooks';
11
  import MessageForm from '../message-form';
12
  import RelevantForm from '../relevant-form';
13
  import RetrievalForm from '../retrieval-form';
 
36
  const operatorName: Operator = node?.data.label;
37
  const OperatorForm = FormMap[operatorName];
38
  const [form] = Form.useForm();
39
+ const { name, handleNameBlur, handleNameChange } =
40
+ useHandleNodeNameChange(node);
41
 
42
  const { handleValuesChange } = useHandleFormValuesChange(node?.id);
43
 
 
49
 
50
  return (
51
  <Drawer
52
+ title={
53
+ <Input
54
+ value={name}
55
+ onBlur={handleNameBlur}
56
+ onChange={handleNameChange}
57
+ ></Input>
58
+ }
59
  placement="right"
60
  onClose={hideModal}
61
  open={visible}
web/src/pages/flow/headhunter_zh.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "edges": [
3
  {
4
- "id": "f42b5218-8052-4eb5-9cec-2dd302ad478a",
5
  "label": "",
6
  "source": "begin",
7
  "target": "answer:0",
@@ -10,7 +10,7 @@
10
  }
11
  },
12
  {
13
- "id": "84c024e1-a96f-438c-905f-63ef725b0442",
14
  "label": "",
15
  "source": "message:reject",
16
  "target": "answer:0",
@@ -19,7 +19,7 @@
19
  }
20
  },
21
  {
22
- "id": "04b4bf3c-1f49-4cd8-9b93-779c9d8aa86c",
23
  "label": "",
24
  "source": "answer:0",
25
  "target": "categorize:0",
@@ -28,7 +28,7 @@
28
  }
29
  },
30
  {
31
- "id": "0c1ac8d3-9a45-44b1-92e1-f7e3f1b3be9b",
32
  "label": "",
33
  "source": "categorize:0",
34
  "target": "message:introduction",
@@ -38,7 +38,7 @@
38
  "sourceHandle": "interested"
39
  },
40
  {
41
- "id": "309d9f73-f125-44aa-be84-e716dffb4af1",
42
  "label": "",
43
  "source": "categorize:0",
44
  "target": "generate:casual",
@@ -48,7 +48,7 @@
48
  "sourceHandle": "casual"
49
  },
50
  {
51
- "id": "d8f39ec9-b993-42c7-aa88-e86192c8ee14",
52
  "label": "",
53
  "source": "categorize:0",
54
  "target": "message:reject",
@@ -58,7 +58,7 @@
58
  "sourceHandle": "answer"
59
  },
60
  {
61
- "id": "34047c0a-6c50-4cf7-a2e6-d1a8cd9b269b",
62
  "label": "",
63
  "source": "categorize:0",
64
  "target": "retrieval:0",
@@ -68,7 +68,7 @@
68
  "sourceHandle": "about_job"
69
  },
70
  {
71
- "id": "0613a366-8476-44a5-8b6c-874007de7d5c",
72
  "label": "",
73
  "source": "message:introduction",
74
  "target": "answer:1",
@@ -77,7 +77,7 @@
77
  }
78
  },
79
  {
80
- "id": "b14d80a7-3e63-4ba4-bfb2-80ad3a1b5980",
81
  "label": "",
82
  "source": "generate:aboutJob",
83
  "target": "answer:1",
@@ -86,7 +86,7 @@
86
  }
87
  },
88
  {
89
- "id": "6126fd77-f407-4ce5-966b-62cb18011343",
90
  "label": "",
91
  "source": "generate:casual",
92
  "target": "answer:1",
@@ -95,7 +95,7 @@
95
  }
96
  },
97
  {
98
- "id": "24c6cc93-7f0d-4fae-a54d-a2a79336f58e",
99
  "label": "",
100
  "source": "generate:get_wechat",
101
  "target": "answer:1",
@@ -104,7 +104,7 @@
104
  }
105
  },
106
  {
107
- "id": "f09d9bf3-d64c-4a23-a415-c53179e7366f",
108
  "label": "",
109
  "source": "generate:nowechat",
110
  "target": "answer:1",
@@ -113,7 +113,7 @@
113
  }
114
  },
115
  {
116
- "id": "cd55cf28-ddac-476e-a73e-d6c0d54f62d2",
117
  "label": "",
118
  "source": "answer:1",
119
  "target": "categorize:1",
@@ -122,7 +122,7 @@
122
  }
123
  },
124
  {
125
- "id": "69ad4e49-c538-4406-900c-352644fde6b9",
126
  "label": "",
127
  "source": "categorize:1",
128
  "target": "retrieval:0",
@@ -132,7 +132,7 @@
132
  "sourceHandle": "about_job"
133
  },
134
  {
135
- "id": "999c5601-e69d-4a35-a15e-474546babe64",
136
  "label": "",
137
  "source": "categorize:1",
138
  "target": "generate:casual",
@@ -142,7 +142,7 @@
142
  "sourceHandle": "casual"
143
  },
144
  {
145
- "id": "9debb81c-9b74-4e51-a6ae-a2f0188b781b",
146
  "label": "",
147
  "source": "categorize:1",
148
  "target": "generate:get_wechat",
@@ -152,7 +152,7 @@
152
  "sourceHandle": "wechat"
153
  },
154
  {
155
- "id": "95e183eb-d114-4ad4-946b-3fb2d3df340c",
156
  "label": "",
157
  "source": "categorize:1",
158
  "target": "generate:nowechat",
@@ -162,7 +162,7 @@
162
  "sourceHandle": "giveup"
163
  },
164
  {
165
- "id": "c59c1a4b-18ed-4a74-bbef-fa961a51d6a4",
166
  "label": "",
167
  "source": "retrieval:0",
168
  "target": "generate:aboutJob",
@@ -171,7 +171,7 @@
171
  }
172
  },
173
  {
174
- "id": "aa902165-fe39-4cc4-8220-1abcf37b9f12",
175
  "label": "",
176
  "source": "relevant:0",
177
  "target": "generate:aboutJob",
@@ -190,6 +190,7 @@
190
  },
191
  "data": {
192
  "label": "Begin",
 
193
  "form": {
194
  "prologue": "您好!我是AGI方向的猎头,了解到您是这方面的大佬,然后冒昧的就联系到您。这边有个机会想和您分享,RAGFlow正在招聘您这个岗位的资深的工程师不知道您那边是不是感兴趣?"
195
  }
@@ -206,6 +207,7 @@
206
  },
207
  "data": {
208
  "label": "Answer",
 
209
  "form": {}
210
  },
211
  "sourcePosition": "left",
@@ -220,6 +222,7 @@
220
  },
221
  "data": {
222
  "label": "Categorize",
 
223
  "form": {
224
  "llm_id": "deepseek-chat",
225
  "category_description": {
@@ -258,6 +261,7 @@
258
  },
259
  "data": {
260
  "label": "Message",
 
261
  "form": {
262
  "messages": [
263
  "我简单介绍以下:\nRAGFlow 是一款基于深度文档理解构建的开源 RAG(Retrieval-Augmented Generation)引擎。RAGFlow 可以为各种规模的企业及个人提供一套精简的 RAG 工作流程,结合大语言模型(LLM)针对用户各类不同的复杂格式数据提供可靠的问答以及有理有据的引用。https://github.com/infiniflow/ragflow\n您那边还有什么要了解的?"
@@ -276,6 +280,7 @@
276
  },
277
  "data": {
278
  "label": "Answer",
 
279
  "form": {}
280
  },
281
  "sourcePosition": "left",
@@ -290,6 +295,7 @@
290
  },
291
  "data": {
292
  "label": "Categorize",
 
293
  "form": {
294
  "llm_id": "deepseek-chat",
295
  "category_description": {
@@ -329,6 +335,7 @@
329
  },
330
  "data": {
331
  "label": "Generate",
 
332
  "form": {
333
  "llm_id": "deepseek-chat",
334
  "prompt": "你是AGI方向的猎头,现在候选人的聊了和职位无关的话题,请耐心的回应候选人,并将话题往该AGI的职位上带,最好能要到候选人微信号以便后面保持联系。",
@@ -349,6 +356,7 @@
349
  },
350
  "data": {
351
  "label": "Retrieval",
 
352
  "form": {
353
  "similarity_threshold": 0.2,
354
  "keywords_similarity_weight": 0.3,
@@ -370,6 +378,7 @@
370
  },
371
  "data": {
372
  "label": "Generate",
 
373
  "form": {
374
  "llm_id": "deepseek-chat",
375
  "prompt": "你是AGI方向的猎头,候选人问了有关职位或公司的问题,你根据以下职位信息回答。如果职位信息中不包含候选人的问题就回答不清楚、不知道、有待确认等。回答完后引导候选人加微信号,如:\n - 方便加一下微信吗,我把JD发您看看?\n - 微信号多少,我把详细职位JD发您?\n 职位信息如下:\n {input}\n 职位信息如上。",
@@ -388,6 +397,7 @@
388
  },
389
  "data": {
390
  "label": "Generate",
 
391
  "form": {
392
  "llm_id": "deepseek-chat",
393
  "prompt": "你是AGI方向的猎头,候选人表示不反感加微信,如果对方已经报了微信号,表示感谢和信任并表示马上会加上;如果没有,则问对方微信号多少。你的微信号是weixin_kevin,E-mail是[email protected]。说话不要重复。不要总是您好。",
@@ -408,6 +418,7 @@
408
  },
409
  "data": {
410
  "label": "Generate",
 
411
  "form": {
412
  "llm_id": "deepseek-chat",
413
  "prompt": "你是AGI方向的猎头,当你提出加微信时对方表示拒绝。你需要耐心礼貌的回应候选人,表示对于保护隐私信息给予理解,也可以询问他对该职位的看法和顾虑。并在恰当的时机再次询问微信联系方式。也可以鼓励候选人主动与你取得联系。你的微信号是weixin_kevin,E-mail是[email protected]。说话不要重复。不要总是您好。",
@@ -428,6 +439,7 @@
428
  },
429
  "data": {
430
  "label": "Message",
 
431
  "form": {
432
  "messages": [
433
  "好的,祝您生活愉快,工作顺利。",
 
1
  {
2
  "edges": [
3
  {
4
+ "id": "1542fe3d-d13d-4e14-a253-c06cdf72e357",
5
  "label": "",
6
  "source": "begin",
7
  "target": "answer:0",
 
10
  }
11
  },
12
  {
13
+ "id": "e0c46945-b60a-4da9-9a35-5dd654469e47",
14
  "label": "",
15
  "source": "message:reject",
16
  "target": "answer:0",
 
19
  }
20
  },
21
  {
22
+ "id": "5806636c-2bba-4c14-922e-3ef905c37f52",
23
  "label": "",
24
  "source": "answer:0",
25
  "target": "categorize:0",
 
28
  }
29
  },
30
  {
31
+ "id": "ebce1598-cd0c-4863-a8b1-2f8a1de28040",
32
  "label": "",
33
  "source": "categorize:0",
34
  "target": "message:introduction",
 
38
  "sourceHandle": "interested"
39
  },
40
  {
41
+ "id": "1e560fed-76f9-494b-a028-cd871acdee07",
42
  "label": "",
43
  "source": "categorize:0",
44
  "target": "generate:casual",
 
48
  "sourceHandle": "casual"
49
  },
50
  {
51
+ "id": "5aa430cc-19c4-4f82-9fed-5649651fff11",
52
  "label": "",
53
  "source": "categorize:0",
54
  "target": "message:reject",
 
58
  "sourceHandle": "answer"
59
  },
60
  {
61
+ "id": "c40b1dab-5f42-425f-9207-27e261d6b70f",
62
  "label": "",
63
  "source": "categorize:0",
64
  "target": "retrieval:0",
 
68
  "sourceHandle": "about_job"
69
  },
70
  {
71
+ "id": "7216138f-cdc0-4992-851e-30916033d520",
72
  "label": "",
73
  "source": "message:introduction",
74
  "target": "answer:1",
 
77
  }
78
  },
79
  {
80
+ "id": "3bb8ada2-b1ac-49cc-81bf-78ffb2c07d94",
81
  "label": "",
82
  "source": "generate:aboutJob",
83
  "target": "answer:1",
 
86
  }
87
  },
88
  {
89
+ "id": "d60c4c33-ddd2-40ff-af62-aabb11e6a91c",
90
  "label": "",
91
  "source": "generate:casual",
92
  "target": "answer:1",
 
95
  }
96
  },
97
  {
98
+ "id": "f425b2ec-fe5b-44d9-b5f3-c2953e12b600",
99
  "label": "",
100
  "source": "generate:get_wechat",
101
  "target": "answer:1",
 
104
  }
105
  },
106
  {
107
+ "id": "ebf55d7f-36bf-43ba-9166-34d8a4a68474",
108
  "label": "",
109
  "source": "generate:nowechat",
110
  "target": "answer:1",
 
113
  }
114
  },
115
  {
116
+ "id": "8897e8ed-12b7-4ca4-a63b-7a5a702a1517",
117
  "label": "",
118
  "source": "answer:1",
119
  "target": "categorize:1",
 
122
  }
123
  },
124
  {
125
+ "id": "a0d646e9-6ef9-490d-9308-830c51b8a663",
126
  "label": "",
127
  "source": "categorize:1",
128
  "target": "retrieval:0",
 
132
  "sourceHandle": "about_job"
133
  },
134
  {
135
+ "id": "6a0714f7-806f-49f4-bc36-210025e48f49",
136
  "label": "",
137
  "source": "categorize:1",
138
  "target": "generate:casual",
 
142
  "sourceHandle": "casual"
143
  },
144
  {
145
+ "id": "9267def3-9b81-4f50-87da-0eef85b4fe90",
146
  "label": "",
147
  "source": "categorize:1",
148
  "target": "generate:get_wechat",
 
152
  "sourceHandle": "wechat"
153
  },
154
  {
155
+ "id": "d8bfe795-36e7-4172-9dfe-649ad37be4d8",
156
  "label": "",
157
  "source": "categorize:1",
158
  "target": "generate:nowechat",
 
162
  "sourceHandle": "giveup"
163
  },
164
  {
165
+ "id": "94c5e5c5-3b35-412d-a6cb-4ed5f883fef2",
166
  "label": "",
167
  "source": "retrieval:0",
168
  "target": "generate:aboutJob",
 
171
  }
172
  },
173
  {
174
+ "id": "17da25cc-09c5-4a5e-ad27-2c6593f8fff5",
175
  "label": "",
176
  "source": "relevant:0",
177
  "target": "generate:aboutJob",
 
190
  },
191
  "data": {
192
  "label": "Begin",
193
+ "name": "OliveGuestsPlay",
194
  "form": {
195
  "prologue": "您好!我是AGI方向的猎头,了解到您是这方面的大佬,然后冒昧的就联系到您。这边有个机会想和您分享,RAGFlow正在招聘您这个岗位的资深的工程师不知道您那边是不是感兴趣?"
196
  }
 
207
  },
208
  "data": {
209
  "label": "Answer",
210
+ "name": "SolidRatsBurn",
211
  "form": {}
212
  },
213
  "sourcePosition": "left",
 
222
  },
223
  "data": {
224
  "label": "Categorize",
225
+ "name": "ShyHousesAccept",
226
  "form": {
227
  "llm_id": "deepseek-chat",
228
  "category_description": {
 
261
  },
262
  "data": {
263
  "label": "Message",
264
+ "name": "ThreeRegionsGrow",
265
  "form": {
266
  "messages": [
267
  "我简单介绍以下:\nRAGFlow 是一款基于深度文档理解构建的开源 RAG(Retrieval-Augmented Generation)引擎。RAGFlow 可以为各种规模的企业及个人提供一套精简的 RAG 工作流程,结合大语言模型(LLM)针对用户各类不同的复杂格式数据提供可靠的问答以及有理有据的引用。https://github.com/infiniflow/ragflow\n您那边还有什么要了解的?"
 
280
  },
281
  "data": {
282
  "label": "Answer",
283
+ "name": "FancyChickenCut",
284
  "form": {}
285
  },
286
  "sourcePosition": "left",
 
295
  },
296
  "data": {
297
  "label": "Categorize",
298
+ "name": "DeepAreasGrow",
299
  "form": {
300
  "llm_id": "deepseek-chat",
301
  "category_description": {
 
335
  },
336
  "data": {
337
  "label": "Generate",
338
+ "name": "TinyOlivesMelt",
339
  "form": {
340
  "llm_id": "deepseek-chat",
341
  "prompt": "你是AGI方向的猎头,现在候选人的聊了和职位无关的话题,请耐心的回应候选人,并将话题往该AGI的职位上带,最好能要到候选人微信号以便后面保持联系。",
 
356
  },
357
  "data": {
358
  "label": "Retrieval",
359
+ "name": "SlimyDonkeysHug",
360
  "form": {
361
  "similarity_threshold": 0.2,
362
  "keywords_similarity_weight": 0.3,
 
378
  },
379
  "data": {
380
  "label": "Generate",
381
+ "name": "PetiteHoundsMove",
382
  "form": {
383
  "llm_id": "deepseek-chat",
384
  "prompt": "你是AGI方向的猎头,候选人问了有关职位或公司的问题,你根据以下职位信息回答。如果职位信息中不包含候选人的问题就回答不清楚、不知道、有待确认等。回答完后引导候选人加微信号,如:\n - 方便加一下微信吗,我把JD发您看看?\n - 微信号多少,我把详细职位JD发您?\n 职位信息如下:\n {input}\n 职位信息如上。",
 
397
  },
398
  "data": {
399
  "label": "Generate",
400
+ "name": "EagerSteaksWin",
401
  "form": {
402
  "llm_id": "deepseek-chat",
403
  "prompt": "你是AGI方向的猎头,候选人表示不反感加微信,如果对方已经报了微信号,表示感谢和信任并表示马上会加上;如果没有,则问对方微信号多少。你的微信号是weixin_kevin,E-mail是[email protected]。说话不要重复。不要总是您好。",
 
418
  },
419
  "data": {
420
  "label": "Generate",
421
+ "name": "IcyAntsBet",
422
  "form": {
423
  "llm_id": "deepseek-chat",
424
  "prompt": "你是AGI方向的猎头,当你提出加微信时对方表示拒绝。你需要耐心礼貌的回应候选人,表示对于保护隐私信息给予理解,也可以询问他对该职位的看法和顾虑。并在恰当的时机再次询问微信联系方式。也可以鼓励候选人主动与你取得联系。你的微信号是weixin_kevin,E-mail是[email protected]。说话不要重复。不要总是您好。",
 
439
  },
440
  "data": {
441
  "label": "Message",
442
+ "name": "SmallCarsRoll",
443
  "form": {
444
  "messages": [
445
  "好的,祝您生活愉快,工作顺利。",
web/src/pages/flow/hooks.ts CHANGED
@@ -8,6 +8,7 @@ import { useFetchLlmList } from '@/hooks/llmHooks';
8
  import { IGraph } from '@/interfaces/database/flow';
9
  import { useIsFetching } from '@tanstack/react-query';
10
  import React, {
 
11
  KeyboardEventHandler,
12
  useCallback,
13
  useEffect,
@@ -22,8 +23,9 @@ import {
22
  } from '@/constants/knowledge';
23
  import { Variable } from '@/interfaces/database/chat';
24
  import { useDebounceEffect } from 'ahooks';
25
- import { FormInstance } from 'antd';
26
  import { humanId } from 'human-id';
 
27
  import { useParams } from 'umi';
28
  import { NodeMap, Operator, RestrictedUpstreamMap } from './constant';
29
  import useGraphStore, { RFState } from './store';
@@ -108,7 +110,11 @@ export const useHandleDrop = () => {
108
  };
109
 
110
  export const useShowDrawer = () => {
111
- const [clickedNode, setClickedNode] = useState<Node>();
 
 
 
 
112
  const {
113
  visible: drawerVisible,
114
  hideModal: hideDrawer,
@@ -117,19 +123,17 @@ export const useShowDrawer = () => {
117
 
118
  const handleShow = useCallback(
119
  (node: Node) => {
120
- setClickedNode(node);
121
- if (node.data.label !== Operator.Answer) {
122
- showDrawer();
123
- }
124
  },
125
- [showDrawer],
126
  );
127
 
128
  return {
129
  drawerVisible,
130
  hideDrawer,
131
  showDrawer: handleShow,
132
- clickedNode,
133
  };
134
  };
135
 
@@ -270,3 +274,35 @@ export const useValidateConnection = () => {
270
 
271
  return isValidConnection;
272
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  import { IGraph } from '@/interfaces/database/flow';
9
  import { useIsFetching } from '@tanstack/react-query';
10
  import React, {
11
+ ChangeEvent,
12
  KeyboardEventHandler,
13
  useCallback,
14
  useEffect,
 
23
  } from '@/constants/knowledge';
24
  import { Variable } from '@/interfaces/database/chat';
25
  import { useDebounceEffect } from 'ahooks';
26
+ import { FormInstance, message } from 'antd';
27
  import { humanId } from 'human-id';
28
+ import trim from 'lodash/trim';
29
  import { useParams } from 'umi';
30
  import { NodeMap, Operator, RestrictedUpstreamMap } from './constant';
31
  import useGraphStore, { RFState } from './store';
 
110
  };
111
 
112
  export const useShowDrawer = () => {
113
+ const {
114
+ clickedNodeId: clickNodeId,
115
+ setClickedNodeId,
116
+ getNode,
117
+ } = useGraphStore((state) => state);
118
  const {
119
  visible: drawerVisible,
120
  hideModal: hideDrawer,
 
123
 
124
  const handleShow = useCallback(
125
  (node: Node) => {
126
+ setClickedNodeId(node.id);
127
+ showDrawer();
 
 
128
  },
129
+ [showDrawer, setClickedNodeId],
130
  );
131
 
132
  return {
133
  drawerVisible,
134
  hideDrawer,
135
  showDrawer: handleShow,
136
+ clickedNode: getNode(clickNodeId),
137
  };
138
  };
139
 
 
274
 
275
  return isValidConnection;
276
  };
277
+
278
+ export const useHandleNodeNameChange = (node?: Node) => {
279
+ const [name, setName] = useState<string>('');
280
+ const { updateNodeName, nodes } = useGraphStore((state) => state);
281
+ const previousName = node?.data.name;
282
+ const id = node?.id;
283
+
284
+ const handleNameBlur = useCallback(() => {
285
+ const existsSameName = nodes.some((x) => x.data.name === name);
286
+ if (trim(name) === '' || existsSameName) {
287
+ if (existsSameName && previousName !== name) {
288
+ message.error('The name cannot be repeated');
289
+ }
290
+ setName(previousName);
291
+ return;
292
+ }
293
+
294
+ if (id) {
295
+ updateNodeName(id, name);
296
+ }
297
+ }, [name, id, updateNodeName, previousName, nodes]);
298
+
299
+ const handleNameChange = useCallback((e: ChangeEvent<any>) => {
300
+ setName(e.target.value);
301
+ }, []);
302
+
303
+ useEffect(() => {
304
+ setName(previousName);
305
+ }, [previousName]);
306
+
307
+ return { name, handleNameBlur, handleNameChange };
308
+ };
web/src/pages/flow/interface.ts CHANGED
@@ -54,7 +54,8 @@ export interface ICategorizeForm extends IGenerateForm {
54
  }
55
 
56
  export type NodeData = {
57
- label: string;
 
58
  color: string;
59
  form: IBeginForm | IRetrievalForm | IGenerateForm | ICategorizeForm;
60
  };
 
54
  }
55
 
56
  export type NodeData = {
57
+ label: string; // operator type
58
+ name: string; // operator name
59
  color: string;
60
  form: IBeginForm | IRetrievalForm | IGenerateForm | ICategorizeForm;
61
  };
web/src/pages/flow/mock.tsx CHANGED
@@ -45,6 +45,7 @@ export const dsl = {
45
  },
46
  data: {
47
  label: 'Begin',
 
48
  },
49
  sourcePosition: 'left',
50
  targetPosition: 'right',
 
45
  },
46
  data: {
47
  label: 'Begin',
48
+ name: 'begin',
49
  },
50
  sourcePosition: 'left',
51
  targetPosition: 'right',
web/src/pages/flow/store.ts CHANGED
@@ -26,6 +26,7 @@ export type RFState = {
26
  edges: Edge[];
27
  selectedNodeIds: string[];
28
  selectedEdgeIds: string[];
 
29
  onNodesChange: OnNodesChange;
30
  onEdgesChange: OnEdgesChange;
31
  onConnect: OnConnect;
@@ -46,6 +47,8 @@ export type RFState = {
46
  findNodeByName: (operatorName: Operator) => Node | undefined;
47
  updateMutableNodeFormItem: (id: string, field: string, value: any) => void;
48
  getOperatorTypeFromId: (id?: string | null) => string | undefined;
 
 
49
  };
50
 
51
  // this is our useStore hook that we can use in our components to get parts of the store and call actions
@@ -56,6 +59,7 @@ const useGraphStore = create<RFState>()(
56
  edges: [] as Edge[],
57
  selectedNodeIds: [] as string[],
58
  selectedEdgeIds: [] as string[],
 
59
  onNodesChange: (changes: NodeChange[]) => {
60
  set({
61
  nodes: applyNodeChanges(changes, get().nodes),
@@ -119,9 +123,6 @@ const useGraphStore = create<RFState>()(
119
  }
120
  }
121
  },
122
- // addOnlyOneEdgeBetweenTwoNodes: (connection: Connection) => {
123
-
124
- // },
125
  duplicateNode: (id: string) => {
126
  const { getNode, addNode } = get();
127
  const node = getNode(id);
@@ -196,6 +197,22 @@ const useGraphStore = create<RFState>()(
196
  lodashSet(nodes, [idx, 'data', 'form', field], value);
197
  }
198
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  }),
200
  { name: 'graph' },
201
  ),
 
26
  edges: Edge[];
27
  selectedNodeIds: string[];
28
  selectedEdgeIds: string[];
29
+ clickedNodeId: string; // currently selected node
30
  onNodesChange: OnNodesChange;
31
  onEdgesChange: OnEdgesChange;
32
  onConnect: OnConnect;
 
47
  findNodeByName: (operatorName: Operator) => Node | undefined;
48
  updateMutableNodeFormItem: (id: string, field: string, value: any) => void;
49
  getOperatorTypeFromId: (id?: string | null) => string | undefined;
50
+ updateNodeName: (id: string, name: string) => void;
51
+ setClickedNodeId: (id?: string) => void;
52
  };
53
 
54
  // this is our useStore hook that we can use in our components to get parts of the store and call actions
 
59
  edges: [] as Edge[],
60
  selectedNodeIds: [] as string[],
61
  selectedEdgeIds: [] as string[],
62
+ clickedNodeId: '',
63
  onNodesChange: (changes: NodeChange[]) => {
64
  set({
65
  nodes: applyNodeChanges(changes, get().nodes),
 
123
  }
124
  }
125
  },
 
 
 
126
  duplicateNode: (id: string) => {
127
  const { getNode, addNode } = get();
128
  const node = getNode(id);
 
197
  lodashSet(nodes, [idx, 'data', 'form', field], value);
198
  }
199
  },
200
+ updateNodeName: (id, name) => {
201
+ if (id) {
202
+ set({
203
+ nodes: get().nodes.map((node) => {
204
+ if (node.id === id) {
205
+ node.data.name = name;
206
+ }
207
+
208
+ return node;
209
+ }),
210
+ });
211
+ }
212
+ },
213
+ setClickedNodeId: (id?: string) => {
214
+ set({ clickedNodeId: id });
215
+ },
216
  }),
217
  { name: 'graph' },
218
  ),
web/src/pages/flow/utils.ts CHANGED
@@ -1,6 +1,7 @@
1
  import { DSLComponents } from '@/interfaces/database/flow';
2
  import { removeUselessFieldsFromValues } from '@/utils/form';
3
  import dagre from 'dagre';
 
4
  import { curry, isEmpty } from 'lodash';
5
  import pipe from 'lodash/fp/pipe';
6
  import { Edge, MarkerType, Node, Position } from 'reactflow';
@@ -61,6 +62,7 @@ export const buildNodesAndEdgesFromDSLComponents = (data: DSLComponents) => {
61
  position: { x: 0, y: 0 },
62
  data: {
63
  label: componentName,
 
64
  form: params,
65
  },
66
  sourcePosition: Position.Left,
 
1
  import { DSLComponents } from '@/interfaces/database/flow';
2
  import { removeUselessFieldsFromValues } from '@/utils/form';
3
  import dagre from 'dagre';
4
+ import { humanId } from 'human-id';
5
  import { curry, isEmpty } from 'lodash';
6
  import pipe from 'lodash/fp/pipe';
7
  import { Edge, MarkerType, Node, Position } from 'reactflow';
 
62
  position: { x: 0, y: 0 },
63
  data: {
64
  label: componentName,
65
+ name: humanId(),
66
  form: params,
67
  },
68
  sourcePosition: Position.Left,