Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ node_modules
.pnp
.pnp.js
/.history

tsconfig.tsbuildinfo/
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Incorrect pattern: tsconfig.tsbuildinfo is a file, not a directory.

The trailing slash causes git to only match directories named tsconfig.tsbuildinfo/. TypeScript build info files are files, not directories. Consider using a glob pattern to ignore all such files and consolidate the duplicate entries below (lines 43, 50, 51, 52).

Suggested fix
-tsconfig.tsbuildinfo/
+*.tsbuildinfo

If you use the glob pattern, you can also remove the redundant specific entries at lines 43, 50, 51, and 52.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tsconfig.tsbuildinfo/
*.tsbuildinfo
🤖 Prompt for AI Agents
In @.gitignore at line 8, The .gitignore entry uses a directory-style pattern
"tsconfig.tsbuildinfo/" but tsconfig.tsbuildinfo is a file; replace it with a
file/glob pattern such as "**/tsconfig*.tsbuildinfo" or "tsconfig.tsbuildinfo"
(no trailing slash) to match build-info files, and remove the redundant
duplicate entries for tsconfig.tsbuildinfo found elsewhere in the file so only
the consolidated glob remains.

# Local env files
.env
.env.local
Expand Down
4 changes: 2 additions & 2 deletions apps/http-backend/src/routes/userRoutes/userRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,9 +434,9 @@ router.get(
);


router.put("/workflow/update" , userMiddleware , (req : AuthRequest , res : Response) => {
// router.put("/workflow/update" , userMiddleware , (req : AuthRequest , res : Response) => {

})
// })
// ---------------------------------------- INSERTING DATA INTO NODES/ TRIGGER TABLE-----------------------------

