[agent-pipeline] pipe-20260315121506-3c5c round-2

This commit is contained in:
DDD1542 2026-03-15 21:22:36 +09:00
parent 009607f3f1
commit 8ed7faf517
1 changed files with 73 additions and 27 deletions

View File

@ -1488,6 +1488,32 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId
});
}
// lookup 필터 OFF일 때: lookup 연결만 있는 테이블 노드를 dim 처리
const lookupOnlyNodes = new Set<string>();
if (!edgeFilterState.lookup) {
const nodeEdgeCategories = new Map<string, Set<EdgeCategory>>();
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
<span className="text-xs text-muted-foreground font-mono">{screen.screenCode}</span>
</>
)}
<div className="h-4 w-px bg-border/30 mx-1" />
<span className="text-[10px] font-medium text-muted-foreground/50"></span>
{(
[
{ 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 (
<button
key={key}
type="button"
onClick={() => setEdgeFilterState((prev) => ({ ...prev, [key]: !prev[key] }))}
className={`inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[10px] font-medium transition-all duration-200 ${
isOn
? "bg-foreground/5 border border-border/20 text-foreground/80"
: `border text-muted-foreground/40 ${!defaultOn ? "border-dashed border-border/20" : "border-border/10"}`
}`}
>
<span className={`w-1.5 h-1.5 rounded-full ${color} transition-opacity ${isOn ? "opacity-100 shadow-sm" : "opacity-30"}`} />
{label}
<span className="text-[9px] text-muted-foreground/40 font-mono">{count}</span>
</button>
);
})}
</div>
)}
{/* isViewReady가 false면 숨김 처리하여 깜빡임 방지 */}
@ -2434,28 +2502,6 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId
marginBottom: "8px",
}}
/>
{/* 관계 범례 */}
<div className="absolute bottom-4 left-4 z-10 rounded-lg border bg-card/90 backdrop-blur-sm p-3 shadow-md">
<p className="text-[10px] font-medium text-muted-foreground mb-2"> </p>
<div className="flex flex-col gap-1.5">
<div className="flex items-center gap-2">
<div className="h-0.5 w-6 rounded-full bg-primary" />
<span className="text-[10px] text-muted-foreground"> </span>
</div>
<div className="flex items-center gap-2">
<div className="h-0.5 w-6 rounded-full bg-primary/50" />
<span className="text-[10px] text-muted-foreground">-</span>
</div>
<div className="flex items-center gap-2">
<div className="h-0.5 w-6 rounded-full bg-warning" />
<span className="text-[10px] text-muted-foreground"> </span>
</div>
<div className="flex items-center gap-2">
<div className="h-0.5 w-6 rounded-full bg-success" />
<span className="text-[10px] text-muted-foreground"> </span>
</div>
</div>
</div>
</ReactFlow>
</div>