balibabu
commited on
Commit
·
4f06073
1
Parent(s):
8828184
feat: Update Switch form data #1739 (#2029)
Browse files### What problem does this PR solve?
feat: Update Switch form data #1739
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
web/src/pages/flow/canvas/node/categorize-handle.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
import { Handle, Position } from 'reactflow';
|
| 2 |
-
// import { v4 as uuid } from 'uuid';
|
| 3 |
|
|
|
|
| 4 |
import styles from './index.less';
|
| 5 |
|
| 6 |
const DEFAULT_HANDLE_STYLE = {
|
|
@@ -10,20 +10,19 @@ const DEFAULT_HANDLE_STYLE = {
|
|
| 10 |
fontSize: 8,
|
| 11 |
};
|
| 12 |
|
| 13 |
-
interface IProps {
|
| 14 |
top: number;
|
| 15 |
right: number;
|
| 16 |
-
|
| 17 |
idx?: number;
|
| 18 |
}
|
| 19 |
|
| 20 |
-
const CategorizeHandle = ({ top, right,
|
| 21 |
return (
|
| 22 |
<Handle
|
| 23 |
type="source"
|
| 24 |
position={Position.Right}
|
| 25 |
-
|
| 26 |
-
id={text}
|
| 27 |
isConnectable
|
| 28 |
style={{
|
| 29 |
...DEFAULT_HANDLE_STYLE,
|
|
@@ -33,7 +32,7 @@ const CategorizeHandle = ({ top, right, text, idx }: IProps) => {
|
|
| 33 |
color: 'black',
|
| 34 |
}}
|
| 35 |
>
|
| 36 |
-
<span className={styles.categorizeAnchorPointText}>{
|
| 37 |
</Handle>
|
| 38 |
);
|
| 39 |
};
|
|
|
|
| 1 |
import { Handle, Position } from 'reactflow';
|
|
|
|
| 2 |
|
| 3 |
+
import React from 'react';
|
| 4 |
import styles from './index.less';
|
| 5 |
|
| 6 |
const DEFAULT_HANDLE_STYLE = {
|
|
|
|
| 10 |
fontSize: 8,
|
| 11 |
};
|
| 12 |
|
| 13 |
+
interface IProps extends React.PropsWithChildren {
|
| 14 |
top: number;
|
| 15 |
right: number;
|
| 16 |
+
id: string;
|
| 17 |
idx?: number;
|
| 18 |
}
|
| 19 |
|
| 20 |
+
const CategorizeHandle = ({ top, right, id, children }: IProps) => {
|
| 21 |
return (
|
| 22 |
<Handle
|
| 23 |
type="source"
|
| 24 |
position={Position.Right}
|
| 25 |
+
id={id}
|
|
|
|
| 26 |
isConnectable
|
| 27 |
style={{
|
| 28 |
...DEFAULT_HANDLE_STYLE,
|
|
|
|
| 32 |
color: 'black',
|
| 33 |
}}
|
| 34 |
>
|
| 35 |
+
<span className={styles.categorizeAnchorPointText}>{children || id}</span>
|
| 36 |
</Handle>
|
| 37 |
);
|
| 38 |
};
|
web/src/pages/flow/canvas/node/categorize-node.tsx
CHANGED
|
@@ -3,7 +3,7 @@ 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';
|
|
@@ -16,6 +16,7 @@ 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,13 +50,18 @@ export function CategorizeNode({ id, data, selected }: NodeProps<NodeData>) {
|
|
| 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 |
-
|
| 59 |
idx={idx}
|
| 60 |
></CategorizeHandle>
|
| 61 |
);
|
|
|
|
| 3 |
import classNames from 'classnames';
|
| 4 |
import lowerFirst from 'lodash/lowerFirst';
|
| 5 |
import { Handle, NodeProps, Position } from 'reactflow';
|
| 6 |
+
import { Operator, SwitchElseTo, operatorMap } from '../../constant';
|
| 7 |
import { NodeData } from '../../interface';
|
| 8 |
import OperatorIcon from '../../operator-icon';
|
| 9 |
import CategorizeHandle from './categorize-handle';
|
|
|
|
| 16 |
const style = operatorMap[data.label as Operator];
|
| 17 |
const { t } = useTranslate('flow');
|
| 18 |
const { positions } = useBuildCategorizeHandlePositions({ data, id });
|
| 19 |
+
const operatorName = data.label;
|
| 20 |
|
| 21 |
return (
|
| 22 |
<NodePopover nodeId={id}>
|
|
|
|
| 50 |
className={styles.handle}
|
| 51 |
id={'c'}
|
| 52 |
></Handle>
|
| 53 |
+
{operatorName === Operator.Switch && (
|
| 54 |
+
<CategorizeHandle top={50} right={-4} id={SwitchElseTo}>
|
| 55 |
+
To
|
| 56 |
+
</CategorizeHandle>
|
| 57 |
+
)}
|
| 58 |
{positions.map((position, idx) => {
|
| 59 |
return (
|
| 60 |
<CategorizeHandle
|
| 61 |
top={position.top}
|
| 62 |
right={position.right}
|
| 63 |
key={idx}
|
| 64 |
+
id={position.text}
|
| 65 |
idx={idx}
|
| 66 |
></CategorizeHandle>
|
| 67 |
);
|
web/src/pages/flow/constant.tsx
CHANGED
|
@@ -2633,3 +2633,5 @@ export const ExeSQLOptions = ['mysql', 'postgresql', 'mariadb'].map((x) => ({
|
|
| 2633 |
label: upperFirst(x),
|
| 2634 |
value: x,
|
| 2635 |
}));
|
|
|
|
|
|
|
|
|
| 2633 |
label: upperFirst(x),
|
| 2634 |
value: x,
|
| 2635 |
}));
|
| 2636 |
+
|
| 2637 |
+
export const SwitchElseTo = 'end_cpn_id';
|
web/src/pages/flow/hooks.ts
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
| 30 |
NodeMap,
|
| 31 |
Operator,
|
| 32 |
RestrictedUpstreamMap,
|
|
|
|
| 33 |
initialArXivValues,
|
| 34 |
initialBaiduFanyiValues,
|
| 35 |
initialBaiduValues,
|
|
@@ -519,6 +520,17 @@ export const useWatchNodeFormDataChange = () => {
|
|
| 519 |
return pre;
|
| 520 |
}, []);
|
| 521 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 522 |
setEdgesByNodeId(nodeId, downstreamEdges);
|
| 523 |
},
|
| 524 |
[setEdgesByNodeId],
|
|
|
|
| 30 |
NodeMap,
|
| 31 |
Operator,
|
| 32 |
RestrictedUpstreamMap,
|
| 33 |
+
SwitchElseTo,
|
| 34 |
initialArXivValues,
|
| 35 |
initialBaiduFanyiValues,
|
| 36 |
initialBaiduValues,
|
|
|
|
| 520 |
return pre;
|
| 521 |
}, []);
|
| 522 |
|
| 523 |
+
// Splice the else condition of the conditional judgment to the edge list
|
| 524 |
+
const elseTo = form[SwitchElseTo];
|
| 525 |
+
if (elseTo) {
|
| 526 |
+
downstreamEdges.push({
|
| 527 |
+
id: uuid(),
|
| 528 |
+
source: nodeId,
|
| 529 |
+
target: elseTo,
|
| 530 |
+
sourceHandle: SwitchElseTo,
|
| 531 |
+
});
|
| 532 |
+
}
|
| 533 |
+
|
| 534 |
setEdgesByNodeId(nodeId, downstreamEdges);
|
| 535 |
},
|
| 536 |
[setEdgesByNodeId],
|
web/src/pages/flow/store.ts
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
| 21 |
import { create } from 'zustand';
|
| 22 |
import { devtools } from 'zustand/middleware';
|
| 23 |
import { immer } from 'zustand/middleware/immer';
|
| 24 |
-
import { Operator } from './constant';
|
| 25 |
import { NodeData } from './interface';
|
| 26 |
import { getOperatorIndex, isEdgeEqual } from './utils';
|
| 27 |
|
|
@@ -37,13 +37,22 @@ export type RFState = {
|
|
| 37 |
setNodes: (nodes: Node[]) => void;
|
| 38 |
setEdges: (edges: Edge[]) => void;
|
| 39 |
setEdgesByNodeId: (nodeId: string, edges: Edge[]) => void;
|
| 40 |
-
updateNodeForm: (
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
onSelectionChange: OnSelectionChangeFunc;
|
| 42 |
addNode: (nodes: Node) => void;
|
| 43 |
getNode: (id?: string | null) => Node<NodeData> | undefined;
|
| 44 |
addEdge: (connection: Connection) => void;
|
| 45 |
getEdge: (id: string) => Edge | undefined;
|
| 46 |
updateFormDataOnConnect: (connection: Connection) => void;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
deletePreviousEdgeOfClassificationNode: (connection: Connection) => void;
|
| 48 |
duplicateNode: (id: string) => void;
|
| 49 |
deleteEdge: () => void;
|
|
@@ -132,8 +141,6 @@ const useGraphStore = create<RFState>()(
|
|
| 132 |
if (isDifferent) {
|
| 133 |
// other operator's edges
|
| 134 |
const irrelevantEdges = edges.filter((x) => x.source !== nodeId);
|
| 135 |
-
// the abandoned edges
|
| 136 |
-
const selfAbandonedEdges = [];
|
| 137 |
// the added downstream edges
|
| 138 |
const selfAddedDownstreamEdges = differenceWith(
|
| 139 |
currentDownstreamEdges,
|
|
@@ -168,7 +175,8 @@ const useGraphStore = create<RFState>()(
|
|
| 168 |
return get().edges.find((x) => x.id === id);
|
| 169 |
},
|
| 170 |
updateFormDataOnConnect: (connection: Connection) => {
|
| 171 |
-
const { getOperatorTypeFromId, updateNodeForm } =
|
|
|
|
| 172 |
const { source, target, sourceHandle } = connection;
|
| 173 |
const operatorType = getOperatorTypeFromId(source);
|
| 174 |
if (source) {
|
|
@@ -185,16 +193,7 @@ const useGraphStore = create<RFState>()(
|
|
| 185 |
]);
|
| 186 |
break;
|
| 187 |
case Operator.Switch: {
|
| 188 |
-
|
| 189 |
-
const operatorIndex = getOperatorIndex(sourceHandle);
|
| 190 |
-
if (operatorIndex) {
|
| 191 |
-
updateNodeForm(source, target, [
|
| 192 |
-
'conditions',
|
| 193 |
-
operatorIndex,
|
| 194 |
-
'to',
|
| 195 |
-
]);
|
| 196 |
-
}
|
| 197 |
-
}
|
| 198 |
break;
|
| 199 |
}
|
| 200 |
default:
|
|
@@ -253,7 +252,12 @@ const useGraphStore = create<RFState>()(
|
|
| 253 |
});
|
| 254 |
},
|
| 255 |
deleteEdgeById: (id: string) => {
|
| 256 |
-
const {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
const currentEdge = edges.find((x) => x.id === id);
|
| 258 |
|
| 259 |
if (currentEdge) {
|
|
@@ -275,16 +279,7 @@ const useGraphStore = create<RFState>()(
|
|
| 275 |
]);
|
| 276 |
break;
|
| 277 |
case Operator.Switch: {
|
| 278 |
-
|
| 279 |
-
const operatorIndex = getOperatorIndex(sourceHandle);
|
| 280 |
-
if (operatorIndex) {
|
| 281 |
-
updateNodeForm(source, undefined, [
|
| 282 |
-
'conditions',
|
| 283 |
-
operatorIndex,
|
| 284 |
-
'to',
|
| 285 |
-
]);
|
| 286 |
-
}
|
| 287 |
-
}
|
| 288 |
break;
|
| 289 |
}
|
| 290 |
default:
|
|
@@ -320,7 +315,11 @@ const useGraphStore = create<RFState>()(
|
|
| 320 |
findNodeByName: (name: Operator) => {
|
| 321 |
return get().nodes.find((x) => x.data.label === name);
|
| 322 |
},
|
| 323 |
-
updateNodeForm: (
|
|
|
|
|
|
|
|
|
|
|
|
|
| 324 |
set({
|
| 325 |
nodes: get().nodes.map((node) => {
|
| 326 |
if (node.id === nodeId) {
|
|
@@ -343,6 +342,23 @@ const useGraphStore = create<RFState>()(
|
|
| 343 |
}),
|
| 344 |
});
|
| 345 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
updateMutableNodeFormItem: (id: string, field: string, value: any) => {
|
| 347 |
const { nodes } = get();
|
| 348 |
const idx = nodes.findIndex((x) => x.id === id);
|
|
|
|
| 21 |
import { create } from 'zustand';
|
| 22 |
import { devtools } from 'zustand/middleware';
|
| 23 |
import { immer } from 'zustand/middleware/immer';
|
| 24 |
+
import { Operator, SwitchElseTo } from './constant';
|
| 25 |
import { NodeData } from './interface';
|
| 26 |
import { getOperatorIndex, isEdgeEqual } from './utils';
|
| 27 |
|
|
|
|
| 37 |
setNodes: (nodes: Node[]) => void;
|
| 38 |
setEdges: (edges: Edge[]) => void;
|
| 39 |
setEdgesByNodeId: (nodeId: string, edges: Edge[]) => void;
|
| 40 |
+
updateNodeForm: (
|
| 41 |
+
nodeId: string,
|
| 42 |
+
values: any,
|
| 43 |
+
path?: (string | number)[],
|
| 44 |
+
) => void;
|
| 45 |
onSelectionChange: OnSelectionChangeFunc;
|
| 46 |
addNode: (nodes: Node) => void;
|
| 47 |
getNode: (id?: string | null) => Node<NodeData> | undefined;
|
| 48 |
addEdge: (connection: Connection) => void;
|
| 49 |
getEdge: (id: string) => Edge | undefined;
|
| 50 |
updateFormDataOnConnect: (connection: Connection) => void;
|
| 51 |
+
updateSwitchFormData: (
|
| 52 |
+
source: string,
|
| 53 |
+
sourceHandle?: string | null,
|
| 54 |
+
target?: string | null,
|
| 55 |
+
) => void;
|
| 56 |
deletePreviousEdgeOfClassificationNode: (connection: Connection) => void;
|
| 57 |
duplicateNode: (id: string) => void;
|
| 58 |
deleteEdge: () => void;
|
|
|
|
| 141 |
if (isDifferent) {
|
| 142 |
// other operator's edges
|
| 143 |
const irrelevantEdges = edges.filter((x) => x.source !== nodeId);
|
|
|
|
|
|
|
| 144 |
// the added downstream edges
|
| 145 |
const selfAddedDownstreamEdges = differenceWith(
|
| 146 |
currentDownstreamEdges,
|
|
|
|
| 175 |
return get().edges.find((x) => x.id === id);
|
| 176 |
},
|
| 177 |
updateFormDataOnConnect: (connection: Connection) => {
|
| 178 |
+
const { getOperatorTypeFromId, updateNodeForm, updateSwitchFormData } =
|
| 179 |
+
get();
|
| 180 |
const { source, target, sourceHandle } = connection;
|
| 181 |
const operatorType = getOperatorTypeFromId(source);
|
| 182 |
if (source) {
|
|
|
|
| 193 |
]);
|
| 194 |
break;
|
| 195 |
case Operator.Switch: {
|
| 196 |
+
updateSwitchFormData(source, sourceHandle, target);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 197 |
break;
|
| 198 |
}
|
| 199 |
default:
|
|
|
|
| 252 |
});
|
| 253 |
},
|
| 254 |
deleteEdgeById: (id: string) => {
|
| 255 |
+
const {
|
| 256 |
+
edges,
|
| 257 |
+
updateNodeForm,
|
| 258 |
+
getOperatorTypeFromId,
|
| 259 |
+
updateSwitchFormData,
|
| 260 |
+
} = get();
|
| 261 |
const currentEdge = edges.find((x) => x.id === id);
|
| 262 |
|
| 263 |
if (currentEdge) {
|
|
|
|
| 279 |
]);
|
| 280 |
break;
|
| 281 |
case Operator.Switch: {
|
| 282 |
+
updateSwitchFormData(source, sourceHandle, undefined);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 283 |
break;
|
| 284 |
}
|
| 285 |
default:
|
|
|
|
| 315 |
findNodeByName: (name: Operator) => {
|
| 316 |
return get().nodes.find((x) => x.data.label === name);
|
| 317 |
},
|
| 318 |
+
updateNodeForm: (
|
| 319 |
+
nodeId: string,
|
| 320 |
+
values: any,
|
| 321 |
+
path: (string | number)[] = [],
|
| 322 |
+
) => {
|
| 323 |
set({
|
| 324 |
nodes: get().nodes.map((node) => {
|
| 325 |
if (node.id === nodeId) {
|
|
|
|
| 342 |
}),
|
| 343 |
});
|
| 344 |
},
|
| 345 |
+
updateSwitchFormData: (source, sourceHandle, target) => {
|
| 346 |
+
const { updateNodeForm } = get();
|
| 347 |
+
if (sourceHandle) {
|
| 348 |
+
if (sourceHandle === SwitchElseTo) {
|
| 349 |
+
updateNodeForm(source, target, [SwitchElseTo]);
|
| 350 |
+
} else {
|
| 351 |
+
const operatorIndex = getOperatorIndex(sourceHandle);
|
| 352 |
+
if (operatorIndex) {
|
| 353 |
+
updateNodeForm(source, target, [
|
| 354 |
+
'conditions',
|
| 355 |
+
Number(operatorIndex) - 1, // The index is the conditions form index
|
| 356 |
+
'to',
|
| 357 |
+
]);
|
| 358 |
+
}
|
| 359 |
+
}
|
| 360 |
+
}
|
| 361 |
+
},
|
| 362 |
updateMutableNodeFormItem: (id: string, field: string, value: any) => {
|
| 363 |
const { nodes } = get();
|
| 364 |
const idx = nodes.findIndex((x) => x.id === id);
|
web/src/pages/flow/switch-form/index.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import { CloseOutlined } from '@ant-design/icons';
|
| 2 |
import { Button, Card, Form, Input, Select, Typography } from 'antd';
|
| 3 |
import { useTranslation } from 'react-i18next';
|
| 4 |
-
import { Operator } from '../constant';
|
| 5 |
import { useBuildFormSelectOptions } from '../form-hooks';
|
| 6 |
import { IOperatorForm, ISwitchForm } from '../interface';
|
| 7 |
import { getOtherFieldValues } from '../utils';
|
|
@@ -38,15 +38,12 @@ const SwitchForm = ({ onValuesChange, node, form }: IOperatorForm) => {
|
|
| 38 |
initialValues={{ conditions: [{}] }}
|
| 39 |
onValuesChange={onValuesChange}
|
| 40 |
>
|
| 41 |
-
<Form.Item label={t('flow.to')} name={[
|
| 42 |
<Select
|
| 43 |
allowClear
|
| 44 |
options={buildCategorizeToOptions(getSelectedConditionTos())}
|
| 45 |
/>
|
| 46 |
</Form.Item>
|
| 47 |
-
<Form.Item label={t('flow.no')} name={['no']}>
|
| 48 |
-
<Input />
|
| 49 |
-
</Form.Item>
|
| 50 |
<Form.List name="conditions">
|
| 51 |
{(fields, { add, remove }) => (
|
| 52 |
<div style={{ display: 'flex', rowGap: 16, flexDirection: 'column' }}>
|
|
@@ -74,7 +71,7 @@ const SwitchForm = ({ onValuesChange, node, form }: IOperatorForm) => {
|
|
| 74 |
<Select
|
| 75 |
allowClear
|
| 76 |
options={buildCategorizeToOptions([
|
| 77 |
-
form?.getFieldValue(
|
| 78 |
...getOtherFieldValues(form!, 'conditions', field, 'to'),
|
| 79 |
])}
|
| 80 |
/>
|
|
|
|
| 1 |
import { CloseOutlined } from '@ant-design/icons';
|
| 2 |
import { Button, Card, Form, Input, Select, Typography } from 'antd';
|
| 3 |
import { useTranslation } from 'react-i18next';
|
| 4 |
+
import { Operator, SwitchElseTo } from '../constant';
|
| 5 |
import { useBuildFormSelectOptions } from '../form-hooks';
|
| 6 |
import { IOperatorForm, ISwitchForm } from '../interface';
|
| 7 |
import { getOtherFieldValues } from '../utils';
|
|
|
|
| 38 |
initialValues={{ conditions: [{}] }}
|
| 39 |
onValuesChange={onValuesChange}
|
| 40 |
>
|
| 41 |
+
<Form.Item label={t('flow.to')} name={[SwitchElseTo]}>
|
| 42 |
<Select
|
| 43 |
allowClear
|
| 44 |
options={buildCategorizeToOptions(getSelectedConditionTos())}
|
| 45 |
/>
|
| 46 |
</Form.Item>
|
|
|
|
|
|
|
|
|
|
| 47 |
<Form.List name="conditions">
|
| 48 |
{(fields, { add, remove }) => (
|
| 49 |
<div style={{ display: 'flex', rowGap: 16, flexDirection: 'column' }}>
|
|
|
|
| 71 |
<Select
|
| 72 |
allowClear
|
| 73 |
options={buildCategorizeToOptions([
|
| 74 |
+
form?.getFieldValue(SwitchElseTo),
|
| 75 |
...getOtherFieldValues(form!, 'conditions', field, 'to'),
|
| 76 |
])}
|
| 77 |
/>
|