balibabu commited on
Commit
16f8eca
·
1 Parent(s): 2e208d4

feat: Extract the code for building categorize operator coordinates to hooks.ts #1739 (#2005)

Browse files

### What problem does this PR solve?

feat: Extract the code for building categorize operator coordinates to
hooks.ts #1739

### Type of change


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

web/src/pages/flow/canvas/node/categorize-node.tsx CHANGED
@@ -1,66 +1,21 @@
1
  import { useTranslate } from '@/hooks/common-hooks';
2
  import { Flex } from 'antd';
3
  import classNames from 'classnames';
4
- import { pick } from 'lodash';
5
- import get from 'lodash/get';
6
- import intersectionWith from 'lodash/intersectionWith';
7
- import isEqual from 'lodash/isEqual';
8
  import lowerFirst from 'lodash/lowerFirst';
9
- import { useEffect, useMemo, useState } from 'react';
10
- import { Handle, NodeProps, Position, useUpdateNodeInternals } from 'reactflow';
11
  import { Operator, operatorMap } from '../../constant';
12
- import { IPosition, NodeData } from '../../interface';
13
  import OperatorIcon from '../../operator-icon';
14
- import { buildNewPositionMap } from '../../utils';
15
  import CategorizeHandle from './categorize-handle';
16
  import NodeDropdown from './dropdown';
 
17
  import styles from './index.less';
18
  import NodePopover from './popover';
19
 
