ERP-node/frontend/components/screen/config-panels/ImprovedButtonControlConfig...

360 lines
12 KiB
TypeScript
Raw Normal View History

2025-09-29 12:17:10 +09:00
"use client";
2025-12-12 18:28:58 +09:00
import React, { useState, useEffect, useCallback } from "react";
2025-09-29 12:17:10 +09:00
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Switch } from "@/components/ui/switch";
import { Separator } from "@/components/ui/separator";
2025-12-12 18:28:58 +09:00
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Settings, Clock, Info, Workflow, Plus, Trash2, GripVertical, ChevronUp, ChevronDown } from "lucide-react";
feat: 노드 기반 데이터 플로우 시스템 구현 - 노드 에디터 UI 구현 (React Flow 기반) - TableSource, DataTransform, INSERT, UPDATE, DELETE, UPSERT 노드 - 드래그앤드롭 노드 추가 및 연결 - 속성 패널을 통한 노드 설정 - 실시간 필드 라벨 표시 (column_labels 테이블 연동) - 데이터 변환 노드 (DataTransform) 기능 - EXPLODE: 구분자로 1개 행 → 여러 행 확장 - UPPERCASE, LOWERCASE, TRIM, CONCAT, SPLIT, REPLACE 등 12가지 변환 타입 - In-place 변환 지원 (타겟 필드 생략 시 소스 필드 덮어쓰기) - 변환된 필드가 하위 액션 노드에 자동 전달 - 노드 플로우 실행 엔진 - 위상 정렬을 통한 노드 실행 순서 결정 - 레벨별 병렬 실행 (Promise.allSettled) - 부분 실패 허용 (한 노드 실패 시 연결된 하위 노드만 스킵) - 트랜잭션 기반 안전한 데이터 처리 - UPSERT 액션 로직 구현 - DB 제약 조건 없이 SELECT → UPDATE or INSERT 방식 - 복합 충돌 키 지원 (예: sales_no + product_name) - 파라미터 인덱스 정확한 매핑 - 데이터 소스 자동 감지 - 테이블 선택 데이터 (selectedRowsData) 자동 주입 - 폼 입력 데이터 (formData) 자동 주입 - TableSource 노드가 외부 데이터 우선 사용 - 버튼 컴포넌트 통합 - 기존 관계 실행 + 새 노드 플로우 실행 하이브리드 지원 - 노드 플로우 선택 UI 추가 - API 클라이언트 통합 (Axios) - 개발 문서 작성 - 노드 기반 제어 시스템 개선 계획 - 노드 연결 규칙 설계 - 노드 실행 엔진 설계 - 노드 구조 개선안 - 버튼 통합 분석
2025-10-02 16:22:29 +09:00
import { ComponentData } from "@/types/screen";
import { getNodeFlows, NodeFlow } from "@/lib/api/nodeFlows";
2025-09-29 12:17:10 +09:00
interface ImprovedButtonControlConfigPanelProps {
component: ComponentData;
onUpdateProperty: (path: string, value: any) => void;
}
2025-12-12 18:28:58 +09:00
// 다중 제어 설정 인터페이스
interface FlowControlConfig {
id: string;
flowId: number;
flowName: string;
executionTiming: "before" | "after" | "replace";
order: number;
}
2025-09-29 12:17:10 +09:00
/**
2025-12-12 18:28:58 +09:00
* 🔥
feat: 노드 기반 데이터 플로우 시스템 구현 - 노드 에디터 UI 구현 (React Flow 기반) - TableSource, DataTransform, INSERT, UPDATE, DELETE, UPSERT 노드 - 드래그앤드롭 노드 추가 및 연결 - 속성 패널을 통한 노드 설정 - 실시간 필드 라벨 표시 (column_labels 테이블 연동) - 데이터 변환 노드 (DataTransform) 기능 - EXPLODE: 구분자로 1개 행 → 여러 행 확장 - UPPERCASE, LOWERCASE, TRIM, CONCAT, SPLIT, REPLACE 등 12가지 변환 타입 - In-place 변환 지원 (타겟 필드 생략 시 소스 필드 덮어쓰기) - 변환된 필드가 하위 액션 노드에 자동 전달 - 노드 플로우 실행 엔진 - 위상 정렬을 통한 노드 실행 순서 결정 - 레벨별 병렬 실행 (Promise.allSettled) - 부분 실패 허용 (한 노드 실패 시 연결된 하위 노드만 스킵) - 트랜잭션 기반 안전한 데이터 처리 - UPSERT 액션 로직 구현 - DB 제약 조건 없이 SELECT → UPDATE or INSERT 방식 - 복합 충돌 키 지원 (예: sales_no + product_name) - 파라미터 인덱스 정확한 매핑 - 데이터 소스 자동 감지 - 테이블 선택 데이터 (selectedRowsData) 자동 주입 - 폼 입력 데이터 (formData) 자동 주입 - TableSource 노드가 외부 데이터 우선 사용 - 버튼 컴포넌트 통합 - 기존 관계 실행 + 새 노드 플로우 실행 하이브리드 지원 - 노드 플로우 선택 UI 추가 - API 클라이언트 통합 (Axios) - 개발 문서 작성 - 노드 기반 제어 시스템 개선 계획 - 노드 연결 규칙 설계 - 노드 실행 엔진 설계 - 노드 구조 개선안 - 버튼 통합 분석
2025-10-02 16:22:29 +09:00
*
2025-12-12 18:28:58 +09:00
* :
* -
* -
* -
2025-09-29 12:17:10 +09:00
*/
export const ImprovedButtonControlConfigPanel: React.FC<ImprovedButtonControlConfigPanelProps> = ({
component,
onUpdateProperty,
}) => {
const config = component.webTypeConfig || {};
const dataflowConfig = config.dataflowConfig || {};
2025-12-12 18:28:58 +09:00
// 다중 제어 설정 (배열)
const flowControls: FlowControlConfig[] = dataflowConfig.flowControls || [];
2025-09-29 12:17:10 +09:00
// 🔥 State 관리
feat: 노드 기반 데이터 플로우 시스템 구현 - 노드 에디터 UI 구현 (React Flow 기반) - TableSource, DataTransform, INSERT, UPDATE, DELETE, UPSERT 노드 - 드래그앤드롭 노드 추가 및 연결 - 속성 패널을 통한 노드 설정 - 실시간 필드 라벨 표시 (column_labels 테이블 연동) - 데이터 변환 노드 (DataTransform) 기능 - EXPLODE: 구분자로 1개 행 → 여러 행 확장 - UPPERCASE, LOWERCASE, TRIM, CONCAT, SPLIT, REPLACE 등 12가지 변환 타입 - In-place 변환 지원 (타겟 필드 생략 시 소스 필드 덮어쓰기) - 변환된 필드가 하위 액션 노드에 자동 전달 - 노드 플로우 실행 엔진 - 위상 정렬을 통한 노드 실행 순서 결정 - 레벨별 병렬 실행 (Promise.allSettled) - 부분 실패 허용 (한 노드 실패 시 연결된 하위 노드만 스킵) - 트랜잭션 기반 안전한 데이터 처리 - UPSERT 액션 로직 구현 - DB 제약 조건 없이 SELECT → UPDATE or INSERT 방식 - 복합 충돌 키 지원 (예: sales_no + product_name) - 파라미터 인덱스 정확한 매핑 - 데이터 소스 자동 감지 - 테이블 선택 데이터 (selectedRowsData) 자동 주입 - 폼 입력 데이터 (formData) 자동 주입 - TableSource 노드가 외부 데이터 우선 사용 - 버튼 컴포넌트 통합 - 기존 관계 실행 + 새 노드 플로우 실행 하이브리드 지원 - 노드 플로우 선택 UI 추가 - API 클라이언트 통합 (Axios) - 개발 문서 작성 - 노드 기반 제어 시스템 개선 계획 - 노드 연결 규칙 설계 - 노드 실행 엔진 설계 - 노드 구조 개선안 - 버튼 통합 분석
2025-10-02 16:22:29 +09:00
const [flows, setFlows] = useState<NodeFlow[]>([]);
2025-09-29 12:17:10 +09:00
const [loading, setLoading] = useState(false);
feat: 노드 기반 데이터 플로우 시스템 구현 - 노드 에디터 UI 구현 (React Flow 기반) - TableSource, DataTransform, INSERT, UPDATE, DELETE, UPSERT 노드 - 드래그앤드롭 노드 추가 및 연결 - 속성 패널을 통한 노드 설정 - 실시간 필드 라벨 표시 (column_labels 테이블 연동) - 데이터 변환 노드 (DataTransform) 기능 - EXPLODE: 구분자로 1개 행 → 여러 행 확장 - UPPERCASE, LOWERCASE, TRIM, CONCAT, SPLIT, REPLACE 등 12가지 변환 타입 - In-place 변환 지원 (타겟 필드 생략 시 소스 필드 덮어쓰기) - 변환된 필드가 하위 액션 노드에 자동 전달 - 노드 플로우 실행 엔진 - 위상 정렬을 통한 노드 실행 순서 결정 - 레벨별 병렬 실행 (Promise.allSettled) - 부분 실패 허용 (한 노드 실패 시 연결된 하위 노드만 스킵) - 트랜잭션 기반 안전한 데이터 처리 - UPSERT 액션 로직 구현 - DB 제약 조건 없이 SELECT → UPDATE or INSERT 방식 - 복합 충돌 키 지원 (예: sales_no + product_name) - 파라미터 인덱스 정확한 매핑 - 데이터 소스 자동 감지 - 테이블 선택 데이터 (selectedRowsData) 자동 주입 - 폼 입력 데이터 (formData) 자동 주입 - TableSource 노드가 외부 데이터 우선 사용 - 버튼 컴포넌트 통합 - 기존 관계 실행 + 새 노드 플로우 실행 하이브리드 지원 - 노드 플로우 선택 UI 추가 - API 클라이언트 통합 (Axios) - 개발 문서 작성 - 노드 기반 제어 시스템 개선 계획 - 노드 연결 규칙 설계 - 노드 실행 엔진 설계 - 노드 구조 개선안 - 버튼 통합 분석
2025-10-02 16:22:29 +09:00
// 🔥 플로우 목록 로딩
2025-09-29 12:17:10 +09:00
useEffect(() => {
if (config.enableDataflowControl) {
feat: 노드 기반 데이터 플로우 시스템 구현 - 노드 에디터 UI 구현 (React Flow 기반) - TableSource, DataTransform, INSERT, UPDATE, DELETE, UPSERT 노드 - 드래그앤드롭 노드 추가 및 연결 - 속성 패널을 통한 노드 설정 - 실시간 필드 라벨 표시 (column_labels 테이블 연동) - 데이터 변환 노드 (DataTransform) 기능 - EXPLODE: 구분자로 1개 행 → 여러 행 확장 - UPPERCASE, LOWERCASE, TRIM, CONCAT, SPLIT, REPLACE 등 12가지 변환 타입 - In-place 변환 지원 (타겟 필드 생략 시 소스 필드 덮어쓰기) - 변환된 필드가 하위 액션 노드에 자동 전달 - 노드 플로우 실행 엔진 - 위상 정렬을 통한 노드 실행 순서 결정 - 레벨별 병렬 실행 (Promise.allSettled) - 부분 실패 허용 (한 노드 실패 시 연결된 하위 노드만 스킵) - 트랜잭션 기반 안전한 데이터 처리 - UPSERT 액션 로직 구현 - DB 제약 조건 없이 SELECT → UPDATE or INSERT 방식 - 복합 충돌 키 지원 (예: sales_no + product_name) - 파라미터 인덱스 정확한 매핑 - 데이터 소스 자동 감지 - 테이블 선택 데이터 (selectedRowsData) 자동 주입 - 폼 입력 데이터 (formData) 자동 주입 - TableSource 노드가 외부 데이터 우선 사용 - 버튼 컴포넌트 통합 - 기존 관계 실행 + 새 노드 플로우 실행 하이브리드 지원 - 노드 플로우 선택 UI 추가 - API 클라이언트 통합 (Axios) - 개발 문서 작성 - 노드 기반 제어 시스템 개선 계획 - 노드 연결 규칙 설계 - 노드 실행 엔진 설계 - 노드 구조 개선안 - 버튼 통합 분석
2025-10-02 16:22:29 +09:00
loadFlows();
2025-09-29 12:17:10 +09:00
}
}, [config.enableDataflowControl]);
/**
feat: 노드 기반 데이터 플로우 시스템 구현 - 노드 에디터 UI 구현 (React Flow 기반) - TableSource, DataTransform, INSERT, UPDATE, DELETE, UPSERT 노드 - 드래그앤드롭 노드 추가 및 연결 - 속성 패널을 통한 노드 설정 - 실시간 필드 라벨 표시 (column_labels 테이블 연동) - 데이터 변환 노드 (DataTransform) 기능 - EXPLODE: 구분자로 1개 행 → 여러 행 확장 - UPPERCASE, LOWERCASE, TRIM, CONCAT, SPLIT, REPLACE 등 12가지 변환 타입 - In-place 변환 지원 (타겟 필드 생략 시 소스 필드 덮어쓰기) - 변환된 필드가 하위 액션 노드에 자동 전달 - 노드 플로우 실행 엔진 - 위상 정렬을 통한 노드 실행 순서 결정 - 레벨별 병렬 실행 (Promise.allSettled) - 부분 실패 허용 (한 노드 실패 시 연결된 하위 노드만 스킵) - 트랜잭션 기반 안전한 데이터 처리 - UPSERT 액션 로직 구현 - DB 제약 조건 없이 SELECT → UPDATE or INSERT 방식 - 복합 충돌 키 지원 (예: sales_no + product_name) - 파라미터 인덱스 정확한 매핑 - 데이터 소스 자동 감지 - 테이블 선택 데이터 (selectedRowsData) 자동 주입 - 폼 입력 데이터 (formData) 자동 주입 - TableSource 노드가 외부 데이터 우선 사용 - 버튼 컴포넌트 통합 - 기존 관계 실행 + 새 노드 플로우 실행 하이브리드 지원 - 노드 플로우 선택 UI 추가 - API 클라이언트 통합 (Axios) - 개발 문서 작성 - 노드 기반 제어 시스템 개선 계획 - 노드 연결 규칙 설계 - 노드 실행 엔진 설계 - 노드 구조 개선안 - 버튼 통합 분석
2025-10-02 16:22:29 +09:00
* 🔥
2025-09-29 12:17:10 +09:00
*/
feat: 노드 기반 데이터 플로우 시스템 구현 - 노드 에디터 UI 구현 (React Flow 기반) - TableSource, DataTransform, INSERT, UPDATE, DELETE, UPSERT 노드 - 드래그앤드롭 노드 추가 및 연결 - 속성 패널을 통한 노드 설정 - 실시간 필드 라벨 표시 (column_labels 테이블 연동) - 데이터 변환 노드 (DataTransform) 기능 - EXPLODE: 구분자로 1개 행 → 여러 행 확장 - UPPERCASE, LOWERCASE, TRIM, CONCAT, SPLIT, REPLACE 등 12가지 변환 타입 - In-place 변환 지원 (타겟 필드 생략 시 소스 필드 덮어쓰기) - 변환된 필드가 하위 액션 노드에 자동 전달 - 노드 플로우 실행 엔진 - 위상 정렬을 통한 노드 실행 순서 결정 - 레벨별 병렬 실행 (Promise.allSettled) - 부분 실패 허용 (한 노드 실패 시 연결된 하위 노드만 스킵) - 트랜잭션 기반 안전한 데이터 처리 - UPSERT 액션 로직 구현 - DB 제약 조건 없이 SELECT → UPDATE or INSERT 방식 - 복합 충돌 키 지원 (예: sales_no + product_name) - 파라미터 인덱스 정확한 매핑 - 데이터 소스 자동 감지 - 테이블 선택 데이터 (selectedRowsData) 자동 주입 - 폼 입력 데이터 (formData) 자동 주입 - TableSource 노드가 외부 데이터 우선 사용 - 버튼 컴포넌트 통합 - 기존 관계 실행 + 새 노드 플로우 실행 하이브리드 지원 - 노드 플로우 선택 UI 추가 - API 클라이언트 통합 (Axios) - 개발 문서 작성 - 노드 기반 제어 시스템 개선 계획 - 노드 연결 규칙 설계 - 노드 실행 엔진 설계 - 노드 구조 개선안 - 버튼 통합 분석
2025-10-02 16:22:29 +09:00
const loadFlows = async () => {
2025-09-29 12:17:10 +09:00
try {
setLoading(true);
feat: 노드 기반 데이터 플로우 시스템 구현 - 노드 에디터 UI 구현 (React Flow 기반) - TableSource, DataTransform, INSERT, UPDATE, DELETE, UPSERT 노드 - 드래그앤드롭 노드 추가 및 연결 - 속성 패널을 통한 노드 설정 - 실시간 필드 라벨 표시 (column_labels 테이블 연동) - 데이터 변환 노드 (DataTransform) 기능 - EXPLODE: 구분자로 1개 행 → 여러 행 확장 - UPPERCASE, LOWERCASE, TRIM, CONCAT, SPLIT, REPLACE 등 12가지 변환 타입 - In-place 변환 지원 (타겟 필드 생략 시 소스 필드 덮어쓰기) - 변환된 필드가 하위 액션 노드에 자동 전달 - 노드 플로우 실행 엔진 - 위상 정렬을 통한 노드 실행 순서 결정 - 레벨별 병렬 실행 (Promise.allSettled) - 부분 실패 허용 (한 노드 실패 시 연결된 하위 노드만 스킵) - 트랜잭션 기반 안전한 데이터 처리 - UPSERT 액션 로직 구현 - DB 제약 조건 없이 SELECT → UPDATE or INSERT 방식 - 복합 충돌 키 지원 (예: sales_no + product_name) - 파라미터 인덱스 정확한 매핑 - 데이터 소스 자동 감지 - 테이블 선택 데이터 (selectedRowsData) 자동 주입 - 폼 입력 데이터 (formData) 자동 주입 - TableSource 노드가 외부 데이터 우선 사용 - 버튼 컴포넌트 통합 - 기존 관계 실행 + 새 노드 플로우 실행 하이브리드 지원 - 노드 플로우 선택 UI 추가 - API 클라이언트 통합 (Axios) - 개발 문서 작성 - 노드 기반 제어 시스템 개선 계획 - 노드 연결 규칙 설계 - 노드 실행 엔진 설계 - 노드 구조 개선안 - 버튼 통합 분석
2025-10-02 16:22:29 +09:00
console.log("🔍 플로우 목록 로딩...");
2025-09-29 12:17:10 +09:00
feat: 노드 기반 데이터 플로우 시스템 구현 - 노드 에디터 UI 구현 (React Flow 기반) - TableSource, DataTransform, INSERT, UPDATE, DELETE, UPSERT 노드 - 드래그앤드롭 노드 추가 및 연결 - 속성 패널을 통한 노드 설정 - 실시간 필드 라벨 표시 (column_labels 테이블 연동) - 데이터 변환 노드 (DataTransform) 기능 - EXPLODE: 구분자로 1개 행 → 여러 행 확장 - UPPERCASE, LOWERCASE, TRIM, CONCAT, SPLIT, REPLACE 등 12가지 변환 타입 - In-place 변환 지원 (타겟 필드 생략 시 소스 필드 덮어쓰기) - 변환된 필드가 하위 액션 노드에 자동 전달 - 노드 플로우 실행 엔진 - 위상 정렬을 통한 노드 실행 순서 결정 - 레벨별 병렬 실행 (Promise.allSettled) - 부분 실패 허용 (한 노드 실패 시 연결된 하위 노드만 스킵) - 트랜잭션 기반 안전한 데이터 처리 - UPSERT 액션 로직 구현 - DB 제약 조건 없이 SELECT → UPDATE or INSERT 방식 - 복합 충돌 키 지원 (예: sales_no + product_name) - 파라미터 인덱스 정확한 매핑 - 데이터 소스 자동 감지 - 테이블 선택 데이터 (selectedRowsData) 자동 주입 - 폼 입력 데이터 (formData) 자동 주입 - TableSource 노드가 외부 데이터 우선 사용 - 버튼 컴포넌트 통합 - 기존 관계 실행 + 새 노드 플로우 실행 하이브리드 지원 - 노드 플로우 선택 UI 추가 - API 클라이언트 통합 (Axios) - 개발 문서 작성 - 노드 기반 제어 시스템 개선 계획 - 노드 연결 규칙 설계 - 노드 실행 엔진 설계 - 노드 구조 개선안 - 버튼 통합 분석
2025-10-02 16:22:29 +09:00
const flowList = await getNodeFlows();
setFlows(flowList);
console.log(`✅ 플로우 ${flowList.length}개 로딩 완료`);
2025-09-29 12:17:10 +09:00
} catch (error) {
feat: 노드 기반 데이터 플로우 시스템 구현 - 노드 에디터 UI 구현 (React Flow 기반) - TableSource, DataTransform, INSERT, UPDATE, DELETE, UPSERT 노드 - 드래그앤드롭 노드 추가 및 연결 - 속성 패널을 통한 노드 설정 - 실시간 필드 라벨 표시 (column_labels 테이블 연동) - 데이터 변환 노드 (DataTransform) 기능 - EXPLODE: 구분자로 1개 행 → 여러 행 확장 - UPPERCASE, LOWERCASE, TRIM, CONCAT, SPLIT, REPLACE 등 12가지 변환 타입 - In-place 변환 지원 (타겟 필드 생략 시 소스 필드 덮어쓰기) - 변환된 필드가 하위 액션 노드에 자동 전달 - 노드 플로우 실행 엔진 - 위상 정렬을 통한 노드 실행 순서 결정 - 레벨별 병렬 실행 (Promise.allSettled) - 부분 실패 허용 (한 노드 실패 시 연결된 하위 노드만 스킵) - 트랜잭션 기반 안전한 데이터 처리 - UPSERT 액션 로직 구현 - DB 제약 조건 없이 SELECT → UPDATE or INSERT 방식 - 복합 충돌 키 지원 (예: sales_no + product_name) - 파라미터 인덱스 정확한 매핑 - 데이터 소스 자동 감지 - 테이블 선택 데이터 (selectedRowsData) 자동 주입 - 폼 입력 데이터 (formData) 자동 주입 - TableSource 노드가 외부 데이터 우선 사용 - 버튼 컴포넌트 통합 - 기존 관계 실행 + 새 노드 플로우 실행 하이브리드 지원 - 노드 플로우 선택 UI 추가 - API 클라이언트 통합 (Axios) - 개발 문서 작성 - 노드 기반 제어 시스템 개선 계획 - 노드 연결 규칙 설계 - 노드 실행 엔진 설계 - 노드 구조 개선안 - 버튼 통합 분석
2025-10-02 16:22:29 +09:00
console.error("❌ 플로우 목록 로딩 실패:", error);
setFlows([]);
2025-09-29 12:17:10 +09:00
} finally {
setLoading(false);
}
};
/**
2025-12-12 18:28:58 +09:00
* 🔥
2025-09-29 12:17:10 +09:00
*/
2025-12-12 18:28:58 +09:00
const handleAddControl = useCallback(() => {
const newControl: FlowControlConfig = {
id: `control_${Date.now()}`,
flowId: 0,
flowName: "",
executionTiming: "after",
order: flowControls.length + 1,
};
const updatedControls = [...flowControls, newControl];
updateFlowControls(updatedControls);
}, [flowControls]);
/**
* 🔥
*/
const handleRemoveControl = useCallback(
(controlId: string) => {
const updatedControls = flowControls
.filter((c) => c.id !== controlId)
.map((c, index) => ({ ...c, order: index + 1 }));
updateFlowControls(updatedControls);
},
[flowControls],
);
/**
* 🔥
*/
const handleFlowSelect = useCallback(
(controlId: string, flowId: string) => {
const selectedFlow = flows.find((f) => f.flowId.toString() === flowId);
if (selectedFlow) {
const updatedControls = flowControls.map((c) =>
c.id === controlId ? { ...c, flowId: selectedFlow.flowId, flowName: selectedFlow.flowName } : c,
);
updateFlowControls(updatedControls);
}
},
[flows, flowControls],
);
/**
* 🔥
*/
const handleTimingChange = useCallback(
(controlId: string, timing: "before" | "after" | "replace") => {
const updatedControls = flowControls.map((c) => (c.id === controlId ? { ...c, executionTiming: timing } : c));
updateFlowControls(updatedControls);
},
[flowControls],
);
/**
* 🔥
*/
const handleMoveUp = useCallback(
(controlId: string) => {
const index = flowControls.findIndex((c) => c.id === controlId);
if (index > 0) {
const updatedControls = [...flowControls];
[updatedControls[index - 1], updatedControls[index]] = [updatedControls[index], updatedControls[index - 1]];
// 순서 번호 재정렬
updatedControls.forEach((c, i) => (c.order = i + 1));
updateFlowControls(updatedControls);
}
},
[flowControls],
);
/**
* 🔥
*/
const handleMoveDown = useCallback(
(controlId: string) => {
const index = flowControls.findIndex((c) => c.id === controlId);
if (index < flowControls.length - 1) {
const updatedControls = [...flowControls];
[updatedControls[index], updatedControls[index + 1]] = [updatedControls[index + 1], updatedControls[index]];
// 순서 번호 재정렬
updatedControls.forEach((c, i) => (c.order = i + 1));
updateFlowControls(updatedControls);
}
},
[flowControls],
);
/**
* 🔥 ( )
*/
const updateFlowControls = (controls: FlowControlConfig[]) => {
// 첫 번째 제어를 기존 형식으로도 저장 (하위 호환성)
const firstValidControl = controls.find((c) => c.flowId > 0);
onUpdateProperty("webTypeConfig.dataflowConfig", {
...dataflowConfig,
// 기존 형식 (하위 호환성)
selectedDiagramId: firstValidControl?.flowId || null,
selectedRelationshipId: null,
flowConfig: firstValidControl
? {
flowId: firstValidControl.flowId,
flowName: firstValidControl.flowName,
executionTiming: firstValidControl.executionTiming,
contextData: {},
}
: null,
// 새로운 다중 제어 형식
flowControls: controls,
});
2025-09-29 12:17:10 +09:00
};
return (
<div className="space-y-6">
{/* 🔥 제어관리 활성화 스위치 */}
2025-10-27 16:40:59 +09:00
<div className="flex items-center justify-between">
2025-09-29 12:17:10 +09:00
<div className="flex items-center space-x-2">
<Settings className="text-primary h-4 w-4" />
2025-09-29 12:17:10 +09:00
<div>
2025-10-27 16:40:59 +09:00
<Label className="text-sm font-medium"> </Label>
<p className="text-muted-foreground mt-1 text-xs"> </p>
2025-09-29 12:17:10 +09:00
</div>
</div>
<Switch
checked={config.enableDataflowControl || false}
onCheckedChange={(checked) => onUpdateProperty("webTypeConfig.enableDataflowControl", checked)}
/>
</div>
{/* 🔥 제어관리가 활성화된 경우에만 설정 표시 */}
{config.enableDataflowControl && (
2025-10-27 16:40:59 +09:00
<div className="space-y-4">
2025-12-12 18:28:58 +09:00
{/* 제어 목록 헤더 */}
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<Workflow className="h-4 w-4 text-green-600" />
<Label> ( )</Label>
</div>
<Button variant="outline" size="sm" onClick={handleAddControl} className="h-8">
<Plus className="mr-1 h-3 w-3" />
</Button>
</div>
{/* 제어 목록 */}
{flowControls.length === 0 ? (
<div className="rounded-md border border-dashed p-6 text-center">
<Workflow className="mx-auto h-8 w-8 text-gray-400" />
<p className="mt-2 text-sm text-gray-500"> </p>
<Button variant="outline" size="sm" onClick={handleAddControl} className="mt-3">
<Plus className="mr-1 h-3 w-3" />
</Button>
</div>
) : (
<div className="space-y-2">
{flowControls.map((control, index) => (
<FlowControlItem
key={control.id}
control={control}
flows={flows}
loading={loading}
isFirst={index === 0}
isLast={index === flowControls.length - 1}
onFlowSelect={(flowId) => handleFlowSelect(control.id, flowId)}
onTimingChange={(timing) => handleTimingChange(control.id, timing)}
onMoveUp={() => handleMoveUp(control.id)}
onMoveDown={() => handleMoveDown(control.id)}
onRemove={() => handleRemoveControl(control.id)}
/>
))}
</div>
)}
{/* 안내 메시지 */}
{flowControls.length > 0 && (
<div className="rounded bg-blue-50 p-3">
<div className="flex items-start space-x-2">
<Info className="mt-0.5 h-4 w-4 text-blue-600" />
<div className="text-xs text-blue-800">
<p className="font-medium"> :</p>
<p className="mt-1"> </p>
<p> </p>
<p> </p>
2025-10-27 16:40:59 +09:00
</div>
</div>
</div>
)}
</div>
2025-09-29 12:17:10 +09:00
)}
</div>
);
};
/**
2025-12-12 18:28:58 +09:00
* 🔥
2025-09-29 12:17:10 +09:00
*/
2025-12-12 18:28:58 +09:00
const FlowControlItem: React.FC<{
control: FlowControlConfig;
feat: 노드 기반 데이터 플로우 시스템 구현 - 노드 에디터 UI 구현 (React Flow 기반) - TableSource, DataTransform, INSERT, UPDATE, DELETE, UPSERT 노드 - 드래그앤드롭 노드 추가 및 연결 - 속성 패널을 통한 노드 설정 - 실시간 필드 라벨 표시 (column_labels 테이블 연동) - 데이터 변환 노드 (DataTransform) 기능 - EXPLODE: 구분자로 1개 행 → 여러 행 확장 - UPPERCASE, LOWERCASE, TRIM, CONCAT, SPLIT, REPLACE 등 12가지 변환 타입 - In-place 변환 지원 (타겟 필드 생략 시 소스 필드 덮어쓰기) - 변환된 필드가 하위 액션 노드에 자동 전달 - 노드 플로우 실행 엔진 - 위상 정렬을 통한 노드 실행 순서 결정 - 레벨별 병렬 실행 (Promise.allSettled) - 부분 실패 허용 (한 노드 실패 시 연결된 하위 노드만 스킵) - 트랜잭션 기반 안전한 데이터 처리 - UPSERT 액션 로직 구현 - DB 제약 조건 없이 SELECT → UPDATE or INSERT 방식 - 복합 충돌 키 지원 (예: sales_no + product_name) - 파라미터 인덱스 정확한 매핑 - 데이터 소스 자동 감지 - 테이블 선택 데이터 (selectedRowsData) 자동 주입 - 폼 입력 데이터 (formData) 자동 주입 - TableSource 노드가 외부 데이터 우선 사용 - 버튼 컴포넌트 통합 - 기존 관계 실행 + 새 노드 플로우 실행 하이브리드 지원 - 노드 플로우 선택 UI 추가 - API 클라이언트 통합 (Axios) - 개발 문서 작성 - 노드 기반 제어 시스템 개선 계획 - 노드 연결 규칙 설계 - 노드 실행 엔진 설계 - 노드 구조 개선안 - 버튼 통합 분석
2025-10-02 16:22:29 +09:00
flows: NodeFlow[];
2025-09-29 12:17:10 +09:00
loading: boolean;
2025-12-12 18:28:58 +09:00
isFirst: boolean;
isLast: boolean;
onFlowSelect: (flowId: string) => void;
onTimingChange: (timing: "before" | "after" | "replace") => void;
onMoveUp: () => void;
onMoveDown: () => void;
onRemove: () => void;
}> = ({ control, flows, loading, isFirst, isLast, onFlowSelect, onTimingChange, onMoveUp, onMoveDown, onRemove }) => {
2025-09-29 12:17:10 +09:00
return (
2025-12-12 18:28:58 +09:00
<Card className="p-3">
<div className="flex items-start gap-2">
{/* 순서 표시 및 이동 버튼 */}
<div className="flex flex-col items-center gap-1">
<Badge variant="secondary" className="h-6 w-6 justify-center rounded-full p-0 text-xs">
{control.order}
</Badge>
<div className="flex flex-col">
<Button variant="ghost" size="icon" className="h-5 w-5" onClick={onMoveUp} disabled={isFirst}>
<ChevronUp className="h-3 w-3" />
</Button>
<Button variant="ghost" size="icon" className="h-5 w-5" onClick={onMoveDown} disabled={isLast}>
<ChevronDown className="h-3 w-3" />
</Button>
</div>
</div>
feat: 노드 기반 데이터 플로우 시스템 구현 - 노드 에디터 UI 구현 (React Flow 기반) - TableSource, DataTransform, INSERT, UPDATE, DELETE, UPSERT 노드 - 드래그앤드롭 노드 추가 및 연결 - 속성 패널을 통한 노드 설정 - 실시간 필드 라벨 표시 (column_labels 테이블 연동) - 데이터 변환 노드 (DataTransform) 기능 - EXPLODE: 구분자로 1개 행 → 여러 행 확장 - UPPERCASE, LOWERCASE, TRIM, CONCAT, SPLIT, REPLACE 등 12가지 변환 타입 - In-place 변환 지원 (타겟 필드 생략 시 소스 필드 덮어쓰기) - 변환된 필드가 하위 액션 노드에 자동 전달 - 노드 플로우 실행 엔진 - 위상 정렬을 통한 노드 실행 순서 결정 - 레벨별 병렬 실행 (Promise.allSettled) - 부분 실패 허용 (한 노드 실패 시 연결된 하위 노드만 스킵) - 트랜잭션 기반 안전한 데이터 처리 - UPSERT 액션 로직 구현 - DB 제약 조건 없이 SELECT → UPDATE or INSERT 방식 - 복합 충돌 키 지원 (예: sales_no + product_name) - 파라미터 인덱스 정확한 매핑 - 데이터 소스 자동 감지 - 테이블 선택 데이터 (selectedRowsData) 자동 주입 - 폼 입력 데이터 (formData) 자동 주입 - TableSource 노드가 외부 데이터 우선 사용 - 버튼 컴포넌트 통합 - 기존 관계 실행 + 새 노드 플로우 실행 하이브리드 지원 - 노드 플로우 선택 UI 추가 - API 클라이언트 통합 (Axios) - 개발 문서 작성 - 노드 기반 제어 시스템 개선 계획 - 노드 연결 규칙 설계 - 노드 실행 엔진 설계 - 노드 구조 개선안 - 버튼 통합 분석
2025-10-02 16:22:29 +09:00
2025-12-12 18:28:58 +09:00
{/* 플로우 선택 및 설정 */}
<div className="flex-1 space-y-2">
{/* 플로우 선택 */}
<Select value={control.flowId > 0 ? control.flowId.toString() : ""} onValueChange={onFlowSelect}>
<SelectTrigger className="h-8 text-xs">
<SelectValue placeholder="플로우를 선택하세요" />
</SelectTrigger>
<SelectContent>
{loading ? (
<div className="p-2 text-center text-xs text-gray-500"> ...</div>
) : flows.length === 0 ? (
<div className="p-2 text-center text-xs text-gray-500"> </div>
) : (
flows.map((flow) => (
<SelectItem key={flow.flowId} value={flow.flowId.toString()}>
<span className="text-xs">{flow.flowName}</span>
</SelectItem>
))
)}
</SelectContent>
</Select>
{/* 실행 타이밍 */}
<Select value={control.executionTiming} onValueChange={onTimingChange}>
<SelectTrigger className="h-8 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="before">
<span className="text-xs">Before ( )</span>
2025-09-29 12:17:10 +09:00
</SelectItem>
2025-12-12 18:28:58 +09:00
<SelectItem value="after">
<span className="text-xs">After ( )</span>
</SelectItem>
<SelectItem value="replace">
<span className="text-xs">Replace ( )</span>
</SelectItem>
</SelectContent>
</Select>
</div>
2025-09-29 12:17:10 +09:00
2025-12-12 18:28:58 +09:00
{/* 삭제 버튼 */}
<Button
variant="ghost"
size="icon"
className="h-8 w-8 text-red-500 hover:bg-red-50 hover:text-red-600"
onClick={onRemove}
>
<Trash2 className="h-4 w-4" />
</Button>
2025-09-29 12:17:10 +09:00
</div>
2025-12-12 18:28:58 +09:00
</Card>
2025-09-29 12:17:10 +09:00
);
};