Skip to content
This repository was archived by the owner on Mar 18, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions src/app/canvas/components/Canvas/components/CanvasNodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ interface CanvasNodesProps {
onOutputAdd?: (nodeId: string, output: any) => void;
onOutputDelete?: (nodeId: string, outputId: string) => void;
onOutputNameChange?: (nodeId: string, outputId: string, newName: string) => void;
// AgentXgen specific props
onOutputsUpdate?: (nodeId: string, outputs: any[]) => void;
currentEdges: any[];
onToggleExpanded: (nodeId: string) => void;
}
Expand All @@ -51,7 +49,6 @@ export const CanvasNodes: React.FC<CanvasNodesProps> = ({
onOutputAdd,
onOutputDelete,
onOutputNameChange,
onOutputsUpdate,
currentEdges,
onToggleExpanded
}) => {
Expand Down Expand Up @@ -101,11 +98,6 @@ export const CanvasNodes: React.FC<CanvasNodesProps> = ({
if (propName === 'onOutputNameChange') additionalProps.onOutputNameChange = onOutputNameChange;
});

// AgentXgen specific prop
if (specialNodeConfig.name === 'AgentXgenNode') {
additionalProps.onOutputsUpdate = onOutputsUpdate;
}

return <SpecialComponent key={node.id} {...commonProps} {...additionalProps} />;
}

Expand Down
31 changes: 1 addition & 30 deletions src/app/canvas/components/Canvas/hooks/useNodeManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ interface UseNodeManagementReturn {
addOutput: (nodeId: string, newOutput: Port) => void;
deleteOutput: (nodeId: string, outputId: string) => void;
updateOutputName: (nodeId: string, outputId: string, newName: string) => void;
// AgentXgen specific functions
updateNodeOutputs: (nodeId: string, outputs: Port[]) => void;
}

export const useNodeManagement = ({ historyHelpers }: UseNodeManagementProps = {}): UseNodeManagementReturn => {
Expand Down Expand Up @@ -361,32 +359,6 @@ export const useNodeManagement = ({ historyHelpers }: UseNodeManagementProps = {
});
}, []);

// AgentXgen specific function - Update entire outputs array
const updateNodeOutputs = useCallback((nodeId: string, outputs: Port[]): void => {
setNodes(prevNodes => {
const targetNodeIndex = prevNodes.findIndex(node => node.id === nodeId);
if (targetNodeIndex === -1) {
return prevNodes;
}

const targetNode = prevNodes[targetNodeIndex];

const newNodes = [
...prevNodes.slice(0, targetNodeIndex),
{
...targetNode,
data: {
...targetNode.data,
outputs
}
},
...prevNodes.slice(targetNodeIndex + 1)
];

return newNodes;
});
}, []);

