Skip to content

Commit

Permalink
feat: fixed issue with threshold translation #882 and add NodeContext…
Browse files Browse the repository at this point in the history
…Menu (#906)

### What problem does this PR solve?

feat: fixed issue with threshold translation #882
feat: add NodeContextMenu

### Type of change


- [ ] New Feature (non-breaking change which adds functionality)
  • Loading branch information
cike8899 authored May 23, 2024
1 parent 1e5c5ab commit 4cda40c
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 57 deletions.
4 changes: 2 additions & 2 deletions web/src/locales/zh-traditional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ export default {
以上就是你需要總結的內容。`,
maxToken: '最大token數',
maxTokenMessage: '最大token數是必填項',
threshold: '臨界點',
thresholdMessage: '臨界點是必填項',
threshold: '閾值',
thresholdMessage: '閾值是必填項',
maxCluster: '最大聚類數',
maxClusterMessage: '最大聚類數是必填項',
randomSeed: '隨機種子',
Expand Down
4 changes: 2 additions & 2 deletions web/src/locales/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,8 @@ export default {
以上就是你需要总结的内容。`,
maxToken: '最大token数',
maxTokenMessage: '最大token数是必填项',
threshold: '临界点',
thresholdMessage: '临界点是必填项',
threshold: '阈值',
thresholdMessage: '阈值是必填项',
maxCluster: '最大聚类数',
maxClusterMessage: '最大聚类数是必填项',
randomSeed: '随机种子',
Expand Down
18 changes: 18 additions & 0 deletions web/src/pages/flow/canvas/context-menu/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.contextMenu {
background: white;
border-style: solid;
box-shadow: 10px 19px 20px rgba(0, 0, 0, 10%);
position: absolute;
z-index: 10;
button {
border: none;
display: block;
padding: 0.5em;
text-align: left;
width: 100%;
}

button:hover {
background: white;
}
}
108 changes: 108 additions & 0 deletions web/src/pages/flow/canvas/context-menu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { useCallback, useRef, useState } from 'react';
import { NodeMouseHandler, useReactFlow } from 'reactflow';

import styles from './index.less';

export interface INodeContextMenu {
id: string;
top: number;
left: number;
right?: number;
bottom?: number;
[key: string]: unknown;
}

export function NodeContextMenu({
id,
top,
left,
right,
bottom,
...props
}: INodeContextMenu) {
const { getNode, setNodes, addNodes, setEdges } = useReactFlow();

const duplicateNode = useCallback(() => {
const node = getNode(id);
const position = {
x: node?.position?.x || 0 + 50,
y: node?.position?.y || 0 + 50,
};

addNodes({
...(node || {}),
data: node?.data,
selected: false,
dragging: false,
id: `${node?.id}-copy`,
position,
});
}, [id, getNode, addNodes]);

const deleteNode = useCallback(() => {
setNodes((nodes) => nodes.filter((node) => node.id !== id));
setEdges((edges) => edges.filter((edge) => edge.source !== id));
}, [id, setNodes, setEdges]);

return (
<div
style={{ top, left, right, bottom }}
className={styles.contextMenu}
{...props}
>
<p style={{ margin: '0.5em' }}>
<small>node: {id}</small>
</p>
<button onClick={duplicateNode} type={'button'}>
duplicate
</button>
<button onClick={deleteNode} type={'button'}>
delete
</button>
</div>
);
}

export const useHandleNodeContextMenu = (sideWidth: number) => {
const [menu, setMenu] = useState<INodeContextMenu>({} as INodeContextMenu);
const ref = useRef<any>(null);

const onNodeContextMenu: NodeMouseHandler = useCallback(
(event, node) => {
// Prevent native context menu from showing
event.preventDefault();

// Calculate position of the context menu. We want to make sure it
// doesn't get positioned off-screen.
const pane = ref.current?.getBoundingClientRect();
// setMenu({
// id: node.id,
// top: event.clientY < pane.height - 200 ? event.clientY : 0,
// left: event.clientX < pane.width - 200 ? event.clientX : 0,
// right: event.clientX >= pane.width - 200 ? pane.width - event.clientX : 0,
// bottom:
// event.clientY >= pane.height - 200 ? pane.height - event.clientY : 0,
// });

console.info('clientX:', event.clientX);
console.info('clientY:', event.clientY);

setMenu({
id: node.id,
top: event.clientY - 72,
left: event.clientX - sideWidth,
// top: event.clientY < pane.height - 200 ? event.clientY - 72 : 0,
// left: event.clientX < pane.width - 200 ? event.clientX : 0,
});
},
[sideWidth],
);

// Close the context menu if it's open whenever the window is clicked.
const onPaneClick = useCallback(
() => setMenu({} as INodeContextMenu),
[setMenu],
);

return { onNodeContextMenu, menu, onPaneClick, ref };
};
41 changes: 32 additions & 9 deletions web/src/pages/flow/canvas/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ReactFlow, {
Controls,
Edge,
Node,
NodeMouseHandler,
OnConnect,
OnEdgesChange,
OnNodesChange,
Expand All @@ -13,7 +14,10 @@ import ReactFlow, {
} from 'reactflow';
import 'reactflow/dist/style.css';

import { useHandleDrop } from '../hooks';
import { NodeContextMenu, useHandleNodeContextMenu } from './context-menu';

import FlowDrawer from '../flow-drawer';
import { useHandleDrop, useShowDrawer } from '../hooks';
import { TextUpdaterNode } from './node';

const nodeTypes = { textUpdater: TextUpdaterNode };
Expand Down Expand Up @@ -42,9 +46,17 @@ const initialEdges = [
{ id: '1-2', source: '1', target: '2', label: 'to the', type: 'step' },
];

function FlowCanvas() {
interface IProps {
sideWidth: number;
showDrawer(): void;
}

function FlowCanvas({ sideWidth }: IProps) {
const [nodes, setNodes] = useState<Node[]>(initialNodes);
const [edges, setEdges] = useState<Edge[]>(initialEdges);
const { ref, menu, onNodeContextMenu, onPaneClick } =
useHandleNodeContextMenu(sideWidth);
const { drawerVisible, hideDrawer, showDrawer } = useShowDrawer();

const onNodesChange: OnNodesChange = useCallback(
(changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
Expand All @@ -60,31 +72,42 @@ function FlowCanvas() {
[],
);

const { handleDrop, allowDrop } = useHandleDrop(setNodes);
const onNodeClick: NodeMouseHandler = useCallback(() => {
showDrawer();
}, [showDrawer]);

const { onDrop, onDragOver, setReactFlowInstance } = useHandleDrop(setNodes);

useEffect(() => {
console.info('nodes:', nodes);
console.info('edges:', edges);
}, [nodes, edges]);

return (
<div
style={{ height: '100%', width: '100%' }}
onDrop={handleDrop}
onDragOver={allowDrop}
>
<div style={{ height: '100%', width: '100%' }}>
<ReactFlow
ref={ref}
nodes={nodes}
onNodesChange={onNodesChange}
onNodeContextMenu={onNodeContextMenu}
edges={edges}
onEdgesChange={onEdgesChange}
// fitView
fitView
onConnect={onConnect}
nodeTypes={nodeTypes}
onPaneClick={onPaneClick}
onDrop={onDrop}
onDragOver={onDragOver}
onNodeClick={onNodeClick}
onInit={setReactFlowInstance}
>
<Background />
<Controls />
{Object.keys(menu).length > 0 && (
<NodeContextMenu onClick={onPaneClick} {...(menu as any)} />
)}
</ReactFlow>
<FlowDrawer visible={drawerVisible} hideModal={hideDrawer}></FlowDrawer>
</div>
);
}
Expand Down
20 changes: 20 additions & 0 deletions web/src/pages/flow/flow-drawer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { IModalProps } from '@/interfaces/common';
import { Drawer } from 'antd';

const FlowDrawer = ({ visible, hideModal }: IModalProps<any>) => {
return (
<Drawer
title="Basic Drawer"
placement="right"
// closable={false}
onClose={hideModal}
open={visible}
getContainer={false}
mask={false}
>
<p>Some contents...</p>
</Drawer>
);
};

export default FlowDrawer;
15 changes: 9 additions & 6 deletions web/src/pages/flow/flow-sider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { Avatar, Card, Flex, Layout, Space } from 'antd';
import classNames from 'classnames';
import { useState } from 'react';
import { componentList } from '../mock';

import { useHandleDrag } from '../hooks';
import styles from './index.less';

const { Sider } = Layout;

const FlowSider = () => {
const [collapsed, setCollapsed] = useState(true);
const { handleDrag } = useHandleDrag();
interface IProps {
setCollapsed: (width: boolean) => void;
collapsed: boolean;
}

const FlowSide = ({ setCollapsed, collapsed }: IProps) => {
const { handleDragStart } = useHandleDrag();

return (
<Sider
Expand All @@ -27,7 +30,7 @@ const FlowSider = () => {
hoverable
draggable
className={classNames(styles.operatorCard)}
onDragStart={handleDrag(x.name)}
onDragStart={handleDragStart(x.name)}
>
<Flex justify="space-between" align="center">
<Space size={15}>
Expand All @@ -45,4 +48,4 @@ const FlowSider = () => {
);
};

export default FlowSider;
export default FlowSide;
Loading

0 comments on commit 4cda40c

Please sign in to comment.