PluginProbe
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services / 8.7.9
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services v8.7.9
8.7.9 8.7.8 8.7.7 8.7.6 8.7.5 8.7.4 8.7.3 8.7.2 8.7.1 8.7.0 8.6.9 8.6.8 8.6.7 8.6.6 8.6.5 8.6.4 8.6.2 8.6.1 8.6.0 8.5.9 8.5.8 8.5.7 8.5.6 8.5.5 8.5.4 All 535 releases
chatbot / addons / automator / src / components / WorkflowNode.jsx

WorkflowNode.jsx in WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services 8.7.9, at addons/automator/src/components/WorkflowNode.jsx

130 lines 4.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 "use client";
2
3 import React from "react";
4 import { X } from "lucide-react";
5
6 export function WorkflowNode({
7 node,
8 scale,
9 onDragStart,
10 onConnectionStart,
11 onConnectionEnd,
12 onDelete,
13 isSelected,
14 onClick,
15 }) {
16 const getNodeTypeLabel = () => {
17 switch (node.type) {
18 case "trigger":
19 return { label: "Trigger", color: "text-emerald-600" };
20 case "router":
21 return { label: "Router", color: "text-slate-500" };
22 case "action":
23 return { label: "Action", color: "text-primary" };
24 default:
25 return { label: "Action", color: "text-primary" };
26 }
27 };
28
29 const typeInfo = getNodeTypeLabel();
30
31 const handleMouseDownOnHandle = (e, handle) => {
32 e.stopPropagation();
33 onConnectionStart(node.id, handle);
34 };
35
36 const handleMouseUpOnHandle = (e, handle) => {
37 e.stopPropagation();
38 onConnectionEnd(node.id, handle);
39 };
40
41 return (
42 <div
43 className="absolute select-none group"
44 style={{
45 left: node.position.x * scale,
46 top: node.position.y * scale,
47 transform: `scale(${scale})`,
48 transformOrigin: "top left",
49 }}
50 >
51 {/* Type Label */}
52 <div className="flex items-center gap-2 mb-1">
53 <span className={`text-xs font-medium ${typeInfo.color}`}>
54 {typeInfo.label}
55 </span>
56 {node.actionNumber !== undefined && (
57 <span className="text-xs text-muted-foreground">
58 {node.actionNumber}
59 </span>
60 )}
61 </div>
62
63 {/* Node Card */}
64 <div className="relative">
65 {/* Left Handle - for incoming connections */}
66 <div
67 className="absolute left-0 top-1/2 -translate-x-1/2 -translate-y-1/2 w-4 h-4 rounded-full border-2 border-foreground/30 bg-card z-10 cursor-crosshair hover:border-primary hover:bg-primary/20 transition-colors"
68 onMouseDown={(e) => handleMouseDownOnHandle(e, "left")}
69 onMouseUp={(e) => handleMouseUpOnHandle(e, "left")}
70 />
71
72 {/* Delete Button */}
73 <button
74 onClick={(e) => {
75 e.stopPropagation();
76 onDelete(node.id);
77 }}
78 className="absolute -top-2 -right-2 w-5 h-5 rounded-full bg-destructive text-destructive-foreground flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity z-20 hover:bg-destructive/90"
79 >
80 <X className="w-3 h-3" />
81 </button>
82
83 {/* Node Content */}
84 <div
85 className={`flex items-center gap-3 px-4 py-3 bg-card rounded-lg border shadow-sm min-w-[180px] cursor-move transition-all ${
86 isSelected ? "border-primary ring-2 ring-primary/20" : "border-border"
87 } ${
88 node.hasError ? "ring-2 ring-destructive" : ""
89 }`}
90 onMouseDown={(e) => onDragStart(e, node.id)}
91 onClick={(e) => {
92 e.stopPropagation();
93 onClick();
94 }}
95 >
96 <div
97 className={`w-9 h-9 rounded-lg ${node.iconBg || 'bg-primary'} flex items-center justify-center text-white text-sm font-semibold flex-shrink-0`}
98 >
99 {node.icon || '⚙️'}
100 </div>
101 <div className="flex-1 min-w-0">
102 <div className="text-sm font-medium text-card-foreground truncate">
103 {node.title || node.label}
104 </div>
105 <div className="text-xs text-muted-foreground truncate">
106 {node.subtitle || node.description || "Configure action"}
107 </div>
108 </div>
109 </div>
110
111 {/* Right Handle - for outgoing connections */}
112 <div
113 className="absolute right-0 top-1/2 translate-x-1/2 -translate-y-1/2 w-4 h-4 rounded-full border-2 border-foreground/30 bg-card z-10 cursor-crosshair hover:border-primary hover:bg-primary/20 transition-colors"
114 onMouseDown={(e) => handleMouseDownOnHandle(e, "right")}
115 onMouseUp={(e) => handleMouseUpOnHandle(e, "right")}
116 />
117
118 {/* Error Badge */}
119 {node.hasError && (
120 <div className="absolute -top-2 -left-2 w-5 h-5 rounded-full bg-destructive flex items-center justify-center text-destructive-foreground text-xs font-bold z-20">
121 1
122 </div>
123 )}
124 </div>
125 </div>
126 );
127 }
128
129 export default WorkflowNode;
130