전략편집기 복합지표 기능 반영
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import React, { memo, useCallback } from 'react';
|
||||
import React, { memo, useCallback, useState } from 'react';
|
||||
import { Handle, Position, useConnection, useReactFlow, type NodeProps } from '@xyflow/react';
|
||||
import { START_NODE_ID, type HandleSide, type StrategyFlowNodeData } from '../../utils/strategyFlowLayout';
|
||||
import { hasNodeSettings } from '../../utils/conditionPeriods';
|
||||
import ConditionNodeSettings from './ConditionNodeSettings';
|
||||
|
||||
const LOGIC_COLORS: Record<string, string> = {
|
||||
AND: '#00aaff',
|
||||
@@ -179,16 +181,23 @@ export const LogicGateNode = memo(function LogicGateNode({ id, data, selected }:
|
||||
export const ConditionFlowNode = memo(function ConditionFlowNode({ id, data, selected }: NodeProps) {
|
||||
const d = data as StrategyFlowNodeData;
|
||||
const node = d.logicNode!;
|
||||
const ind = node.condition?.indicatorType ?? 'COND';
|
||||
const condType = node.condition?.conditionType ?? '';
|
||||
const cond = node.condition;
|
||||
const ind = cond?.indicatorType ?? 'COND';
|
||||
const condType = cond?.conditionType ?? '';
|
||||
const isCross = ['CROSS_UP', 'CROSS_DOWN'].includes(condType);
|
||||
const tone = isCross ? 'cross' : 'value';
|
||||
const isSell = d.signalTab === 'sell';
|
||||
const { onDragOver, onDragLeave, onDrop } = usePaletteDropHandlers(id, d);
|
||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||
const showSettings = cond && hasNodeSettings(cond);
|
||||
|
||||
const handleSettingsChange = useCallback((next: NonNullable<typeof cond>) => {
|
||||
d.onUpdateCondition?.(id, next);
|
||||
}, [d, id]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`se-flow-node se-flow-node--cond se-flow-node--${tone}${isSell ? ' se-flow-node--sell-mode' : ''}${d.isOrphan ? ' se-flow-node--orphan' : ''} ${selected ? 'se-flow-node--selected' : ''} ${d.dragOver ? 'se-flow-node--drop' : ''}`}
|
||||
className={`se-flow-node se-flow-node--cond se-flow-node--${tone}${isSell ? ' se-flow-node--sell-mode' : ''}${d.isOrphan ? ' se-flow-node--orphan' : ''} ${selected ? 'se-flow-node--selected' : ''} ${d.dragOver ? 'se-flow-node--drop' : ''}${settingsOpen ? ' se-flow-node--settings-open' : ''}`}
|
||||
onDragOver={onDragOver}
|
||||
onDragLeave={onDragLeave}
|
||||
onDrop={onDrop}
|
||||
@@ -198,9 +207,38 @@ export const ConditionFlowNode = memo(function ConditionFlowNode({ id, data, sel
|
||||
targetOnly
|
||||
canTargetConnect={d.canTargetConnect !== false}
|
||||
/>
|
||||
<div className="se-flow-cond-badge">{ind}</div>
|
||||
<div className="se-flow-cond-top">
|
||||
<div className="se-flow-cond-badge">{ind}</div>
|
||||
<div className="se-flow-cond-actions">
|
||||
{showSettings && (
|
||||
<button
|
||||
type="button"
|
||||
className="se-flow-settings"
|
||||
title="지표 설정"
|
||||
aria-label="지표 설정"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
setSettingsOpen(v => !v);
|
||||
}}
|
||||
>
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
<button type="button" className="se-flow-del" title="삭제" onClick={() => d.onDelete?.(id)}>×</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="se-flow-cond-text">{d.label ?? ind}</div>
|
||||
<button type="button" className="se-flow-del" title="삭제" onClick={() => d.onDelete?.(id)}>×</button>
|
||||
{settingsOpen && cond && d.def && (
|
||||
<ConditionNodeSettings
|
||||
condition={cond}
|
||||
def={d.def}
|
||||
onChange={handleSettingsChange}
|
||||
onClose={() => setSettingsOpen(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user