return {
nodes,
setNodes,
Expand All @@ -402,7 +374,6 @@ export const useNodeManagement = ({ historyHelpers }: UseNodeManagementProps = {
deleteParameter,
addOutput,
deleteOutput,
updateOutputName,
updateNodeOutputs
updateOutputName
};
};
4 changes: 1 addition & 3 deletions src/app/canvas/components/Canvas/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ const Canvas = forwardRef<CanvasRef, CanvasProps>(({
deleteParameter,
addOutput,
deleteOutput,
updateOutputName,
updateNodeOutputs
updateOutputName
} = useNodeManagement({ historyHelpers });

const {
Expand Down Expand Up @@ -757,7 +756,6 @@ const Canvas = forwardRef<CanvasRef, CanvasProps>(({
onOutputAdd={addOutput}
onOutputDelete={deleteOutput}
onOutputNameChange={updateOutputName}
onOutputsUpdate={updateNodeOutputs}
onClearSelection={clearSelection}
onOpenNodeModal={onOpenNodeModal}
onSynchronizeSchema={handleSynchronizeSchema}
Expand Down
16 changes: 11 additions & 5 deletions src/app/canvas/components/Node/components/NodePorts.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React from 'react';
import React, { useMemo } from 'react';
import { LuDownload } from 'react-icons/lu';
import styles from '@/app/canvas/assets/Node.module.scss';
import { generatePortKey, getConnectedSchemaProvider } from '../utils/nodeUtils';
import { filterPortsByDependency } from '../utils/portUtils';
import type { NodePortsProps } from '../types';

export const NodePorts: React.FC<NodePortsProps> = ({
nodeId,
inputs,
outputs,
parameters,
isPreview = false,
isPredicted = false,
isSelected,
Expand All @@ -20,8 +22,12 @@ export const NodePorts: React.FC<NodePortsProps> = ({
currentEdges,
onSynchronizeSchema
}) => {
const hasInputs = inputs && inputs.length > 0;
const hasOutputs = outputs && outputs.length > 0;
// Dependency를 고려하여 실제 렌더링할 포트만 필터링
const filteredInputs = useMemo(() => filterPortsByDependency(inputs, parameters), [inputs, parameters]);
const filteredOutputs = useMemo(() => filterPortsByDependency(outputs, parameters), [outputs, parameters]);

const hasInputs = filteredInputs && filteredInputs.length > 0;
const hasOutputs = filteredOutputs && filteredOutputs.length > 0;
const hasOnlyOutputs = hasOutputs && !hasInputs;

const handleSynchronizeSchema = (portId: string) => {
Expand All @@ -38,7 +44,7 @@ export const NodePorts: React.FC<NodePortsProps> = ({
{hasInputs && (
<div className={styles.column}>
<div className={styles.sectionHeader}>INPUT</div>
{inputs.map(portData => {
{filteredInputs.map(portData => {
const portKey = generatePortKey(nodeId, portData.id, 'input');
const isSnapping = snappedPortKey === portKey;

Expand Down Expand Up @@ -102,7 +108,7 @@ export const NodePorts: React.FC<NodePortsProps> = ({
{hasOutputs && (
<div className={`${styles.column} ${styles.outputColumn} ${hasOnlyOutputs ? styles.fullWidth : ''}`}>
<div className={styles.sectionHeader}>OUTPUT</div>
{outputs.map(portData => {
{filteredOutputs.map(portData => {
const portClasses = [
styles.port,
styles.outputPort,
Expand Down
16 changes: 11 additions & 5 deletions src/app/canvas/components/Node/components/NodePortsCollapsed.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React from 'react';
import React, { useMemo } from 'react';
import styles from '@/app/canvas/assets/Node.module.scss';
import { generatePortKey } from '../utils/nodeUtils';
import { filterPortsByDependency } from '../utils/portUtils';
import type { NodePortsProps } from '../types';

export const NodePortsCollapsed: React.FC<NodePortsProps> = ({
nodeId,
inputs,
outputs,
parameters,
isPreview = false,
isPredicted = false,
onPortMouseDown,
Expand All @@ -15,8 +17,12 @@ export const NodePortsCollapsed: React.FC<NodePortsProps> = ({
snappedPortKey,
isSnapTargetInvalid
}) => {
const hasInputs = inputs && inputs.length > 0;
const hasOutputs = outputs && outputs.length > 0;
// Dependency를 고려하여 실제 렌더링할 포트만 필터링
const filteredInputs = useMemo(() => filterPortsByDependency(inputs, parameters), [inputs, parameters]);
const filteredOutputs = useMemo(() => filterPortsByDependency(outputs, parameters), [outputs, parameters]);

const hasInputs = filteredInputs && filteredInputs.length > 0;
const hasOutputs = filteredOutputs && filteredOutputs.length > 0;

if (!hasInputs && !hasOutputs) {
return null;
Expand All @@ -26,7 +32,7 @@ export const NodePortsCollapsed: React.FC<NodePortsProps> = ({
<div className={styles.collapsedPorts}>
{/* 입력 포트들 - 왼쪽 */}
<div className={styles.collapsedInputs}>
{hasInputs && inputs?.map((input) => {
{hasInputs && filteredInputs?.map((input) => {
const portKey = generatePortKey(nodeId, input.id, 'input');
const isSnapping = snappedPortKey === portKey;

Expand Down Expand Up @@ -76,7 +82,7 @@ export const NodePortsCollapsed: React.FC<NodePortsProps> = ({

{/* 출력 포트들 - 오른쪽 */}
<div className={styles.collapsedOutputs}>
{hasOutputs && outputs?.map((output) => {
{hasOutputs && filteredOutputs?.map((output) => {
const portKey = generatePortKey(nodeId, output.id, 'output');
const isSnapping = snappedPortKey === portKey;

Expand Down
16 changes: 11 additions & 5 deletions src/app/canvas/components/Node/components/RouterNodePorts.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { useState } from 'react';
import React, { useState, useMemo } from 'react';
import { LuDownload, LuPlus } from 'react-icons/lu';
import styles from '@/app/canvas/assets/Node.module.scss';
import { generatePortKey, getConnectedSchemaProvider } from '../utils/nodeUtils';
import { filterPortsByDependency } from '../utils/portUtils';
import type { NodePortsProps } from '../types';
import type { Port } from '@/app/canvas/types';

Expand All @@ -15,6 +16,7 @@ export const RouterNodePorts: React.FC<RouterNodePortsProps> = ({
nodeId,
inputs,
outputs,
parameters,
isPreview = false,
isPredicted = false,
isSelected,
Expand All @@ -33,8 +35,12 @@ export const RouterNodePorts: React.FC<RouterNodePortsProps> = ({
const [editingOutput, setEditingOutput] = useState<string | null>(null);
const [editingOutputValue, setEditingOutputValue] = useState<string>('');

const hasInputs = inputs && inputs.length > 0;
const hasOutputs = outputs && outputs.length > 0;
// Filter ports based on parameter dependencies
const filteredInputs = useMemo(() => filterPortsByDependency(inputs, parameters), [inputs, parameters]);
const filteredOutputs = useMemo(() => filterPortsByDependency(outputs, parameters), [outputs, parameters]);

const hasInputs = filteredInputs && filteredInputs.length > 0;
const hasOutputs = filteredOutputs && filteredOutputs.length > 0;
const hasOnlyOutputs = hasOutputs && !hasInputs;

const handleSynchronizeSchema = (portId: string) => {
Expand Down Expand Up @@ -116,7 +122,7 @@ export const RouterNodePorts: React.FC<RouterNodePortsProps> = ({
{hasInputs && (
<div className={styles.column}>
<div className={styles.sectionHeader}>INPUT</div>
{inputs.map(portData => {
{filteredInputs.map(portData => {
const portKey = generatePortKey(nodeId, portData.id, 'input');
const isSnapping = snappedPortKey === portKey;

Expand Down Expand Up @@ -220,7 +226,7 @@ export const RouterNodePorts: React.FC<RouterNodePortsProps> = ({
</button>
)}
</div>
{hasOutputs ? outputs.map(portData => {
{hasOutputs ? filteredOutputs.map(portData => {
const portClasses = [
styles.port,
styles.outputPort,
Expand Down
2 changes: 2 additions & 0 deletions src/app/canvas/components/Node/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ const Node: React.FC<NodeProps> = ({
nodeId={id}
inputs={inputs}
outputs={outputs}
parameters={parameters}
isPreview={isPreview}
isPredicted={isPredicted}
isSelected={isSelected}
Expand Down Expand Up @@ -181,6 +182,7 @@ const Node: React.FC<NodeProps> = ({
nodeId={id}
inputs={inputs}
outputs={outputs}
parameters={parameters}
isPreview={isPreview}
isPredicted={isPredicted}
isSelected={isSelected}
Expand Down
1 change: 1 addition & 0 deletions src/app/canvas/components/Node/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export interface NodePortsProps {
nodeId: string;
inputs?: any[];
outputs?: any[];
parameters?: Parameter[]; // Port dependency 체크를 위해 필요
isPreview?: boolean;
isPredicted?: boolean;
isSelected: boolean;
Expand Down
77 changes: 77 additions & 0 deletions src/app/canvas/components/Node/utils/portUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { Port, Parameter } from '@/app/canvas/types';

/**
* Port의 dependency를 확인하는 유틸리티 함수들
* NodeParameters의 dependency 로직과 동일하게 작동
*/

/**
* Parameter 값들을 맵으로 변환
*/
export const createParameterValueMap = (parameters?: Parameter[]): Record<string, Parameter['value'] | undefined> => {
const valueMap: Record<string, Parameter['value'] | undefined> = {};
(parameters ?? []).forEach((param) => {
valueMap[param.id] = param.value;
});
return valueMap;
};

/**
* Boolean 값을 정규화 (문자열 'true'/'false'를 boolean으로 변환)
*/
export const normalizeBoolean = (value: Parameter['value'] | undefined): boolean | undefined => {
if (typeof value === 'boolean') return value;
if (typeof value === 'string') {
const normalized = value.trim().toLowerCase();
if (normalized === 'true') return true;
if (normalized === 'false') return false;
}
return undefined;
};

/**
* Port의 dependency가 만족되는지 확인
* NodeParameters의 isDependencySatisfied와 동일한 로직
*/
export const isPortDependencySatisfied = (
port: Port,
parameterValueMap: Record<string, Parameter['value'] | undefined>
): boolean => {
// dependency가 없으면 항상 표시
if (!port.dependency) return true;

const dependencyValue = parameterValueMap[port.dependency];
const expectedValue = port.dependencyValue ?? true;

// Boolean 비교
if (typeof expectedValue === 'boolean') {
const normalized = normalizeBoolean(dependencyValue);
if (normalized !== undefined) return normalized === expectedValue;
return dependencyValue === expectedValue;
}

// String 비교 (대소문자 무시)
if (typeof expectedValue === 'string') {
if (typeof dependencyValue === 'string') {
return dependencyValue.trim().toLowerCase() === expectedValue.trim().toLowerCase();
}
return false;
}

// 기타 타입 직접 비교
return dependencyValue === expectedValue;
};

/**
* Port 배열을 필터링하여 dependency가 만족되는 포트만 반환
*/
export const filterPortsByDependency = (
ports: Port[] | undefined,
parameters: Parameter[] | undefined
): Port[] => {
if (!ports) return [];

const parameterValueMap = createParameterValueMap(parameters);

return ports.filter(port => isPortDependencySatisfied(port, parameterValueMap));
};
2 changes: 2 additions & 0 deletions src/app/canvas/components/SpecialNode/RouterNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ const RouterNode: React.FC<NodeProps & {
nodeId={id}
inputs={inputs}
outputs={outputs}
parameters={parameters}
isPreview={isPreview}
isPredicted={isPredicted}
isSelected={isSelected}
Expand Down Expand Up @@ -205,6 +206,7 @@ const RouterNode: React.FC<NodeProps & {
nodeId={id}
inputs={inputs}
outputs={outputs}
parameters={parameters}
isPreview={isPreview}
isPredicted={isPredicted}
isSelected={isSelected}
Expand Down
2 changes: 2 additions & 0 deletions src/app/canvas/components/SpecialNode/SchemaProviderNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ const SchemaProviderNode: React.FC<NodeProps> = ({
nodeId={id}
inputs={inputs}
outputs={outputs}
parameters={parameters}
isPreview={isPreview}
isPredicted={isPredicted}
isSelected={isSelected}
Expand Down Expand Up @@ -179,6 +180,7 @@ const SchemaProviderNode: React.FC<NodeProps> = ({
nodeId={id}
inputs={inputs}
outputs={outputs}
parameters={parameters}
isPreview={isPreview}
isPredicted={isPredicted}
isSelected={isSelected}
Expand Down
Loading