- Configure {selectedNode.name}
+
+
{selectedNode.name}
-
+ }
- {/*
- Cancel
- */}
+
{
onClose();
diff --git a/apps/web/app/workflows/[id]/page.tsx b/apps/web/app/workflows/[id]/page.tsx
index fabea2c..75240fe 100644
--- a/apps/web/app/workflows/[id]/page.tsx
+++ b/apps/web/app/workflows/[id]/page.tsx
@@ -24,15 +24,66 @@ import { getNodeConfig } from "@/app/lib/nodeConfigs";
import { useAppDispatch, useAppSelector } from "@/app/hooks/redux";
import { useAutoSave } from "@/app/hooks/useAutoSave";
import { workflowActions } from "@/store/slices/workflowSlice";
-import { store } from "@/store";
-
+import { setNodeOutput, setNodeLoading, selectAllOutputs } from "@/store/slices/nodeOutputSlice";
+import { resolveConfigVariables } from "@repo/common/zod";
export default function WorkflowCanvas() {
const params = useParams();
const workflowId = params.id as string;
const dispatch = useAppDispatch()
const reduxWorkflow = useAppSelector(s => s.workflow)
- const { saveStatus, batchSave, displayStatus } = useAutoSave(workflowId)
+ const allTestedOutputs = useAppSelector(selectAllOutputs);
+ const { batchSave, displayStatus } = useAutoSave(workflowId)
+
+
+ // context rebuilding for test function
+
+ const buildTestContext = ()=>{
+ const context: Record = {};
+ for (const [nodeId, testOutput] of Object.entries(allTestedOutputs)){
+ if(testOutput.success && testOutput.data){
+ const normalizedName = testOutput.nodeName.toLowerCase().replace(/\s+/g, '_')
+ context[normalizedName] = testOutput.data
+ }
+ }
+ return context;
+ }
+ const testNodeFromCanvas = async(nodeId: string, nodeName: string, nodeType: string)=>{
+ dispatch(setNodeLoading({nodeId: nodeId, loading: true}));
+ try{
+ const isTrigger = reduxWorkflow.data.trigger?.TriggerId === nodeId;
+ const savedConfig = isTrigger ? reduxWorkflow.data.trigger?.Config :
+ reduxWorkflow.data.nodes.find(n=> n.NodeId === nodeId)?.Config ;
+ console.log(savedConfig, "-- from 57852")
+ const interpolationContext = buildTestContext();
+ const resolvedConfig = resolveConfigVariables(savedConfig, interpolationContext);
+ console.log(resolvedConfig, "--from 60")
+ const response = await api.execute.node(nodeId,resolvedConfig);
+ dispatch(setNodeOutput({
+ nodeId: nodeId,
+ nodeName: nodeName,
+ nodeType: nodeType,
+ data: response,
+ testedAt: Date.now(),
+ success: true,
+ variables: []
+ }))
+ toast.success(`Tested ${nodeName} successfully!`);
+ }catch(err: any){
+ console.log(err, "from 73")
+ toast.error(`Test failed: ${err.message}`);
+ dispatch(setNodeOutput({
+ nodeId,
+ nodeName,
+ nodeType,
+ data: null,
+ variables: [],
+ testedAt: Date.now(),
+ success: false,
+ error: err.message
+ }));
+ }
+ }
const getPreviousNodes = (
selectedNodeId: string,
allNodes: Node[],
@@ -163,7 +214,6 @@ export default function WorkflowCanvas() {
setError("No trigger found in workflow data, so start with selecting the trigger for the workflow");
return;
}
-
const triggerPosition = ensurePosition(trigger.position, DEFAULT_TRIGGER_POSITION )
const triggerNode = {
id: trigger.TriggerId,
@@ -171,17 +221,20 @@ export default function WorkflowCanvas() {
position: triggerPosition,
data: {
label: trigger.name || "Trigger",
- icon: "⚡", // add icon field in redux and db
+ icon: trigger.icon || "⚡", // add icon field in redux and db
nodeType: "trigger",
isConfigured: checkIsConfigure(trigger.name, trigger.Config),
onConfigure: () =>
handleNodeConfigure({
id: trigger.TriggerId,
- name: trigger.name
+ name: trigger.name,
+ icon: trigger.icon
}),
+ onTest: ( trigger.name.toLowerCase().includes('webhook') ? undefined : ()=> testNodeFromCanvas(trigger.TriggerId, trigger.name, "trigger") ),
},
};
+ console.log(JSON.stringify(reduxNodes), "from 236")
const transformedNodes = reduxNodes.map((node) =>({
id: node.NodeId,
type: "customNode",
@@ -191,7 +244,7 @@ export default function WorkflowCanvas() {
}),
data: {
label: node.name || "Unknown",
- icon: "⚙️", // icon add to db and redux
+ icon: node.icon || "⚙️",
nodeType: "action",
isConfigured: checkIsConfigure(node.name, node.Config),
onConfigure: () =>
@@ -200,7 +253,9 @@ export default function WorkflowCanvas() {
name: node.name,
type: "action",
actionType: node.AvailableNodeID,
+ icon: node.icon
}),
+ onTest: ()=> testNodeFromCanvas(node.NodeId, node.name, "action")
}
}))
@@ -282,6 +337,7 @@ export default function WorkflowCanvas() {
TriggerId: Trigger.id,
name: Trigger.name,
type: Trigger.type,
+ icon: Trigger.icon,
Config: Trigger.config || {},
position: Trigger.Position || DEFAULT_TRIGGER_POSITION,
AvailableTriggerID: Trigger.AvailableTriggerID
@@ -290,6 +346,7 @@ export default function WorkflowCanvas() {
NodeId: n.id,
name: n.name,
type: n.type,
+ icon: n.icon,
Config: n.config || {},
position: n.position || { x: 0, y: 0 },
stage: n.stage,
@@ -309,14 +366,17 @@ export default function WorkflowCanvas() {
position: triggerPosition,
data: {
label: Trigger.name || Trigger.data?.label || "Trigger",
- icon: Trigger.data?.icon || "⚡",
+ icon: Trigger?.icon || "⚡",
nodeType: "trigger",
isConfigured: checkIsConfigure(Trigger.name, Trigger.config || {}),
onConfigure: () =>
handleNodeConfigure({
id: Trigger.id,
- name: Trigger.name
+ name: Trigger.name,
+ icon: Trigger.icon
}),
+ onTest: ( Trigger.name.toLowerCase() === 'webhook' ? undefined : ()=> testNodeFromCanvas(Trigger.TriggerId, Trigger.name, "trigger") )
+
},
};
@@ -330,7 +390,7 @@ export default function WorkflowCanvas() {
}),
data: {
label: node.data?.label || node.name || "Unknown",
- icon: node.data?.icon || "⚙️",
+ icon: node.icon || "⚙️",
nodeType: "action",
isConfigured: checkIsConfigure(node.name || node.data?.label, node.config || {}),
onConfigure: () =>
@@ -338,8 +398,10 @@ export default function WorkflowCanvas() {
id: node.id,
name: node.data?.label || node.name,
type: "action",
+ icon: node.icon,
actionType: node.AvailableNodeId,
}),
+ onTest: ()=> testNodeFromCanvas(node.NodeId, node.name, "action")
},
}));
@@ -514,6 +576,7 @@ export default function WorkflowCanvas() {
name: action.name,
type: action.type,
Config: {},
+ icon: "",
position: newNodePosition,
stage: nextIndex,
AvailableNodeID: action.id
@@ -536,7 +599,9 @@ export default function WorkflowCanvas() {
name: action.name,
type: "action",
actionType: action.id,
+ icon: action.icon
}),
+ onTest: ()=> testNodeFromCanvas(action.NodeId, action.name, "action")
},
};
@@ -626,7 +691,10 @@ export default function WorkflowCanvas() {
id: triggerId,
name: trigger.name,
type: "trigger",
+ icon: trigger.icon
}),
+ onTest: ( trigger.name.toLowerCase() === 'webhook' ? undefined : ()=> testNodeFromCanvas(trigger.TriggerId, trigger.name, "trigger") )
+
},
};
@@ -660,6 +728,7 @@ export default function WorkflowCanvas() {
name: trigger.name,
type: trigger.type,
Config: {},
+ icon: "",
position: DEFAULT_TRIGGER_POSITION,
AvailableTriggerID: trigger.id
}))
diff --git a/apps/web/public/gmail.png b/apps/web/public/gmail.png
new file mode 100644
index 0000000..2563f6f
Binary files /dev/null and b/apps/web/public/gmail.png differ
diff --git a/apps/web/public/google_sheet.png b/apps/web/public/google_sheet.png
new file mode 100644
index 0000000..4cebb64
Binary files /dev/null and b/apps/web/public/google_sheet.png differ
diff --git a/apps/web/public/webhook.png b/apps/web/public/webhook.png
new file mode 100644
index 0000000..7f21304
Binary files /dev/null and b/apps/web/public/webhook.png differ
diff --git a/apps/web/public/webhook1.png b/apps/web/public/webhook1.png
new file mode 100644
index 0000000..80d5041
Binary files /dev/null and b/apps/web/public/webhook1.png differ
diff --git a/apps/web/store/slices/workflowSlice.ts b/apps/web/store/slices/workflowSlice.ts
index b4a42af..164eed4 100644
--- a/apps/web/store/slices/workflowSlice.ts
+++ b/apps/web/store/slices/workflowSlice.ts
@@ -3,6 +3,7 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
interface Trigger {
TriggerId: string;
name: string;
+ icon: string | null;
type: string;
Config: any;
position: Position;
@@ -16,6 +17,7 @@ interface Position {
interface NodeItem {
NodeId: string;
name: string;
+ icon: string | null;
type: string;
Config: any;
position: Position;
diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma
index 9b2a62a..babf97c 100644
--- a/packages/db/prisma/schema.prisma
+++ b/packages/db/prisma/schema.prisma
@@ -36,8 +36,8 @@ model Trigger {
config Json?
workflowId String? @unique
AvailableTriggerID String
- Position Json?
CredentialsID String?
+ Position Json?
triggerType AvailableTrigger @relation(fields: [AvailableTriggerID], references: [id])
Credential Credential? @relation(fields: [CredentialsID], references: [id])
workflow Workflow? @relation(fields: [workflowId], references: [id])
@@ -48,6 +48,7 @@ model AvailableTrigger {
name String
type String @unique
config Json
+ icon String?
triggers Trigger[]
}
@@ -59,6 +60,7 @@ model AvailableNode {
authType String?
requireAuth Boolean?
description String?
+ icon String?
Node Node[]
}