Merging dev into main #49

Merged
8464960 merged 260 commits from dev into main 2026-01-28 10:48:52 +00:00
4 changed files with 150 additions and 21 deletions
Showing only changes of commit 9df46c90a3 - Show all commits

7
package-lock.json generated
View File

@@ -8,6 +8,7 @@
"name": "pepperplus-ui",
"version": "0.0.0",
"dependencies": {
"@neodrag/react": "^2.3.1",
"@xyflow/react": "^12.8.6",
"react": "^19.1.1",
"react-dom": "^19.1.1"
@@ -1006,6 +1007,12 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@neodrag/react": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/@neodrag/react/-/react-2.3.1.tgz",
"integrity": "sha512-mOVefo3mFmaVLs9PB5F5wMXnnclG81qjOaPHyf8YZUnw/Ciz0pAqyJDwDJk0nPTIK5I2x1JdjXSchGNdCxZNRQ==",
"license": "MIT"
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",

View File

@@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"@neodrag/react": "^2.3.1",
"@xyflow/react": "^12.8.6",
"react": "^19.1.1",
"react-dom": "^19.1.1"

View File

@@ -8,6 +8,7 @@ import {
Background,
Controls,
ReactFlow,
ReactFlowProvider,
useNodesState,
useEdgesState,
reconnectEdge,
@@ -23,6 +24,8 @@ import {
PhaseNode
} from "./components/NodeDefinitions.tsx";
import { Sidebar } from './components/DragDropSidebar.tsx';
const nodeTypes = {
start: StartNode,
end: EndNode,
@@ -59,7 +62,7 @@ const defaultEdgeOptions = {
},
};
const VisualProgrammingUI = ()=> {
const VisProgUI = ()=> {
const edgeReconnectSuccessful = useRef(true);
const [nodes, , onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
@@ -89,27 +92,41 @@ const VisualProgrammingUI = ()=> {
}, [setEdges]);
return (
<div style={{outlineStyle: 'solid', borderRadius: '10pt' ,marginInline: 'auto',width: '60vw', height: '60vh' }}>
<ReactFlow
nodes={nodes}
edges={edges}
defaultEdgeOptions={defaultEdgeOptions}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
nodeTypes={nodeTypes}
snapToGrid
onReconnect={onReconnect}
onReconnectStart={onReconnectStart}
onReconnectEnd={onReconnectEnd}
onConnect={onConnect}
fitView
proOptions={{hideAttribution: true }}
>
<Controls />
<Background />
</ReactFlow>
<div style={{marginInline: 'auto',display: 'flex',justifySelf: 'center', padding:'10px', alignItems: 'center', width: '80vw', height: '60vh'}}>
<div style={{outlineStyle: 'solid', borderRadius: '10pt', marginInline: '1em',width: '70%', height:'100%' }}>
<ReactFlow
nodes={nodes}
edges={edges}
defaultEdgeOptions={defaultEdgeOptions}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
nodeTypes={nodeTypes}
snapToGrid
onReconnect={onReconnect}
onReconnectStart={onReconnectStart}
onReconnectEnd={onReconnectEnd}
onConnect={onConnect}
fitView
proOptions={{hideAttribution: true }}
>
<Controls />
<Background />
</ReactFlow>
</div>
<div style={{width: '20%', height: '100%'}}>
<Sidebar />
</div>
</div>
);
};
export default VisualProgrammingUI
function VisualProgrammingUI(){
return (
<ReactFlowProvider>
<VisProgUI />
</ReactFlowProvider>
);
}
export default VisualProgrammingUI;

View File

@@ -0,0 +1,104 @@
import { useDraggable } from '@neodrag/react';
import {
useReactFlow,
type XYPosition
} from '@xyflow/react';
import {
type ReactNode,
useCallback,
useRef,
useState
} from 'react';
// improve later to create better automatic IDs
let id = 0;
const getId = () => `dndnode_${id++}`;
interface DraggableNodeProps {
className?: string;
children: ReactNode;
nodeType: string;
onDrop: (nodeType: string, position: XYPosition) => void;
}
function DraggableNode({ className, children, nodeType, onDrop }: DraggableNodeProps) {
const draggableRef = useRef<HTMLDivElement>(null);
const [position, setPosition] = useState<XYPosition>({ x: 0, y: 0 });
// @ts-ignore
useDraggable(draggableRef, {
position: position,
onDrag: ({ offsetX, offsetY }) => {
// Calculate position relative to the viewport
setPosition({
x: offsetX,
y: offsetY,
});
},
onDragEnd: ({ event }) => {
setPosition({ x: 0, y: 0 });
onDrop(nodeType, {
x: event.clientX,
y: event.clientY,
});
},
});
return (
<div className={className === "default" ? "default-node" : "default-node" + "__" + className} ref={draggableRef}>
{children}
</div>
);
}
export function Sidebar() {
const { setNodes, screenToFlowPosition } = useReactFlow();
const handleNodeDrop = useCallback(
(nodeType: string, screenPosition: XYPosition) => {
const flow = document.querySelector('.react-flow');
const flowRect = flow?.getBoundingClientRect();
const isInFlow =
flowRect &&
screenPosition.x >= flowRect.left &&
screenPosition.x <= flowRect.right &&
screenPosition.y >= flowRect.top &&
screenPosition.y <= flowRect.bottom;
// Create a new node and add it to the flow
if (isInFlow) {
const position = screenToFlowPosition(screenPosition);
const newNode = {
id: getId(),
type: nodeType,
position,
data: { label: `${nodeType} node` },
};
setNodes((nds) => nds.concat(newNode));
}
},
[setNodes, screenToFlowPosition],
);
return (
<aside>
<div className="description">
You can drag these nodes to the pane to create new nodes.
</div>
<DraggableNode className="default" nodeType="start" onDrop={handleNodeDrop}>
start Node
</DraggableNode>
<DraggableNode className="default" nodeType="end" onDrop={handleNodeDrop}>
end Node
</DraggableNode>
<DraggableNode className="default" nodeType="phase" onDrop={handleNodeDrop}>
phase Node
</DraggableNode>
</aside>
);
}