251205:0000 Just start debug backend/frontend

This commit is contained in:
2025-12-05 00:32:02 +07:00
parent dc8b80c5f9
commit 2865bebdb1
88 changed files with 6751 additions and 1016 deletions

View File

@@ -0,0 +1,115 @@
"use client";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { CheckCircle, AlertCircle, Play, Loader2 } from "lucide-react";
import Editor from "@monaco-editor/react";
import { workflowApi } from "@/lib/api/workflows";
import { ValidationResult } from "@/types/workflow";
interface DSLEditorProps {
initialValue?: string;
onChange?: (value: string) => void;
}
export function DSLEditor({ initialValue = "", onChange }: DSLEditorProps) {
const [dsl, setDsl] = useState(initialValue);
const [validationResult, setValidationResult] = useState<ValidationResult | null>(null);
const [isValidating, setIsValidating] = useState(false);
const handleEditorChange = (value: string | undefined) => {
const newValue = value || "";
setDsl(newValue);
onChange?.(newValue);
setValidationResult(null); // Clear validation on change
};
const validateDSL = async () => {
setIsValidating(true);
try {
const result = await workflowApi.validateDSL(dsl);
setValidationResult(result);
} catch (error) {
console.error(error);
setValidationResult({ valid: false, errors: ["Validation failed due to an error"] });
} finally {
setIsValidating(false);
}
};
const testWorkflow = async () => {
alert("Test workflow functionality to be implemented");
};
return (
<div className="space-y-4">
<div className="flex justify-between items-center">
<h3 className="text-lg font-semibold">Workflow DSL</h3>
<div className="flex gap-2">
<Button
variant="outline"
onClick={validateDSL}
disabled={isValidating}
>
{isValidating ? (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
) : (
<CheckCircle className="mr-2 h-4 w-4" />
)}
Validate
</Button>
<Button variant="outline" onClick={testWorkflow}>
<Play className="mr-2 h-4 w-4" />
Test
</Button>
</div>
</div>
<Card className="overflow-hidden border rounded-md">
<Editor
height="500px"
defaultLanguage="yaml"
value={dsl}
onChange={handleEditorChange}
theme="vs-dark"
options={{
minimap: { enabled: false },
fontSize: 14,
lineNumbers: "on",
rulers: [80],
wordWrap: "on",
scrollBeyondLastLine: false,
}}
/>
</Card>
{validationResult && (
<Alert variant={validationResult.valid ? "default" : "destructive"} className={validationResult.valid ? "border-green-500 text-green-700 bg-green-50" : ""}>
{validationResult.valid ? (
<CheckCircle className="h-4 w-4 text-green-600" />
) : (
<AlertCircle className="h-4 w-4" />
)}
<AlertDescription>
{validationResult.valid ? (
"DSL is valid ✓"
) : (
<div>
<p className="font-medium mb-2">Validation Errors:</p>
<ul className="list-disc list-inside space-y-1">
{validationResult.errors?.map((error: string, i: number) => (
<li key={i} className="text-sm">
{error}
</li>
))}
</ul>
</div>
)}
</AlertDescription>
</Alert>
)}
</div>
);
}

View File

@@ -0,0 +1,109 @@
"use client";
import { useCallback } from "react";
import ReactFlow, {
Node,
Edge,
Controls,
Background,
useNodesState,
useEdgesState,
addEdge,
Connection,
} from "reactflow";
import "reactflow/dist/style.css";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
const nodeTypes = {
// We can define custom node types here if needed
};
// Color mapping for node types
const nodeColors: Record<string, string> = {
start: "#10b981", // green
step: "#3b82f6", // blue
condition: "#f59e0b", // amber
end: "#ef4444", // red
};
export function VisualWorkflowBuilder() {
const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
const onConnect = useCallback(
(params: Connection) => setEdges((eds) => addEdge(params, eds)),
[setEdges]
);
const addNode = (type: string) => {
const newNode: Node = {
id: `${type}-${Date.now()}`,
type: "default", // Using default node type for now
position: { x: Math.random() * 400, y: Math.random() * 400 },
data: { label: `${type.charAt(0).toUpperCase() + type.slice(1)} Node` },
style: {
background: nodeColors[type] || "#64748b",
color: "white",
padding: 10,
borderRadius: 5,
border: "1px solid #fff",
width: 150,
},
};
setNodes((nds) => [...nds, newNode]);
};
const generateDSL = () => {
// Convert visual workflow to DSL (Mock implementation)
const dsl = {
name: "Generated Workflow",
steps: nodes.map((node) => ({
step_name: node.data.label,
step_type: "APPROVAL",
})),
connections: edges.map((edge) => ({
from: edge.source,
to: edge.target,
})),
};
alert(JSON.stringify(dsl, null, 2));
};
return (
<div className="space-y-4">
<div className="flex gap-2 flex-wrap">
<Button onClick={() => addNode("start")} variant="outline" size="sm" className="border-green-500 text-green-600 hover:bg-green-50">
Add Start
</Button>
<Button onClick={() => addNode("step")} variant="outline" size="sm" className="border-blue-500 text-blue-600 hover:bg-blue-50">
Add Step
</Button>
<Button onClick={() => addNode("condition")} variant="outline" size="sm" className="border-amber-500 text-amber-600 hover:bg-amber-50">
Add Condition
</Button>
<Button onClick={() => addNode("end")} variant="outline" size="sm" className="border-red-500 text-red-600 hover:bg-red-50">
Add End
</Button>
<Button onClick={generateDSL} className="ml-auto" size="sm">
Generate DSL
</Button>
</div>
<Card className="h-[600px] border">
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
nodeTypes={nodeTypes}
fitView
>
<Controls />
<Background color="#aaa" gap={16} />
</ReactFlow>
</Card>
</div>
);
}