전략편집기 팝업 기능 적용

This commit is contained in:
Macbook
2026-06-16 10:48:13 +09:00
parent 484f477d6c
commit d5e864b230
7 changed files with 644 additions and 84 deletions
@@ -21,6 +21,7 @@ import { fetchEvaluationSnapshotAtBar } from '../utils/strategyEvaluationSnapsho
import StrategyEvaluationSignalPanel from './strategyEvaluation/StrategyEvaluationSignalPanel';
import StrategyEvaluationChart from './strategyEvaluation/StrategyEvaluationChart';
import StrategyEvaluationSettingsTab from './strategyEvaluation/StrategyEvaluationSettingsTab';
import StrategyEditorModal from './strategyEvaluation/StrategyEditorModal';
import SePanelCollapseHandle from './strategyEditor/SePanelCollapseHandle';
import { readStoredSize, readStoredBool, storeBool, storeSize, usePanelResize } from './strategyEditor/usePanelResize';
import { getKoreanName } from '../utils/marketNameCache';
@@ -75,6 +76,7 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
const [paramsRevision, setParamsRevision] = useState(0);
const [chartLoading, setChartLoading] = useState(false);
const [backtestSignals, setBacktestSignals] = useState<BacktestSignal[]>([]);
const [editorModalOpen, setEditorModalOpen] = useState(false);
const evalSessionRef = useRef(0);
const paramsRevisionRef = useRef(paramsRevision);
@@ -169,6 +171,27 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
void loadStrategies().then(list => setStrategies(list ?? []));
}, []);
const refreshStrategies = useCallback(async () => {
const list = await loadStrategies();
const next = list ?? [];
setStrategies(next);
if (selectedStrategyId == null) return;
const still = next.find(s => s.id === selectedStrategyId);
if (still) {
setSelectedStrategy(hydrateStrategyDto(still));
return;
}
setSelectedStrategyId(null);
setSelectedStrategy(null);
setAppliedIndicatorParams(null);
setParamsRevision(v => v + 1);
}, [selectedStrategyId]);
const handleCloseStrategyEditor = useCallback(() => {
setEditorModalOpen(false);
void refreshStrategies();
}, [refreshStrategies]);
useEffect(() => {
if (!selectedStrategyId) {
setSelectedStrategy(null);
@@ -308,26 +331,41 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
>
<aside className={`btd-sidebar seval-left-sidebar${leftOpen ? ' seval-left-sidebar--open' : ''}`}>
<div className="btd-exec-list seval-left-panel">
<div className="btd-exec-tabs" role="tablist">
<button
type="button"
role="tab"
aria-selected={leftTab === 'strategy'}
className={`btd-exec-tab${leftTab === 'strategy' ? ' btd-exec-tab--on' : ''}`}
onClick={() => setLeftTab('strategy')}
>
</button>
<button
type="button"
role="tab"
aria-selected={leftTab === 'settings'}
className={`btd-exec-tab${leftTab === 'settings' ? ' btd-exec-tab--on' : ''}`}
onClick={() => setLeftTab('settings')}
disabled={!selectedStrategy}
>
</button>
<div className="seval-left-tabs-row">
<div className="btd-exec-tabs" role="tablist">
<button
type="button"
role="tab"
aria-selected={leftTab === 'strategy'}
className={`btd-exec-tab${leftTab === 'strategy' ? ' btd-exec-tab--on' : ''}`}
onClick={() => setLeftTab('strategy')}
>
</button>
<button
type="button"
role="tab"
aria-selected={leftTab === 'settings'}
className={`btd-exec-tab${leftTab === 'settings' ? ' btd-exec-tab--on' : ''}`}
onClick={() => setLeftTab('settings')}
disabled={!selectedStrategy}
>
</button>
</div>
{leftTab === 'strategy' && (
<button
type="button"
className="seval-strategy-add-btn"
title="전략 추가·편집"
aria-label="전략 추가·편집"
onClick={() => setEditorModalOpen(true)}
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" aria-hidden>
<path d="M12 5v14M5 12h14" strokeLinecap="round" />
</svg>
</button>
)}
</div>
{leftTab === 'strategy' ? (
@@ -487,6 +525,15 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
</footer>
</aside>
</div>
{editorModalOpen && (
<StrategyEditorModal
theme={theme}
initialStrategyId={selectedStrategyId}
onClose={handleCloseStrategyEditor}
onStrategiesChanged={() => { void refreshStrategies(); }}
/>
)}
</div>
);
}