Skip to content

early merge graph branch for general bug fixes#38

Merged
Morten-Renner merged 43 commits into
developmentfrom
graph-based-tools
Sep 28, 2025
Merged

early merge graph branch for general bug fixes#38
Morten-Renner merged 43 commits into
developmentfrom
graph-based-tools

Conversation

@Morten-Renner

Copy link
Copy Markdown
Member

No description provided.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a graph-based node editor system with internationalization improvements. The implementation includes a visual node editor with drag-and-drop functionality, edge connections between nodes, and type-safe node definitions for various operations.

  • Adds complete graph editor infrastructure with node management, edge rendering, and execution engine
  • Implements drag-and-drop canvas functionality with infinite scrolling
  • Enhances internationalization with client-side error handling and fallback mechanisms

Reviewed Changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/styles/node.css Node styling with animations and drag states
src/lib/graph/* Core graph functionality including node execution, edge rendering, and type compatibility
src/components/graph/* React components for the graph editor UI
src/i18n/request.ts Server-side i18n error handling
src/components/intl-error-handling-client-provider.tsx Client-side i18n error handling
src/app/[locale]/layout.tsx Integration of new i18n provider
src/app/[locale]/debug/graph/page.tsx Debug page showcasing graph functionality
next.config.mjs Configuration update for i18n
i18n/en.json Translation keys for graph components

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread src/lib/graph/isEdgeDropValid.ts Outdated
Comment thread src/lib/graph/isEdgeDropValid.ts Outdated
Comment on lines +28 to +31
const formNodeIO = fromNode?.getAllIO().find(io => io.name === fromIO.nodeIOName);
const toNodeIO = toNode?.getAllIO().find(io => io.name === toIO.nodeIOName);

if (!formNodeIO || !toNodeIO) {

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable reference 'formNodeIO' should be 'fromNodeIO' to match the corrected variable name.

Suggested change
const formNodeIO = fromNode?.getAllIO().find(io => io.name === fromIO.nodeIOName);
const toNodeIO = toNode?.getAllIO().find(io => io.name === toIO.nodeIOName);
if (!formNodeIO || !toNodeIO) {
const fromNodeIO = fromNode?.getAllIO().find(io => io.name === fromIO.nodeIOName);
const toNodeIO = toNode?.getAllIO().find(io => io.name === toIO.nodeIOName);
if (!fromNodeIO || !toNodeIO) {

Copilot uses AI. Check for mistakes.
Comment thread src/lib/graph/isEdgeDropValid.ts Outdated
const isFromIoOutput = fromNode.outputs.some(output => output.name === fromIO.nodeIOName);
const isToIoInput = toNode.inputs.some(input => input.name === toIO.nodeIOName);

if(isFromIoOutput !== isToIoInput) { // only input to outpot or output to input is valid

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment contains typo 'outpot' which should be 'output'.

Suggested change
if(isFromIoOutput !== isToIoInput) { // only input to outpot or output to input is valid
if(isFromIoOutput !== isToIoInput) { // only input to output or output to input is valid

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +44
console.log({
dragStartRef: dragStartRef.current,
scrollStartRef: scrollStartRef.current,
currentX: e.clientX,
currentY: e.clientY,
deltaX: e.clientX - dragStartRef.current.x,
deltaY: e.clientY - dragStartRef.current.y,
});

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug console.log statement should be removed from production code.

Copilot uses AI. Check for mistakes.
Comment thread src/lib/graph/useCanvasDrag.ts Outdated
Comment on lines +70 to +87
useEffect(() => {
console.log("onEndDraggingCanvas");
return () => {
console.log("cleanup onEndDraggingCanvas");
};
}, [onEndDraggingCanvas]);
useEffect(() => {
console.log("setCurrentlyDraggingNode");
return () => {
console.log("cleanup setCurrentlyDraggingNode");
};
}, [onEndDraggingCanvas]);
useEffect(() => {
console.log("onMouseMoveDragCanvas");
return () => {
console.log("cleanup onMouseMoveDragCanvas");
};
}, [onEndDraggingCanvas]);

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple debug console.log statements and empty useEffect hooks should be removed from production code.

Copilot uses AI. Check for mistakes.
Comment thread src/lib/graph/areTypesCompatible.ts Outdated
}

areTypesCompatibleCache[cacheKey] = variant;
console.log(areTypesCompatibleCache);

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug console.log statement should be removed from production code.

Suggested change
console.log(areTypesCompatibleCache);

Copilot uses AI. Check for mistakes.
Comment thread src/lib/graph/useEdgeRenderer.tsx Outdated
Comment on lines +69 to +73
graphRef.current?.addEventListener("transitionend", recalculateEdges);
graphRef.current?.addEventListener("scroll", recalculateEdges);
return () => {
graphRef.current?.removeEventListener("transitionend", recalculateEdges);
graphRef.current?.removeEventListener("scroll", recalculateEdges);

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Event listeners are being removed using a stale reference to graphRef.current. Store the reference in a variable within the useEffect to ensure proper cleanup.

Suggested change
graphRef.current?.addEventListener("transitionend", recalculateEdges);
graphRef.current?.addEventListener("scroll", recalculateEdges);
return () => {
graphRef.current?.removeEventListener("transitionend", recalculateEdges);
graphRef.current?.removeEventListener("scroll", recalculateEdges);
const graphEl = graphRef.current;
graphEl?.addEventListener("transitionend", recalculateEdges);
graphEl?.addEventListener("scroll", recalculateEdges);
return () => {
graphEl?.removeEventListener("transitionend", recalculateEdges);
graphEl?.removeEventListener("scroll", recalculateEdges);

Copilot uses AI. Check for mistakes.
e.dataTransfer.dropEffect = "move";

const fromIoJSON = e.dataTransfer.getData("fromIO");
if (fromIoJSON == undefined || fromIoJSON.length == 0) {

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use strict equality (===) instead of loose equality (==) for type safety.

Suggested change
if (fromIoJSON == undefined || fromIoJSON.length == 0) {
if (fromIoJSON === undefined || fromIoJSON === null || fromIoJSON.length === 0) {

Copilot uses AI. Check for mistakes.
<Node
key={nodeState.id}
nodeState={nodeState}
isBeingDragged={nodeState.id == currentlyDraggingNode?.nodeId}

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use strict equality (===) instead of loose equality (==) for type safety.

Suggested change
isBeingDragged={nodeState.id == currentlyDraggingNode?.nodeId}
isBeingDragged={nodeState.id === currentlyDraggingNode?.nodeId}

Copilot uses AI. Check for mistakes.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 28 out of 28 changed files in this pull request and generated 5 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +37 to +44
console.log({
dragStartRef: dragStartRef.current,
scrollStartRef: scrollStartRef.current,
currentX: e.clientX,
currentY: e.clientY,
deltaX: e.clientX - dragStartRef.current.x,
deltaY: e.clientY - dragStartRef.current.y,
});

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug console.log statement should be removed from production code. Consider using a proper logging solution or removing this debug output.

Suggested change
console.log({
dragStartRef: dragStartRef.current,
scrollStartRef: scrollStartRef.current,
currentX: e.clientX,
currentY: e.clientY,
deltaX: e.clientX - dragStartRef.current.x,
deltaY: e.clientY - dragStartRef.current.y,
});

Copilot uses AI. Check for mistakes.
const isFromIoOutput = fromNode.outputs.some(output => output.name === fromIO.nodeIOName);
const isToIoInput = toNode.inputs.some(input => input.name === toIO.nodeIOName);

if(isFromIoOutput !== isToIoInput) { // only input to output or output to input is valid

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic is inverted. The condition should be if(isFromIoOutput === isToIoInput) because connecting output-to-output or input-to-input should be invalid, not output-to-input or input-to-output.

Suggested change
if(isFromIoOutput !== isToIoInput) { // only input to output or output to input is valid
if(isFromIoOutput === isToIoInput) { // only input to output or output to input is valid

Copilot uses AI. Check for mistakes.
e.dataTransfer.dropEffect = "move";

const fromIoJSON = e.dataTransfer.getData("fromIO");
if (fromIoJSON == undefined || fromIoJSON.length == 0) {

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use strict equality operators (=== and !==) instead of loose equality (== and !=) for better type safety and to avoid unexpected type coercion.

Suggested change
if (fromIoJSON == undefined || fromIoJSON.length == 0) {
if (fromIoJSON === undefined || fromIoJSON.length == 0) {

Copilot uses AI. Check for mistakes.
OutputKeys extends readonly string[]
>(
config: {
type: string;

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type parameter should be constrained to the valid node types ('input' | 'output' | 'operation') instead of accepting any string, to ensure type safety and prevent invalid node types.

Suggested change
type: string;
type: 'input' | 'output' | 'operation';

Copilot uses AI. Check for mistakes.
<NextIntlClientProvider
locale={locale}
onError={(error) => {
if (error.code != "MISSING_MESSAGE") {

Copilot AI Sep 28, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use strict inequality operator (!==) instead of loose inequality (!=) for better type safety and to avoid unexpected type coercion.

Suggested change
if (error.code != "MISSING_MESSAGE") {
if (error.code !== "MISSING_MESSAGE") {

Copilot uses AI. Check for mistakes.
@Morten-Renner Morten-Renner merged commit f8f3130 into development Sep 28, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants