전략평가 목록 정렬

This commit is contained in:
Macbook
2026-06-23 00:49:18 +09:00
parent c63775bba6
commit 32be015b49
3 changed files with 130 additions and 2 deletions
@@ -47,6 +47,15 @@ import {
type BacktestRunTimeframeChoice,
} from '../utils/backtestRunTimeframe';
import { resolveBarSignalHighlight } from '../utils/strategyEvaluationBarSignals';
import {
loadStrategyListSort,
saveStrategyListSort,
sortStrategies,
strategyListSortLabel,
toggleStrategyListSort,
type StrategyListSort,
type StrategyListSortField,
} from '../utils/strategyEvaluationListSort';
import type { OHLCVBar } from '../types';
import BacktestAnalysisReportModal from './backtest/BacktestAnalysisReportModal';
import type { BacktestAnalysisReportModel } from './backtest/BacktestAnalysisReportModal';
@@ -132,6 +141,7 @@ function StrategyEvaluationPageInner({ theme = 'dark' }: Props) {
const [marketSearchOpen, setMarketSearchOpen] = useState(false);
const [strategies, setStrategies] = useState<StrategyDto[]>([]);
const [strategySearch, setStrategySearch] = useState('');
const [strategyListSort, setStrategyListSort] = useState<StrategyListSort>(loadStrategyListSort);
const [selectedStrategyId, setSelectedStrategyId] = useState<number | null>(null);
const [selectedStrategy, setSelectedStrategy] = useState<StrategyDto | null>(null);
@@ -416,6 +426,19 @@ function StrategyEvaluationPageInner({ theme = 'dark' }: Props) {
);
}, [strategies, strategySearch]);
const sortedFilteredStrategies = useMemo(
() => sortStrategies(filteredStrategies, strategyListSort),
[filteredStrategies, strategyListSort],
);
const handleStrategyListSort = useCallback((field: StrategyListSortField) => {
setStrategyListSort(prev => {
const next = toggleStrategyListSort(prev, field);
saveStrategyListSort(next);
return next;
});
}, []);
const selectedBarTimeSec = bars[selectedBarIndex]?.time ?? null;
useEffect(() => {
@@ -953,11 +976,31 @@ function StrategyEvaluationPageInner({ theme = 'dark' }: Props) {
</button>
)}
</div>
<div className="btd-exec-filters seval-strategy-list-sort" role="group" aria-label="전략 목록 정렬">
<button
type="button"
className={`btd-exec-filter${strategyListSort.field === 'name' ? ' btd-exec-filter--on' : ''}`}
title="이름순 — 클릭할 때마다 오름차순·내림차순 전환"
aria-pressed={strategyListSort.field === 'name'}
onClick={() => handleStrategyListSort('name')}
>
{strategyListSortLabel(strategyListSort, 'name')}
</button>
<button
type="button"
className={`btd-exec-filter${strategyListSort.field === 'createdAt' ? ' btd-exec-filter--on' : ''}`}
title="추가 일시 기준 — 클릭할 때마다 최신순·오래된순 전환"
aria-pressed={strategyListSort.field === 'createdAt'}
onClick={() => handleStrategyListSort('createdAt')}
>
{strategyListSortLabel(strategyListSort, 'createdAt')}
</button>
</div>
<div className="btd-exec-scroll">
{filteredStrategies.length === 0 ? (
{sortedFilteredStrategies.length === 0 ? (
<p className="btd-sidebar-empty"> </p>
) : (
filteredStrategies.map(s => {
sortedFilteredStrategies.map(s => {
const name = repairUtf8Mojibake(s.name ?? `전략 #${s.id}`);
const active = selectedStrategyId === s.id;
return (