import { create } from 'zustand'; import { devtools } from 'zustand/middleware'; /** * 제어 노드 16종 정의 (mockup CTRL_NODE_TYPES) * out: 커스텀 출력 포트. 없으면 기본 [{port:'out', label:'→'}] */ export const CTRL_NODE_TYPES: Record = { 'timer': { icon: '⏱', label: '타이머', rgb: '0,206,201', cat: '트리거' }, 'condition': { icon: '◇', label: '조건분기', rgb: '253,203,110', cat: '조건', out: [{ port: 'yes', label: 'Y', cls: 'port-yes' }, { port: 'no', label: 'N', cls: 'port-no' }] }, 'validation': { icon: '✔', label: '데이터 검증', rgb: '255,107,129', cat: '조건', out: [{ port: 'pass', label: '✓', cls: 'port-yes' }, { port: 'fail', label: '✗', cls: 'port-no' }] }, 'status-change': { icon: '🔄', label: '상태 변경', rgb: '108,92,231', cat: '액션' }, 'auto-insert': { icon: '📝', label: '자동 등록', rgb: '85,239,196', cat: '액션' }, 'calculation': { icon: '🧮', label: '계산/수식', rgb: '45,152,218', cat: '액션' }, 'delete': { icon: '🗑', label: '삭제/보관', rgb: '255,71,87', cat: '액션' }, 'document': { icon: '📄', label: '문서 생성', rgb: '162,155,254', cat: '액션' }, 'approval': { icon: '✋', label: '승인/결재', rgb: '255,165,2', cat: '흐름', out: [{ port: 'approved', label: '✓', cls: 'port-yes' }, { port: 'rejected', label: '✗', cls: 'port-no' }] }, 'delay': { icon: '⏳', label: '대기/지연', rgb: '72,219,251', cat: '흐름' }, 'loop': { icon: '🔁', label: '반복', rgb: '223,142,254', cat: '흐름', out: [{ port: 'each', label: '→', cls: '' }, { port: 'done', label: '✓', cls: 'port-yes' }] }, 'parallel': { icon: '🔀', label: '병렬 실행', rgb: '0,206,201', cat: '흐름' }, 'merge': { icon: '⤵', label: '병합/합류', rgb: '149,175,192', cat: '흐름' }, 'webhook': { icon: '🌐', label: '외부 호출', rgb: '116,185,255', cat: '연동' }, 'notification': { icon: '📨', label: '알림 발송', rgb: '253,121,168', cat: '연동' }, 'log': { icon: '📜', label: '로그 기록', rgb: '150,150,160', cat: '기록' }, }; interface ControlModeState { /** 제어 모드 활성 여부 */ active: boolean; /** 읽기 / 편집 / 실행 / 이력 모드 (선택된 카드 컨텍스트 안의 토글, v3 — IDE 4-segmented tabs) */ mode: 'view' | 'edit' | 'run' | 'history'; /** 선택된 카드 ID — 카드 클릭 시 좌측 축소 + 그 옆에 제어 패널 */ selectedCardId: string | null; /** 활성 흐름 — FlowViewer 내부 상태 (selectedCardId 와 동기화) */ activeFlowCardId: string | null; /** 흐름 엣지 배열 (BFS 결과) */ flowEdges: Record[]; /** 테이블 노드 위치 */ tablePositions: Record; /** 규칙 빌더 — 노드 */ ruleNodes: Record[]; /** 규칙 빌더 — 연결 */ ruleConnections: Record[]; /** 현재 편집 중인 룰 ID */ activeRuleId: string | null; /** 설정 팝오버 대상 노드 ID */ configNodeId: string | null; // 액션 toggleControlMode: () => void; setMode: (mode: 'view' | 'edit' | 'run' | 'history') => void; setSelectedCardId: (cardId: string | null) => void; setActiveFlowCard: (cardId: string | null) => void; setFlowEdges: (edges: Record[]) => void; setTablePositions: (pos: Record) => void; setRuleNodes: (nodes: Record[]) => void; addRuleNode: (node: Record) => void; updateRuleNode: (nodeId: string, updates: Record) => void; removeRuleNode: (nodeId: string) => void; moveRuleNode: (nodeId: string, x: number, y: number) => void; setRuleConnections: (conns: Record[]) => void; addRuleConnection: (conn: Record) => void; removeRuleConnection: (connId: string) => void; setActiveRuleId: (ruleId: string | null) => void; setConfigNodeId: (nodeId: string | null) => void; resetControlMode: () => void; } let _nodeSeq = 0; export function genNodeId(prefix: string) { return `${prefix}-${++_nodeSeq}`; } let _connSeq = 0; export function genConnId() { return `conn-${++_connSeq}`; } export const useControlMode = create()( devtools( (set) => ({ active: false, mode: 'view', selectedCardId: null, activeFlowCardId: null, flowEdges: [], tablePositions: {}, ruleNodes: [], ruleConnections: [], activeRuleId: null, configNodeId: null, toggleControlMode: () => set((s) => ({ active: !s.active, mode: 'view', selectedCardId: null, activeFlowCardId: null, flowEdges: [], tablePositions: {}, ruleNodes: [], ruleConnections: [], configNodeId: null, })), setMode: (mode) => set({ mode, configNodeId: null }), setSelectedCardId: (cardId) => set({ selectedCardId: cardId, // 카드 바꾸면 모드/룰 초기화 (각 카드는 자기 제어 컨텍스트) mode: 'view', activeFlowCardId: cardId, ruleNodes: [], ruleConnections: [], activeRuleId: null, configNodeId: null, }), setActiveFlowCard: (cardId) => set({ activeFlowCardId: cardId }), setFlowEdges: (edges) => set({ flowEdges: edges }), setTablePositions: (pos) => set({ tablePositions: pos }), setRuleNodes: (nodes) => set({ ruleNodes: nodes }), addRuleNode: (node) => set((s) => ({ ruleNodes: [...s.ruleNodes, node] })), updateRuleNode: (nodeId, updates) => set((s) => ({ ruleNodes: s.ruleNodes.map((n) => n.id === nodeId ? { ...n, ...updates } : n ), })), removeRuleNode: (nodeId) => set((s) => ({ ruleNodes: s.ruleNodes.filter((n) => n.id !== nodeId), ruleConnections: s.ruleConnections.filter( (c) => c.from_node_id !== nodeId && c.to_node_id !== nodeId ), })), moveRuleNode: (nodeId, x, y) => set((s) => ({ ruleNodes: s.ruleNodes.map((n) => n.id === nodeId ? { ...n, x, y } : n ), })), setRuleConnections: (conns) => set({ ruleConnections: conns }), addRuleConnection: (conn) => set((s) => ({ ruleConnections: [...s.ruleConnections, conn] })), removeRuleConnection: (connId) => set((s) => ({ ruleConnections: s.ruleConnections.filter((c) => c.id !== connId), })), setActiveRuleId: (ruleId) => set({ activeRuleId: ruleId }), setConfigNodeId: (nodeId) => set({ configNodeId: nodeId }), resetControlMode: () => set({ active: false, mode: 'view', selectedCardId: null, activeFlowCardId: null, flowEdges: [], tablePositions: {}, ruleNodes: [], ruleConnections: [], activeRuleId: null, configNodeId: null, }), }), { name: 'control-mode-store' } ) );