/** * 노드 플로우 기반 버튼 실행기 */ import { executeNodeFlow, ExecutionResult } from "../api/nodeFlows"; import { logger } from "../utils/logger"; import { toast } from "sonner"; import type { ButtonDataflowConfig, ExtendedControlContext } from "@/types/control-management"; export interface ButtonExecutionContext { buttonId: string; screenId?: number; companyCode?: string; userId?: string; formData: Record; selectedRows?: any[]; selectedRowsData?: Record[]; controlDataSource?: "form" | "table-selection" | "both"; onRefresh?: () => void; onClose?: () => void; } export interface FlowExecutionResult { success: boolean; message: string; executionTime?: number; data?: ExecutionResult; } /** * 노드 플로우 실행 함수 */ export async function executeButtonWithFlow( flowConfig: ButtonDataflowConfig["flowConfig"], context: ButtonExecutionContext, originalAction?: () => Promise, ): Promise { if (!flowConfig) { throw new Error("플로우 설정이 없습니다."); } const { flowId, flowName, executionTiming = "before" } = flowConfig; logger.info(`🚀 노드 플로우 실행 시작:`, { flowId, flowName, timing: executionTiming, contextKeys: Object.keys(context), }); try { // 컨텍스트 데이터 준비 const contextData = prepareContextData(context); // 타이밍에 따라 실행 switch (executionTiming) { case "before": // 1. 플로우 먼저 실행 const beforeResult = await executeNodeFlow(flowId, contextData); if (!beforeResult.success) { toast.error(`플로우 실행 실패: ${beforeResult.message}`); return { success: false, message: beforeResult.message, data: beforeResult, }; } toast.success(`플로우 실행 완료: ${flowName}`); // 2. 원래 버튼 액션 실행 if (originalAction) { await originalAction(); } return { success: true, message: "플로우 및 버튼 액션이 성공적으로 실행되었습니다.", executionTime: beforeResult.executionTime, data: beforeResult, }; case "after": // 1. 원래 버튼 액션 먼저 실행 if (originalAction) { await originalAction(); } // 2. 플로우 실행 const afterResult = await executeNodeFlow(flowId, contextData); if (!afterResult.success) { toast.warning(`버튼 액션은 성공했으나 플로우 실행 실패: ${afterResult.message}`); } else { toast.success(`플로우 실행 완료: ${flowName}`); } return { success: afterResult.success, message: afterResult.message, executionTime: afterResult.executionTime, data: afterResult, }; case "replace": // 플로우만 실행 (원래 액션 대체) const replaceResult = await executeNodeFlow(flowId, contextData); if (!replaceResult.success) { toast.error(`플로우 실행 실패: ${replaceResult.message}`); } else { toast.success(`플로우 실행 완료: ${flowName}`, { description: `${replaceResult.summary.success}/${replaceResult.summary.total} 노드 성공`, }); } return { success: replaceResult.success, message: replaceResult.message, executionTime: replaceResult.executionTime, data: replaceResult, }; default: throw new Error(`지원하지 않는 실행 타이밍: ${executionTiming}`); } } catch (error) { logger.error("플로우 실행 오류:", error); const errorMessage = error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다."; toast.error(`플로우 실행 오류: ${errorMessage}`); return { success: false, message: errorMessage, }; } } /** * 컨텍스트 데이터 준비 */ function prepareContextData(context: ButtonExecutionContext): Record { return { buttonId: context.buttonId, screenId: context.screenId, companyCode: context.companyCode, userId: context.userId, formData: context.formData || {}, selectedRowsData: context.selectedRowsData || [], controlDataSource: context.controlDataSource || "form", }; } /** * 플로우 실행 결과 처리 */ export function handleFlowExecutionResult(result: FlowExecutionResult, context: ButtonExecutionContext): void { if (result.success) { logger.info("✅ 플로우 실행 성공:", result); // 성공 시 데이터 새로고침 if (context.onRefresh) { context.onRefresh(); } // 실행 결과 요약 표시 if (result.data) { const { summary } = result.data; console.log("📊 플로우 실행 요약:", { 전체: summary.total, 성공: summary.success, 실패: summary.failed, 스킵: summary.skipped, 실행시간: `${result.executionTime}ms`, }); } } else { logger.error("❌ 플로우 실행 실패:", result); // 실패한 노드 정보 표시 if (result.data) { const failedNodes = result.data.nodes.filter((n) => n.status === "failed"); if (failedNodes.length > 0) { console.error("❌ 실패한 노드들:", failedNodes); } } } }