"use client"; /** * 스크립트 실행 노드 속성 편집 */ import { useEffect, useState, useCallback } from "react"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Switch } from "@/components/ui/switch"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Card, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Plus, Trash2, Terminal, FileCode, Settings, Play } from "lucide-react"; import { useFlowEditorStore } from "@/lib/stores/flowEditorStore"; import type { ScriptActionNodeData } from "@/types/node-editor"; interface ScriptActionPropertiesProps { nodeId: string; data: ScriptActionNodeData; } export function ScriptActionProperties({ nodeId, data }: ScriptActionPropertiesProps) { const { updateNode } = useFlowEditorStore(); // 로컬 상태 const [displayName, setDisplayName] = useState(data.displayName || "스크립트 실행"); const [scriptType, setScriptType] = useState(data.scriptType || "python"); const [executionMode, setExecutionMode] = useState<"inline" | "file">(data.executionMode || "inline"); const [inlineScript, setInlineScript] = useState(data.inlineScript || ""); const [scriptPath, setScriptPath] = useState(data.scriptPath || ""); const [executablePath, setExecutablePath] = useState(data.executablePath || ""); const [inputMethod, setInputMethod] = useState(data.inputMethod || "stdin"); const [inputFormat, setInputFormat] = useState<"json" | "csv" | "text">(data.inputFormat || "json"); const [workingDirectory, setWorkingDirectory] = useState(data.workingDirectory || ""); const [timeout, setTimeout] = useState(data.options?.timeout?.toString() || "60000"); const [maxBuffer, setMaxBuffer] = useState(data.options?.maxBuffer?.toString() || "1048576"); const [shell, setShell] = useState(data.options?.shell || ""); const [captureStdout, setCaptureStdout] = useState(data.outputHandling?.captureStdout ?? true); const [captureStderr, setCaptureStderr] = useState(data.outputHandling?.captureStderr ?? true); const [parseOutput, setParseOutput] = useState<"json" | "lines" | "text">(data.outputHandling?.parseOutput || "text"); // 환경변수 const [envVars, setEnvVars] = useState>( Object.entries(data.environmentVariables || {}).map(([key, value]) => ({ key, value })) ); // 명령줄 인자 const [args, setArgs] = useState(data.arguments || []); // 데이터 변경 시 로컬 상태 동기화 useEffect(() => { setDisplayName(data.displayName || "스크립트 실행"); setScriptType(data.scriptType || "python"); setExecutionMode(data.executionMode || "inline"); setInlineScript(data.inlineScript || ""); setScriptPath(data.scriptPath || ""); setExecutablePath(data.executablePath || ""); setInputMethod(data.inputMethod || "stdin"); setInputFormat(data.inputFormat || "json"); setWorkingDirectory(data.workingDirectory || ""); setTimeout(data.options?.timeout?.toString() || "60000"); setMaxBuffer(data.options?.maxBuffer?.toString() || "1048576"); setShell(data.options?.shell || ""); setCaptureStdout(data.outputHandling?.captureStdout ?? true); setCaptureStderr(data.outputHandling?.captureStderr ?? true); setParseOutput(data.outputHandling?.parseOutput || "text"); setEnvVars(Object.entries(data.environmentVariables || {}).map(([key, value]) => ({ key, value }))); setArgs(data.arguments || []); }, [data]); // 노드 업데이트 함수 const updateNodeData = useCallback( (updates: Partial) => { updateNode(nodeId, { ...data, ...updates, }); }, [nodeId, data, updateNode] ); // 표시명 변경 const handleDisplayNameChange = (value: string) => { setDisplayName(value); updateNodeData({ displayName: value }); }; // 스크립트 타입 변경 const handleScriptTypeChange = (value: ScriptActionNodeData["scriptType"]) => { setScriptType(value); updateNodeData({ scriptType: value }); }; // 실행 모드 변경 const handleExecutionModeChange = (value: "inline" | "file") => { setExecutionMode(value); updateNodeData({ executionMode: value }); }; // 스크립트 내용 업데이트 const updateScriptContent = useCallback(() => { updateNodeData({ inlineScript, scriptPath, executablePath, }); }, [inlineScript, scriptPath, executablePath, updateNodeData]); // 입력 설정 업데이트 const updateInputSettings = useCallback(() => { updateNodeData({ inputMethod, inputFormat, workingDirectory: workingDirectory || undefined, }); }, [inputMethod, inputFormat, workingDirectory, updateNodeData]); // 옵션 업데이트 const updateOptions = useCallback(() => { updateNodeData({ options: { timeout: parseInt(timeout) || 60000, maxBuffer: parseInt(maxBuffer) || 1048576, shell: shell || undefined, }, }); }, [timeout, maxBuffer, shell, updateNodeData]); // 출력 처리 업데이트 const updateOutputHandling = useCallback(() => { updateNodeData({ outputHandling: { captureStdout, captureStderr, parseOutput, }, }); }, [captureStdout, captureStderr, parseOutput, updateNodeData]); // 환경변수 추가 const addEnvVar = () => { const newEnvVars = [...envVars, { key: "", value: "" }]; setEnvVars(newEnvVars); }; // 환경변수 삭제 const removeEnvVar = (index: number) => { const newEnvVars = envVars.filter((_, i) => i !== index); setEnvVars(newEnvVars); const envObj = Object.fromEntries(newEnvVars.filter(e => e.key).map(e => [e.key, e.value])); updateNodeData({ environmentVariables: envObj }); }; // 환경변수 업데이트 const updateEnvVar = (index: number, field: "key" | "value", value: string) => { const newEnvVars = [...envVars]; newEnvVars[index][field] = value; setEnvVars(newEnvVars); }; // 환경변수 저장 const saveEnvVars = () => { const envObj = Object.fromEntries(envVars.filter(e => e.key).map(e => [e.key, e.value])); updateNodeData({ environmentVariables: envObj }); }; // 인자 추가 const addArg = () => { const newArgs = [...args, ""]; setArgs(newArgs); }; // 인자 삭제 const removeArg = (index: number) => { const newArgs = args.filter((_, i) => i !== index); setArgs(newArgs); updateNodeData({ arguments: newArgs }); }; // 인자 업데이트 const updateArg = (index: number, value: string) => { const newArgs = [...args]; newArgs[index] = value; setArgs(newArgs); }; // 인자 저장 const saveArgs = () => { updateNodeData({ arguments: args.filter(a => a) }); }; // 스크립트 타입별 기본 스크립트 템플릿 const getScriptTemplate = (type: string) => { switch (type) { case "python": return `import sys import json # 입력 데이터 읽기 (stdin) input_data = json.loads(sys.stdin.read()) # 처리 로직 result = { "status": "success", "data": input_data } # 결과 출력 print(json.dumps(result))`; case "shell": return `#!/bin/bash # 입력 데이터 읽기 INPUT=$(cat) # 처리 로직 echo "입력 데이터: $INPUT" # 결과 출력 echo '{"status": "success"}'`; case "powershell": return `# 입력 데이터 읽기 $input = $input | ConvertFrom-Json # 처리 로직 $result = @{ status = "success" data = $input } # 결과 출력 $result | ConvertTo-Json`; case "node": return `const readline = require('readline'); let input = ''; process.stdin.on('data', (chunk) => { input += chunk; }); process.stdin.on('end', () => { const data = JSON.parse(input); // 처리 로직 const result = { status: 'success', data: data }; console.log(JSON.stringify(result)); });`; default: return ""; } }; return (
{/* 표시명 */}
handleDisplayNameChange(e.target.value)} placeholder="스크립트 실행" className="h-8 text-sm" />
{/* 스크립트 타입 */}
{/* 실행 모드 */}
스크립트 입력 환경 출력 {/* 스크립트 탭 */} {executionMode === "inline" ? (