플로우 페이지네이션 안보임

This commit is contained in:
kjs
2025-10-24 15:40:08 +09:00
parent 0a57a2cef1
commit 7d6281d289
21 changed files with 2101 additions and 469 deletions

View File

@@ -4,7 +4,7 @@
* 노드 기반 플로우 에디터 메인 컴포넌트
*/
import { useCallback, useRef, useEffect, useState } from "react";
import { useCallback, useRef, useEffect, useState, useMemo } from "react";
import ReactFlow, { Background, Controls, MiniMap, Panel, ReactFlowProvider, useReactFlow } from "reactflow";
import "reactflow/dist/style.css";
@@ -14,6 +14,7 @@ import { NodePalette } from "./sidebar/NodePalette";
import { LeftUnifiedToolbar, ToolbarButton } from "@/components/screen/toolbar/LeftUnifiedToolbar";
import { Boxes, Settings } from "lucide-react";
import { PropertiesPanel } from "./panels/PropertiesPanel";
import { ValidationNotification } from "./ValidationNotification";
import { FlowToolbar } from "./FlowToolbar";
import { TableSourceNode } from "./nodes/TableSourceNode";
import { ExternalDBSourceNode } from "./nodes/ExternalDBSourceNode";
@@ -27,6 +28,8 @@ import { DataTransformNode } from "./nodes/DataTransformNode";
import { RestAPISourceNode } from "./nodes/RestAPISourceNode";
import { CommentNode } from "./nodes/CommentNode";
import { LogNode } from "./nodes/LogNode";
import { validateFlow } from "@/lib/utils/flowValidation";
import type { FlowValidation } from "@/lib/utils/flowValidation";
// 노드 타입들
const nodeTypes = {
@@ -77,7 +80,7 @@ const flowToolbarButtons: ToolbarButton[] = [
function FlowEditorInner({ initialFlowId }: FlowEditorInnerProps) {
const reactFlowWrapper = useRef<HTMLDivElement>(null);
const { screenToFlowPosition } = useReactFlow();
const { screenToFlowPosition, setCenter } = useReactFlow();
// 패널 표시 상태
const [showNodesPanel, setShowNodesPanel] = useState(true);
@@ -91,8 +94,6 @@ function FlowEditorInner({ initialFlowId }: FlowEditorInnerProps) {
onConnect,
onNodeDragStart,
addNode,
showPropertiesPanel,
setShowPropertiesPanel,
selectNodes,
selectedNodes,
removeNodes,
@@ -101,6 +102,26 @@ function FlowEditorInner({ initialFlowId }: FlowEditorInnerProps) {
loadFlow,
} = useFlowEditorStore();
// 🆕 실시간 플로우 검증
const validations = useMemo<FlowValidation[]>(() => {
return validateFlow(nodes, edges);
}, [nodes, edges]);
// 🆕 노드 클릭 핸들러 (검증 패널에서 사용)
const handleValidationNodeClick = useCallback(
(nodeId: string) => {
const node = nodes.find((n) => n.id === nodeId);
if (node) {
selectNodes([nodeId]);
setCenter(node.position.x + 125, node.position.y + 50, {
zoom: 1.5,
duration: 500,
});
}
},
[nodes, selectNodes, setCenter],
);
// 속성 패널 상태 동기화
useEffect(() => {
if (selectedNodes.length > 0 && !showPropertiesPanelLocal) {
@@ -245,7 +266,7 @@ function FlowEditorInner({ initialFlowId }: FlowEditorInnerProps) {
);
return (
<div className="flex h-full w-full">
<div className="flex h-full w-full" style={{ height: "100%", overflow: "hidden" }}>
{/* 좌측 통합 툴바 */}
<LeftUnifiedToolbar
buttons={flowToolbarButtons}
@@ -258,7 +279,6 @@ function FlowEditorInner({ initialFlowId }: FlowEditorInnerProps) {
setShowNodesPanel(!showNodesPanel);
} else if (panelId === "properties") {
setShowPropertiesPanelLocal(!showPropertiesPanelLocal);
setShowPropertiesPanel(!showPropertiesPanelLocal);
}
}}
/>
@@ -273,8 +293,8 @@ function FlowEditorInner({ initialFlowId }: FlowEditorInnerProps) {
{/* 중앙 캔버스 */}
<div className="relative flex-1" ref={reactFlowWrapper} onKeyDown={onKeyDown} tabIndex={0}>
<ReactFlow
nodes={nodes}
edges={edges}
nodes={nodes as any}
edges={edges as any}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
@@ -305,17 +325,28 @@ function FlowEditorInner({ initialFlowId }: FlowEditorInnerProps) {
{/* 상단 툴바 */}
<Panel position="top-center" className="pointer-events-auto">
<FlowToolbar />
<FlowToolbar validations={validations} />
</Panel>
</ReactFlow>
</div>
{/* 우측 속성 패널 */}
{showPropertiesPanelLocal && selectedNodes.length > 0 && (
<div className="h-full w-[350px] border-l bg-white">
<div
style={{
height: "100%",
width: "350px",
display: "flex",
flexDirection: "column",
}}
className="border-l bg-white"
>
<PropertiesPanel />
</div>
)}
{/* 검증 알림 (우측 상단 플로팅) */}
<ValidationNotification validations={validations} onNodeClick={handleValidationNodeClick} />
</div>
);
}