router.post(
Expand Down
3 changes: 2 additions & 1 deletion apps/web/app/workflows/[id]/components/ConfigModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { getNodeConfig } from "@/app/lib/nodeConfigs";
import { useState } from "react";
import { HOOKS_URL } from "@repo/common/zod";
import { userAction } from "@/store/slices/userSlice";
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

The import of userAction from "@/store/slices/userSlice" is no longer used after switching to useAppSelector. This unused import should be removed to keep the code clean.

Suggested change
import { userAction } from "@/store/slices/userSlice";

Copilot uses AI. Check for mistakes.
import { useAppSelector } from "@/app/hooks/redux";
interface ConfigModalProps {
isOpen: boolean;
selectedNode: any | null;
Expand All @@ -20,7 +21,7 @@ export default function ConfigModal({
const [loading, setLoading] = useState(false);

if (!isOpen || !selectedNode) return null;
const userId =userAction.setUserId as unknown as string;
const userId = useAppSelector((state) => state.user.userId) as unknown as string;
console.log("we are getting this userId from ConfigModal" , userId)
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

Inconsistent spacing around the comma in the console.log statement. There should be a space after the comma for standard formatting consistency.

Suggested change
console.log("we are getting this userId from ConfigModal" , userId)
console.log("we are getting this userId from ConfigModal", userId);

Copilot uses AI. Check for mistakes.
Comment on lines 23 to 25
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Hook called after conditional return violates Rules of Hooks.

useAppSelector on line 24 is called after the early return on line 23. React hooks must be called unconditionally and in the same order on every render. This will cause runtime errors or unpredictable behavior.

Move the hook call before the early return, and consider removing the unused userAction import on line 6.

Proposed fix
 export default function ConfigModal({
   isOpen,
   selectedNode,
   onClose,
   onSave,
 }: ConfigModalProps) {
   const [loading, setLoading] = useState(false);
+  const userId = useAppSelector((state) => state.user.userId) as string;

   if (!isOpen || !selectedNode) return null;
-  const userId = useAppSelector((state) => state.user.userId) as unknown as string;
   console.log("we are getting this userId from ConfigModal" , userId)

Also remove the unused import:

-import { userAction } from "@/store/slices/userSlice";
🧰 Tools
🪛 Biome (2.1.2)

[error] 24-24: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

🤖 Prompt for AI Agents
In `@apps/web/app/workflows/`[id]/components/ConfigModal.tsx around lines 23 - 25,
The hook call useAppSelector must be moved before the conditional early return
so hooks run unconditionally: call const userId = useAppSelector(...) (and any
other hooks) at the top of the ConfigModal component (before checking isOpen or
selectedNode) and then keep the if (!isOpen || !selectedNode) return null;
afterwards; also remove the unused userAction import referenced on line 6 to
avoid dead code.

const handleSave = async () => {
setLoading(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use client';

import { Handle , Position } from "@xyflow/react";
"use client";

import { Handle, Position } from "@xyflow/react";

interface PlaceholderNodeProps {
data: {
Expand All @@ -11,12 +10,12 @@ interface PlaceholderNodeProps {

export function PlaceholderNode({ data }: PlaceholderNodeProps) {
return (
<div
<div
onClick={data.onClick}
className="border-2 border-dashed border-gray-300 rounded-lg bg-gray-50 hover:bg-gray-100 hover:border-blue-400 cursor-pointer transition-all min-w-[280px]"
>
<Handle type="target" position={Position.Top} className="!bg-gray-400" />

<div className="p-8 flex flex-col items-center">
<div className="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center mb-3">
<span className="text-2xl">➕</span>
Expand Down
55 changes: 29 additions & 26 deletions apps/web/app/workflows/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,33 +58,36 @@ export default function WorkflowCanvas() {

const handleNodesChange = (changes: NodeChange[]) => {
onNodesChange(changes); // Update UI first

changes.forEach((change) => {
if (change.type === "position" && change.position) {
// Find the node in local state to check its type
const changedNode = nodes.find((n) => n.id === change.id);

if (changedNode?.data?.nodeType === "trigger") {
// If it's a trigger node, update via trigger API
api.triggers.update({
TriggerId: change.id,
Config: {
...(typeof changedNode.data.config === "object" &&
changedNode.data.config !== null
? changedNode.data.config
: {}),
try {
changes.forEach((change) => {
if (change.type === "position" && change.position) {
// Find the node in local state to check its type
const changedNode = nodes.find((n) => n.id === change.id);

if (changedNode?.data?.nodeType === "trigger") {
// If it's a trigger node, update via trigger API
api.triggers.update({
TriggerId: change.id,
Config: {
...(typeof changedNode.data.config === "object" &&
changedNode.data.config !== null
? changedNode.data.config
: {}),
position: change.position,
},
});
} else {
// Otherwise, update in node table
api.nodes.update({
NodeId: change.id,
position: change.position,
},
});
} else {
// Otherwise, update in node table
api.nodes.update({
NodeId: change.id,
position: change.position,
});
});
Comment on lines +69 to +84
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

The API calls inside handleNodesChange are not awaited. These are asynchronous operations that may fail, but without await, the try-catch block won't properly catch errors from these API calls. The errors would become unhandled promise rejections. Either add await to these API calls or handle the promises properly with .catch().

Copilot uses AI. Check for mistakes.
}
}
}
});
});
} catch (error: any) {
setError(error);
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

The error variable is typed as string (line 49) but is being set to an error object. This will cause type mismatches. Either change the error state type to Error | null or convert the error to a string using error.message.

Suggested change
setError(error);
setError(error instanceof Error ? error.message : String(error));

Copilot uses AI. Check for mistakes.
}
Comment on lines +61 to +90
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Async API calls not awaited—try/catch won't catch errors.

The api.triggers.update and api.nodes.update calls return Promises but are not awaited. The synchronous try/catch block won't catch any errors from these async operations. Additionally, forEach doesn't handle async callbacks properly.

Proposed fix using for...of with await
   const handleNodesChange = (changes: NodeChange[]) => {
     onNodesChange(changes); // Update UI first
-    try {
-      changes.forEach((change) => {
+    changes.forEach(async (change) => {
+      try {
         if (change.type === "position" && change.position) {
           // Find the node in local state to check its type
           const changedNode = nodes.find((n) => n.id === change.id);

           if (changedNode?.data?.nodeType === "trigger") {
             // If it's a trigger node, update via trigger API
-            api.triggers.update({
+            await api.triggers.update({
               TriggerId: change.id,
               Config: {
                 ...(typeof changedNode.data.config === "object" &&
                 changedNode.data.config !== null
                   ? changedNode.data.config
                   : {}),
                 position: change.position,
               },
             });
           } else {
             // Otherwise, update in node table
-            api.nodes.update({
+            await api.nodes.update({
               NodeId: change.id,
               position: change.position,
             });
           }
         }
-      });
-    } catch (error: any) {
-      setError(error);
-    }
+      } catch (error: any) {
+        setError(error.message ?? "Failed to update node position");
+      }
+    });
   };
🤖 Prompt for AI Agents
In `@apps/web/app/workflows/`[id]/page.tsx around lines 61 - 90, The loop over
changes uses forEach and calls async functions api.triggers.update and
api.nodes.update without awaiting them, so the surrounding try/catch cannot
catch rejections; replace the forEach with an async-aware loop (e.g., for...of)
or collect promises and await Promise.all, and ensure each call to
api.triggers.update or api.nodes.update is awaited so errors propagate to the
try/catch and setError(error) will be invoked; locate this logic around the
variables changes, nodes, changedNode and update the block that currently calls
api.triggers.update(...) and api.nodes.update(...) to await the returned
promises.

};
// const handleActionSelection = async (action: any) => {
// try {
Expand Down Expand Up @@ -427,7 +430,7 @@ export default function WorkflowCanvas() {
const isTrigger =
nodes.find((n) => n.id === nodeId)?.data.nodeType === "trigger";
if (isTrigger) {
await api.triggers.update({ TriggerId: nodeId, Config: config });
await api.triggers.update({ TriggerId: nodeId, Config: config});
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

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

Inconsistent spacing before the closing parenthesis. There should be a space before the closing brace for consistency with line 435 and standard formatting conventions.

Suggested change
await api.triggers.update({ TriggerId: nodeId, Config: config});
await api.triggers.update({ TriggerId: nodeId, Config: config });

Copilot uses AI. Check for mistakes.
} else {
await api.nodes.update({ NodeId: nodeId, Config: config });
}
Expand Down
Loading