diff --git a/frontend/components/screen/ScreenRelationFlow.tsx b/frontend/components/screen/ScreenRelationFlow.tsx index 9f75874a..09c980df 100644 --- a/frontend/components/screen/ScreenRelationFlow.tsx +++ b/frontend/components/screen/ScreenRelationFlow.tsx @@ -1488,6 +1488,32 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId }); } + // lookup 필터 OFF일 때: lookup 연결만 있는 테이블 노드를 dim 처리 + const lookupOnlyNodes = new Set(); + if (!edgeFilterState.lookup) { + const nodeEdgeCategories = new Map>(); + edges.forEach((edge) => { + const category = (edge.data as any)?.edgeCategory as EdgeCategory | undefined; + if (!category) return; + [edge.source, edge.target].forEach((nodeId) => { + if (!nodeEdgeCategories.has(nodeId)) { + nodeEdgeCategories.set(nodeId, new Set()); + } + nodeEdgeCategories.get(nodeId)!.add(category); + }); + }); + nodeEdgeCategories.forEach((categories, nodeId) => { + if (nodeId.startsWith("table-") || nodeId.startsWith("subtable-")) { + const hasVisibleCategory = Array.from(categories).some( + (cat) => cat !== "lookup" && edgeFilterState[cat] + ); + if (!hasVisibleCategory) { + lookupOnlyNodes.add(nodeId); + } + } + }); + } + return nodes.map((node) => { // 화면 노드 스타일링 (포커스가 있을 때만) if (node.id.startsWith("screen-")) { @@ -1783,7 +1809,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId ...node.data, isFocused: isFocusedTable, isRelated: isRelatedTable, - isFaded: focusedScreenId !== null && !isActiveTable, + isFaded: (focusedScreenId !== null && !isActiveTable) || lookupOnlyNodes.has(node.id), highlightedColumns: isActiveTable ? highlightedColumns : [], joinColumns: isActiveTable ? joinColumns : [], joinColumnRefs: focusedJoinColumnRefs.length > 0 ? focusedJoinColumnRefs : undefined, // 조인 컬럼 참조 정보 @@ -1894,7 +1920,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId data: { ...node.data, isFocused: isActiveSubTable, - isFaded: !isActiveSubTable, + isFaded: !isActiveSubTable || lookupOnlyNodes.has(node.id), highlightedColumns: isActiveSubTable ? subTableHighlightedColumns : [], joinColumns: isActiveSubTable ? subTableJoinColumns : [], fieldMappings: isActiveSubTable ? displayFieldMappings : [], @@ -1905,7 +1931,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId return node; }); - }, [nodes, selectedGroup, focusedScreenId, screenSubTableMap, subTablesDataMap, screenUsedColumnsMap, screenTableMap, tableColumns]); + }, [nodes, selectedGroup, focusedScreenId, screenSubTableMap, subTablesDataMap, screenUsedColumnsMap, screenTableMap, tableColumns, edgeFilterState, edges]); // 포커스에 따른 엣지 스타일링 (그룹 모드 & 개별 화면 모드) const styledEdges = React.useMemo(() => { @@ -2304,8 +2330,19 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId }); // 기존 엣지 + 조인 관계 엣지 합치기 - return [...styledOriginalEdges, ...joinEdges]; - }, [edges, nodes, selectedGroup, focusedScreenId, screen, screenSubTableMap, subTablesDataMap, screenTableMap]); + const allEdges = [...styledOriginalEdges, ...joinEdges]; + // 엣지 필터 적용 (edgeFilterState에 따라 숨김) + return allEdges.map((edge) => { + const category = (edge.data as any)?.edgeCategory as EdgeCategory | undefined; + if (category && !edgeFilterState[category]) { + return { + ...edge, + hidden: true, + }; + } + return edge; + }); + }, [edges, nodes, selectedGroup, focusedScreenId, screen, screenSubTableMap, subTablesDataMap, screenTableMap, edgeFilterState]); // 그룹의 화면 목록 (데이터 흐름 설정용) - 모든 조건부 return 전에 선언해야 함 const groupScreensList = React.useMemo(() => { @@ -2385,6 +2422,37 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId {screen.screenCode} )} + +
+ 연결 + + {( + [ + { key: "main" as EdgeCategory, label: "메인", color: "bg-primary", defaultOn: true }, + { key: "filter" as EdgeCategory, label: "마스터-디테일", color: "bg-[hsl(var(--info))]", defaultOn: true }, + { key: "join" as EdgeCategory, label: "엔티티 조인", color: "bg-amber-400", defaultOn: true }, + { key: "lookup" as EdgeCategory, label: "코드 참조", color: "bg-warning", defaultOn: false }, + ] as const + ).map(({ key, label, color, defaultOn }) => { + const isOn = edgeFilterState[key]; + const count = edges.filter((e) => (e.data as any)?.edgeCategory === key).length; + return ( + + ); + })}
)} {/* isViewReady가 false면 숨김 처리하여 깜빡임 방지 */} @@ -2434,28 +2502,6 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId marginBottom: "8px", }} /> - {/* 관계 범례 */} -
-

관계 유형

-
-
-
- 메인 테이블 -
-
-
- 마스터-디테일 -
-
-
- 코드 참조 -
-
-
- 엔티티 조인 -
-
-