feat: Add RunDrawer #3355 (#3434)

### What problem does this PR solve?

feat: Translation test run form #3355
feat: Wrap QueryTable with Collapse #3355
feat: If the required fields are not filled in, the submit button will
be grayed out. #3355
feat: Add RunDrawer #3355

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2024-11-15 15:17:23 +08:00
committed by GitHub
parent a854bc22d1
commit e0659a4f0e
25 changed files with 780 additions and 135 deletions

View File

@@ -1,4 +1,5 @@
import { useCallback } from 'react';
import { useSetModalState } from '@/hooks/common-hooks';
import { useCallback, useEffect } from 'react';
import ReactFlow, {
Background,
ConnectionMode,
@@ -8,14 +9,17 @@ import ReactFlow, {
import 'reactflow/dist/style.css';
import ChatDrawer from '../chat/drawer';
import { Operator } from '../constant';
import FlowDrawer from '../flow-drawer';
import FormDrawer from '../flow-drawer';
import {
useGetBeginNodeDataQuery,
useHandleDrop,
useSelectCanvasData,
useShowDrawer,
useShowFormDrawer,
useValidateConnection,
useWatchNodeFormDataChange,
} from '../hooks';
import { BeginQuery } from '../interface';
import RunDrawer from '../run-drawer';
import { ButtonEdge } from './edge';
import styles from './index.less';
import { RagNode } from './node';
@@ -53,11 +57,11 @@ const edgeTypes = {
};
interface IProps {
chatDrawerVisible: boolean;
hideChatDrawer(): void;
drawerVisible: boolean;
hideDrawer(): void;
}
function FlowCanvas({ chatDrawerVisible, hideChatDrawer }: IProps) {
function FlowCanvas({ drawerVisible, hideDrawer }: IProps) {
const {
nodes,
edges,
@@ -67,27 +71,66 @@ function FlowCanvas({ chatDrawerVisible, hideChatDrawer }: IProps) {
onSelectionChange,
} = useSelectCanvasData();
const isValidConnection = useValidateConnection();
const {
visible: runVisible,
showModal: showRunModal,
hideModal: hideRunModal,
} = useSetModalState();
const {
visible: chatVisible,
showModal: showChatModal,
hideModal: hideChatModal,
} = useSetModalState();
const { drawerVisible, hideDrawer, showDrawer, clickedNode } =
useShowDrawer();
const onNodeClick: NodeMouseHandler = useCallback(
(e, node) => {
if (node.data.label !== Operator.Note) {
showDrawer(node);
}
},
[showDrawer],
);
const { formDrawerVisible, hideFormDrawer, showFormDrawer, clickedNode } =
useShowFormDrawer();
const onPaneClick = useCallback(() => {
hideDrawer();
}, [hideDrawer]);
hideFormDrawer();
}, [hideFormDrawer]);
const { onDrop, onDragOver, setReactFlowInstance } = useHandleDrop();
useWatchNodeFormDataChange();
const hideRunOrChatDrawer = useCallback(() => {
hideChatModal();
hideRunModal();
hideDrawer();
}, [hideChatModal, hideDrawer, hideRunModal]);
const onNodeClick: NodeMouseHandler = useCallback(
(e, node) => {
if (node.data.label !== Operator.Note) {
hideRunOrChatDrawer();
showFormDrawer(node);
}
},
[hideRunOrChatDrawer, showFormDrawer],
);
const getBeginNodeDataQuery = useGetBeginNodeDataQuery();
useEffect(() => {
if (drawerVisible) {
const query: BeginQuery[] = getBeginNodeDataQuery();
if (query.length > 0) {
showRunModal();
hideChatModal();
} else {
showChatModal();
hideRunModal();
}
}
}, [
hideChatModal,
hideRunModal,
showChatModal,
showRunModal,
drawerVisible,
getBeginNodeDataQuery,
]);
return (
<div className={styles.canvasWrapper}>
<svg
@@ -147,17 +190,26 @@ function FlowCanvas({ chatDrawerVisible, hideChatDrawer }: IProps) {
<Background />
<Controls />
</ReactFlow>
<FlowDrawer
node={clickedNode}
visible={drawerVisible}
hideModal={hideDrawer}
></FlowDrawer>
{chatDrawerVisible && (
{formDrawerVisible && (
<FormDrawer
node={clickedNode}
visible={formDrawerVisible}
hideModal={hideFormDrawer}
></FormDrawer>
)}
{chatVisible && (
<ChatDrawer
visible={chatDrawerVisible}
hideModal={hideChatDrawer}
visible={chatVisible}
hideModal={hideRunOrChatDrawer}
></ChatDrawer>
)}
{runVisible && (
<RunDrawer
hideModal={hideRunOrChatDrawer}
showModal={showChatModal}
></RunDrawer>
)}
</div>
);
}

View File

@@ -1,9 +1,15 @@
import { Flex } from 'antd';
import classNames from 'classnames';
import get from 'lodash/get';
import { useTranslation } from 'react-i18next';
import { Handle, NodeProps, Position } from 'reactflow';
import { Operator, operatorMap } from '../../constant';
import { NodeData } from '../../interface';
import {
BeginQueryType,
BeginQueryTypeIconMap,
Operator,
operatorMap,
} from '../../constant';
import { BeginQuery, NodeData } from '../../interface';
import OperatorIcon from '../../operator-icon';
import { RightHandleStyle } from './handle-icon';
import styles from './index.less';
@@ -11,15 +17,13 @@ import styles from './index.less';
// TODO: do not allow other nodes to connect to this node
export function BeginNode({ selected, data }: NodeProps<NodeData>) {
const { t } = useTranslation();
const query: BeginQuery[] = get(data, 'form.query', []);
return (
<section
className={classNames(styles.ragNode, {
[styles.selectedNode]: selected,
})}
style={{
width: 100,
}}
>
<Handle
type="source"
@@ -29,7 +33,7 @@ export function BeginNode({ selected, data }: NodeProps<NodeData>) {
style={RightHandleStyle}
></Handle>
<Flex align="center" justify={'space-around'}>
<Flex align="center" justify={'center'} gap={10}>
<OperatorIcon
name={data.label as Operator}
fontSize={24}
@@ -37,6 +41,24 @@ export function BeginNode({ selected, data }: NodeProps<NodeData>) {
></OperatorIcon>
<div className={styles.nodeTitle}>{t(`flow.begin`)}</div>
</Flex>
<Flex gap={8} vertical className={styles.generateParameters}>
{query.map((x, idx) => {
const Icon = BeginQueryTypeIconMap[x.type as BeginQueryType];
return (
<Flex
key={idx}
align="center"
gap={6}
className={styles.conditionBlock}
>
<Icon className="size-4" />
<label htmlFor="">{x.key}</label>
<span className={styles.parameterValue}>{x.name}</span>
<span className="flex-1">{x.optional ? 'Yes' : 'No'}</span>
</Flex>
);
})}
</Flex>
</section>
);
}