20
  export function CategorizeNode({ id, data, selected }: NodeProps<NodeData>) {
21
- const updateNodeInternals = useUpdateNodeInternals();
22
- const [postionMap, setPositionMap] = useState<Record<string, IPosition>>({});
23
- const categoryData = useMemo(
24
- () => get(data, 'form.category_description') ?? {},
25
- [data],
26
- );
27
  const style = operatorMap[data.label as Operator];
28
  const { t } = useTranslate('flow');
29
-
30
- useEffect(() => {
31
- // Cache used coordinates
32
- setPositionMap((state) => {
33
- // index in use
34
- const indexesInUse = Object.values(state).map((x) => x.idx);
35
- const categoryDataKeys = Object.keys(categoryData);
36
- const stateKeys = Object.keys(state);
37
- if (!isEqual(categoryDataKeys.sort(), stateKeys.sort())) {
38
- const intersectionKeys = intersectionWith(
39
- stateKeys,
40
- categoryDataKeys,
41
- (categoryDataKey, postionMapKey) => categoryDataKey === postionMapKey,
42
- );
43
- const newPositionMap = buildNewPositionMap(
44
- categoryDataKeys.filter(
45
- (x) => !intersectionKeys.some((y) => y === x),
46
- ),
47
- indexesInUse,
48
- );
49
-
50
- const nextPostionMap = {
51
- ...pick(state, intersectionKeys),
52
- ...newPositionMap,
53
- };
54
-
55
- return nextPostionMap;
56
- }
57
- return state;
58
- });
59
- }, [categoryData]);
60
-
61
- useEffect(() => {
62
- updateNodeInternals(id);
63
- }, [id, updateNodeInternals, postionMap]);
64
 
65
  return (
66
  <NodePopover nodeId={id}>
@@ -94,18 +49,15 @@ export function CategorizeNode({ id, data, selected }: NodeProps<NodeData>) {
94
  className={styles.handle}
95
  id={'c'}
96
  ></Handle>
97
- {Object.keys(categoryData).map((x, idx) => {
98
- const position = postionMap[x];
99
  return (
100
- position && (
101
- <CategorizeHandle
102
- top={position.top}
103
- right={position.right}
104
- key={idx}
105
- text={x}
106
- idx={idx}
107
- ></CategorizeHandle>
108
- )
109
  );
110
  })}
111
  <Flex vertical align="center" justify="center" gap={6}>
 
1
  import { useTranslate } from '@/hooks/common-hooks';
2
  import { Flex } from 'antd';
3
  import classNames from 'classnames';
 
 
 
 
4
  import lowerFirst from 'lodash/lowerFirst';
5
+ import { Handle, NodeProps, Position } from 'reactflow';
 
6
  import { Operator, operatorMap } from '../../constant';
7
+ import { NodeData } from '../../interface';
8
  import OperatorIcon from '../../operator-icon';
 
9
  import CategorizeHandle from './categorize-handle';
10
  import NodeDropdown from './dropdown';
11
+ import { useBuildCategorizeHandlePositions } from './hooks';
12
  import styles from './index.less';
13
  import NodePopover from './popover';
14
 
15
  export function CategorizeNode({ id, data, selected }: NodeProps<NodeData>) {
 
 
 
 
 
 
16
  const style = operatorMap[data.label as Operator];
17
  const { t } = useTranslate('flow');
18
+ const { positions } = useBuildCategorizeHandlePositions({ data, id });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  return (
21
  <NodePopover nodeId={id}>
 
49
  className={styles.handle}
50
  id={'c'}
51
  ></Handle>
52
+ {positions.map((position, idx) => {
 
53
  return (
54
+ <CategorizeHandle
55
+ top={position.top}
56
+ right={position.right}
57
+ key={idx}
58
+ text={position.text}
59
+ idx={idx}
60
+ ></CategorizeHandle>
 
 
61
  );
62
  })}
63
  <Flex vertical align="center" justify="center" gap={6}>
web/src/pages/flow/canvas/node/hooks.ts ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import get from 'lodash/get';
2
+ import intersectionWith from 'lodash/intersectionWith';
3
+ import isEqual from 'lodash/isEqual';
4
+ import pick from 'lodash/pick';
5
+ import { useEffect, useMemo, useState } from 'react';
6
+ import { useUpdateNodeInternals } from 'reactflow';
7
+ import { IPosition, NodeData } from '../../interface';
8
+ import { buildNewPositionMap } from '../../utils';
9
+
10
+ export const useBuildCategorizeHandlePositions = ({
11
+ data,
12
+ id,
13
+ }: {
14
+ id: string;
15
+ data: NodeData;
16
+ }) => {
17
+ const updateNodeInternals = useUpdateNodeInternals();
18
+ const [positionMap, setPositionMap] = useState<Record<string, IPosition>>({});
19
+ const categoryData = useMemo(
20
+ () => get(data, 'form.category_description') ?? {},
21
+ [data],
22
+ );
23
+
24
+ const positions = useMemo(() => {
25
+ return Object.keys(categoryData)
26
+ .map((x) => {
27
+ const position = positionMap[x];
28
+ return { text: x, ...position };
29
+ })
30
+ .filter((x) => typeof x?.right === 'number');
31
+ }, [categoryData, positionMap]);
32
+
33
+ useEffect(() => {
34
+ // Cache used coordinates
35
+ setPositionMap((state) => {
36
+ // index in use
37
+ const indexesInUse = Object.values(state).map((x) => x.idx);
38
+ const categoryDataKeys = Object.keys(categoryData);
39
+ const stateKeys = Object.keys(state);
40
+ if (!isEqual(categoryDataKeys.sort(), stateKeys.sort())) {
41
+ const intersectionKeys = intersectionWith(
42
+ stateKeys,
43
+ categoryDataKeys,
44
+ (categoryDataKey, postionMapKey) => categoryDataKey === postionMapKey,
45
+ );
46
+ const newPositionMap = buildNewPositionMap(
47
+ categoryDataKeys.filter(
48
+ (x) => !intersectionKeys.some((y) => y === x),
49
+ ),
50
+ indexesInUse,
51
+ );
52
+
53
+ const nextPositionMap = {
54
+ ...pick(state, intersectionKeys),
55
+ ...newPositionMap,
56
+ };
57
+
58
+ return nextPositionMap;
59
+ }
60
+ return state;
61
+ });
62
+ }, [categoryData]);
63
+
64
+ useEffect(() => {
65
+ updateNodeInternals(id);
66
+ }, [id, updateNodeInternals, positionMap]);
67
+
68
+ return { positions };
69
+ };
70
+
71
+ export const useBuildSwitchHandlePositions = ({
72
+ data,
73
+ id,
74
+ }: {
75
+ id: string;
76
+ data: NodeData;
77
+ }) => {};
web/src/pages/flow/constant.tsx CHANGED
@@ -485,7 +485,7 @@ export const NodeMap = {
485
  [Operator.BaiduFanyi]: 'ragNode',
486
  [Operator.QWeather]: 'ragNode',
487
  [Operator.ExeSQL]: 'ragNode',
488
- [Operator.Switch]: 'logicNode',
489
  };
490
 
491
  export const LanguageOptions = [
 
485
  [Operator.BaiduFanyi]: 'ragNode',
486
  [Operator.QWeather]: 'ragNode',
487
  [Operator.ExeSQL]: 'ragNode',
488
+ [Operator.Switch]: 'categorizeNode',
489
  };
490
 
491
  export const LanguageOptions = [
web/src/pages/flow/form-hooks.ts CHANGED
@@ -1,6 +1,6 @@
1
  import { useTranslate } from '@/hooks/common-hooks';
2
  import { useCallback, useMemo } from 'react';
3
- import { Operator } from './constant';
4
  import useGraphStore from './store';
5
 
6
  const ExcludedNodesMap = {
@@ -13,6 +13,7 @@ const ExcludedNodesMap = {
13
  ],
14
  [Operator.Relevant]: [Operator.Begin, Operator.Answer, Operator.Relevant],
15
  [Operator.Generate]: [Operator.Begin],
 
16
  };
17
 
18
  export const useBuildFormSelectOptions = (
@@ -23,7 +24,8 @@ export const useBuildFormSelectOptions = (
23
 
24
  const buildCategorizeToOptions = useCallback(
25
  (toList: string[]) => {
26
- const excludedNodes: Operator[] = ExcludedNodesMap[operatorName] ?? [];
 
27
  return nodes
28
  .filter(
29
  (x) =>
 
1
  import { useTranslate } from '@/hooks/common-hooks';
2
  import { useCallback, useMemo } from 'react';
3
+ import { Operator, RestrictedUpstreamMap } from './constant';
4
  import useGraphStore from './store';
5
 
6
  const ExcludedNodesMap = {
 
13
  ],
14
  [Operator.Relevant]: [Operator.Begin, Operator.Answer, Operator.Relevant],
15
  [Operator.Generate]: [Operator.Begin],
16
+ [Operator.Switch]: [Operator.Begin],
17
  };
18
 
19
  export const useBuildFormSelectOptions = (
 
24
 
25
  const buildCategorizeToOptions = useCallback(
26
  (toList: string[]) => {
27
+ const excludedNodes: Operator[] =
28
+ RestrictedUpstreamMap[operatorName] ?? [];
29
  return nodes
30
  .filter(
31
  (x) =>
web/src/pages/flow/store.ts CHANGED
@@ -147,7 +147,6 @@ const useGraphStore = create<RFState>()(
147
  ]);
148
  }
149
  },
150
-
151
  addNode: (node: Node) => {
152
  set({ nodes: get().nodes.concat(node) });
153
  },
 
147
  ]);
148
  }
149
  },
 
150
  addNode: (node: Node) => {
151
  set({ nodes: get().nodes.concat(node) });
152
  },
web/src/pages/flow/switch-form/index.tsx CHANGED
@@ -1,7 +1,9 @@
1
  import { CloseOutlined } from '@ant-design/icons';
2
- import { Button, Card, Form, Input, Typography } from 'antd';
3
  import React from 'react';
4
  import { useTranslation } from 'react-i18next';
 
 
5
  import { IOperatorForm } from '../interface';
6
 
7
  const subLabelCol = {
@@ -12,8 +14,16 @@ const subWrapperCol = {
12
  span: 17,
13
  };
14
 
15
- const SwitchForm: React.FC = ({ form, onValuesChange }: IOperatorForm) => {
 
 
 
 
16
  const { t } = useTranslation();
 
 
 
 
17
 
18
  return (
19
  <Form
@@ -26,7 +36,7 @@ const SwitchForm: React.FC = ({ form, onValuesChange }: IOperatorForm) => {
26
  onValuesChange={onValuesChange}
27
  >
28
  <Form.Item label={t('flow.to')} name={['end_cpn_id']}>
29
- <Input />
30
  </Form.Item>
31
  <Form.Item label={t('flow.no')} name={['no']}>
32
  <Input />
@@ -55,9 +65,8 @@ const SwitchForm: React.FC = ({ form, onValuesChange }: IOperatorForm) => {
55
  </Form.Item>
56
 
57
  <Form.Item label={t('flow.to')} name={[field.name, 'to']}>
58
- <Input />
59
  </Form.Item>
60
- {/* Nest Form.List */}
61
  <Form.Item label="Items">
62
  <Form.List name={[field.name, 'items']}>
63
  {(subFields, subOpt) => (
 
1
  import { CloseOutlined } from '@ant-design/icons';
2
+ import { Button, Card, Form, Input, Select, Typography } from 'antd';
3
  import React from 'react';
4
  import { useTranslation } from 'react-i18next';
5
+ import { Operator } from '../constant';
6
+ import { useBuildFormSelectOptions } from '../form-hooks';
7
  import { IOperatorForm } from '../interface';
8
 
9
  const subLabelCol = {
 
14
  span: 17,
15
  };
16
 
17
+ const SwitchForm: React.FC = ({
18
+ form,
19
+ onValuesChange,
20
+ nodeId,
21
+ }: IOperatorForm) => {
22
  const { t } = useTranslation();
23
+ const buildCategorizeToOptions = useBuildFormSelectOptions(
24
+ Operator.Categorize,
25
+ nodeId,
26
+ );
27
 
28
  return (
29
  <Form
 
36
  onValuesChange={onValuesChange}
37
  >
38
  <Form.Item label={t('flow.to')} name={['end_cpn_id']}>
39
+ <Select options={buildCategorizeToOptions([])} />
40
  </Form.Item>
41
  <Form.Item label={t('flow.no')} name={['no']}>
42
  <Input />
 
65
  </Form.Item>
66
 
67
  <Form.Item label={t('flow.to')} name={[field.name, 'to']}>
68
+ <Select options={buildCategorizeToOptions([])} />
69
  </Form.Item>
 
70
  <Form.Item label="Items">
71
  <Form.List name={[field.name, 'items']}>
72
  {(subFields, subOpt) => (
web/src/utils/request.ts CHANGED
@@ -9,7 +9,7 @@ import { history } from 'umi';
9
  import { RequestMethod, extend } from 'umi-request';
10
  import { convertTheKeysOfTheObjectToSnake } from './common-util';
11
 
12
- const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.';
13
 
14
  const RetcodeMessage = {
15
  200: i18n.t('message.200'),
@@ -50,8 +50,11 @@ const errorHandler = (error: {
50
  message: string;
51
  }): Response => {
52
  const { response } = error;
53
- if (error.message === ABORT_REQUEST_ERR_MESSAGE) {
54
- console.log('user abort request');
 
 
 
55
  } else {
56
  if (response && response.status) {
57
  const errorText =
@@ -61,11 +64,6 @@ const errorHandler = (error: {
61
  message: `${i18n.t('message.requestError')} ${status}: ${url}`,
62
  description: errorText,
63
  });
64
- } else if (!response) {
65
- notification.error({
66
- description: i18n.t('message.networkAnomalyDescription'),
67
- message: i18n.t('message.networkAnomaly'),
68
- });
69
  }
70
  }
71
  return response;
@@ -102,6 +100,7 @@ request.interceptors.response.use(async (response: any, options) => {
102
  if (options.responseType === 'blob') {
103
  return response;
104
  }
 
105
  const data: ResponseType = await response.clone().json();
106
 
107
  if (data.retcode === 401 || data.retcode === 401) {
 
9
  import { RequestMethod, extend } from 'umi-request';
10
  import { convertTheKeysOfTheObjectToSnake } from './common-util';
11
 
12
+ const FAILED_TO_FETCH = 'Failed to fetch';
13
 
14
  const RetcodeMessage = {
15
  200: i18n.t('message.200'),
 
50
  message: string;
51
  }): Response => {
52
  const { response } = error;
53
+ if (error.message === FAILED_TO_FETCH) {
54
+ notification.error({
55
+ description: i18n.t('message.networkAnomalyDescription'),
56
+ message: i18n.t('message.networkAnomaly'),
57
+ });
58
  } else {
59
  if (response && response.status) {
60
  const errorText =
 
64
  message: `${i18n.t('message.requestError')} ${status}: ${url}`,
65
  description: errorText,
66
  });
 
 
 
 
 
67
  }
68
  }
69
  return response;
 
100
  if (options.responseType === 'blob') {
101
  return response;
102
  }
103
+
104
  const data: ResponseType = await response.clone().json();
105
 
106
  if (data.retcode === 401 || data.retcode === 401) {