refactor: Initial working framework of node encapsulation works- polymorphic implementation of nodes in creating and connecting calls correct functions

ref: N25B-294
This commit is contained in:
Björn Otgaar
2025-11-17 14:25:01 +01:00
parent b7eb0cb5ec
commit c5dc825ca3
13 changed files with 605 additions and 662 deletions

View File

@@ -0,0 +1,116 @@
import {
Handle,
type NodeProps,
Position,
type Connection,
type Edge,
useReactFlow,
type Node,
} from '@xyflow/react';
import { Toolbar } from './NodeDefinitions';
import styles from '../../VisProg.module.css';
import { NodeDefaults, NodeReduces } from '../NodeRegistry';
import type { FlowState } from '../VisProgTypes';
/**
* The default data dot a phase node
* @param label: the label of this phase
* @param droppable: whether this node is droppable from the drop bar (initialized as true)
* @param children: ID's of children of this node
*/
export type PhaseNodeData = {
label: string;
droppable: boolean;
children: string[];
hasReduce: boolean;
};
/**
* Default data for this node
*/
export const PhaseNodeDefaults: PhaseNodeData = {
label: "Phase Node",
droppable: true,
children: [],
hasReduce: true,
};
export type PhaseNode = Node<PhaseNodeData>
/**
*
* @param connection
* @returns
*/
export function PhaseNodeCanConnect(connection: Connection | Edge): boolean {
return true;
}
/**
* Defines how a phase node should be rendered
* @param props NodeProps, like id, label, children
* @returns React.JSX.Element
*/
export default function PhaseNode(props: NodeProps<Node>) {
const reactFlow = useReactFlow();
const label_input_id = `phase_${props.id}_label_input`;
return (
<>
<Toolbar nodeId={props.id} allowDelete={true}/>
<div className={`${styles.defaultNode} ${styles.nodePhase}`}>
<div className={"flex-row gap-sm"}>
<label htmlFor={label_input_id}></label>
{props.data.label as string}
</div>
<Handle type="target" position={Position.Left} id="target"/>
<Handle type="source" position={Position.Right} id="source"/>
<Handle type="source" position={Position.Bottom} id="norms"/>
</div>
</>
);
}
/**
* Reduces each phase, including its children down into its relevant data.
* @param props: The Node Properties of this node.
*/
export function PhaseReduce(node: Node, nodes: Node[]) {
const thisnode = node as PhaseNode;
const data = thisnode.data as PhaseNodeData;
const reducableChildren = Object.entries(NodeDefaults)
.filter(([_, data]) => data.hasReduce)
.map(([type, _]) => (
type
));
let childrenData: any = ""
if (data.children != undefined) {
childrenData = data.children.map((childId) => {
// Reduce each of this phases' children.
let child = nodes.find((node) => node.id == childId);
// Make sure that we reduce only valid children nodes.
if (child == undefined || child.type == undefined || !reducableChildren.includes(child.type)) return ''
const reducer = NodeReduces[child.type as keyof typeof NodeReduces]
if (!reducer) {
console.warn(`No reducer found for node type ${child.type}`);
return null;
}
return reducer(child, nodes);
})}
return {
id: thisnode.id,
name: data.label as string,
children: childrenData,
}
}
export function PhaseConnects(thisNode: Node, otherNode: Node, isThisSource: boolean) {
console.log("Connect functionality called.")
let node = thisNode as PhaseNode
let data = node.data as PhaseNodeData
if (isThisSource)
data.children.push(otherNode.id)
}