From 9aa99cdfe656e463d419a18eff984040bcf5ebd7 Mon Sep 17 00:00:00 2001 From: lacvet Date: Mon, 6 Apr 2026 11:37:44 +0900 Subject: [PATCH] =?UTF-8?q?AX=20Agent=20=EB=8C=80=ED=99=94=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=ED=95=84=ED=84=B0=20=ED=94=84=EB=A0=88=EC=A0=A0?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20?= =?UTF-8?q?=EC=82=AC=EC=9D=B4=EB=93=9C=EB=B0=94=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ChatWindow에서 대화 목록 필터/정렬 interaction과 선호 저장 로직을 ConversationFilterPresentation partial로 분리 - 실행 중 보기, 최근/활동 정렬, 관련 버튼 UI 갱신을 메인 창 orchestration 코드 밖으로 이동 - README와 DEVELOPMENT 문서에 2026-04-06 11:11 (KST) 기준 구조 개선 누적 완료 범위 반영 - dotnet build 검증 경고 0, 오류 0 확인 --- README.md | 3 + docs/DEVELOPMENT.md | 2 + ...atWindow.ConversationFilterPresentation.cs | 116 ++++++++++++++++++ src/AxCopilot/Views/ChatWindow.xaml.cs | 107 ---------------- 4 files changed, 121 insertions(+), 107 deletions(-) create mode 100644 src/AxCopilot/Views/ChatWindow.ConversationFilterPresentation.cs diff --git a/README.md b/README.md index dff65ca..d3272ae 100644 --- a/README.md +++ b/README.md @@ -1194,3 +1194,6 @@ MIT License - 업데이트: 2026-04-06 11:03 (KST) - 좌측 sidebar의 검색/새 대화 interaction을 [ChatWindow.SidebarInteractionPresentation.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.SidebarInteractionPresentation.cs) 로 분리했다. 검색 트리거 hover, 새 대화 hover, 검색 열기/닫기 애니메이션이 메인 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 밖으로 이동해, 메인 창은 runtime/transcript orchestration에 더 집중하고 sidebar UX는 별도 presentation surface에서 다루게 정리했다. - 큰 구조 개선 계획 기준으로는 이제 sidebar interaction까지 분리 완료 상태이며, 이후 남는 작업은 공통 시각 언어 polish나 실제 사용 흐름 기반 미세 UX 튜닝 같은 후속 개선 영역이다. +- 업데이트: 2026-04-06 11:11 (KST) + - 좌측 대화 목록의 필터/정렬 interaction을 [ChatWindow.ConversationFilterPresentation.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.ConversationFilterPresentation.cs) 로 분리했다. 실행 중 보기, 최근/활동 정렬, 대화 목록 선호 저장/복원, 관련 버튼 UI 상태 갱신이 메인 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 밖으로 이동해 sidebar 상태 표현 책임이 더 응집도 있게 정리됐다. + - 이 단계까지 누적 완료된 구조 개선은 상태선/권한/도구 결과 카탈로그화, inline ask/plan 분리, footer/Git/preset/list/message/timeline/conversation management/sidebar interaction/filter 분리까지다. 이제 남는 건 큰 분리가 아니라 실제 시나리오 기반 polish와 공통 시각 언어 고도화다. diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index ca05bdb..4ae5489 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -4933,3 +4933,5 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎. - Document update: 2026-04-06 10:56 (KST) - With this pass, the remaining large structure-improvement track is effectively complete; follow-up work is now mostly UX polish and surface-level tuning rather than further decomposition of the main chat window orchestration file. - Document update: 2026-04-06 11:03 (KST) - Split sidebar search/new-chat interactions out of `ChatWindow.xaml.cs` into `ChatWindow.SidebarInteractionPresentation.cs`. Hover state changes, sidebar search open/close transitions, and new-chat trigger behavior now live in a dedicated presentation partial. - Document update: 2026-04-06 11:03 (KST) - This leaves the main chat window even more orchestration-focused and effectively closes the last obvious sidebar interaction block from the large structure-improvement plan. Remaining work is now follow-up UX polish rather than major decomposition. +- Document update: 2026-04-06 11:11 (KST) - Split conversation list filter/sort interactions and preference persistence out of `ChatWindow.xaml.cs` into `ChatWindow.ConversationFilterPresentation.cs`. Running-only toggles, recent/activity sort toggles, UI-state refresh, and conversation-list preference apply/persist logic now live in a dedicated presentation partial. +- Document update: 2026-04-06 11:11 (KST) - This keeps sidebar state presentation more cohesive and further narrows the main chat window file toward orchestration-only responsibilities. Remaining work is now post-plan polish rather than another major structural split. diff --git a/src/AxCopilot/Views/ChatWindow.ConversationFilterPresentation.cs b/src/AxCopilot/Views/ChatWindow.ConversationFilterPresentation.cs new file mode 100644 index 0000000..10e25b4 --- /dev/null +++ b/src/AxCopilot/Views/ChatWindow.ConversationFilterPresentation.cs @@ -0,0 +1,116 @@ +using System; +using System.Windows; +using System.Windows.Media; +using AxCopilot.Models; + +namespace AxCopilot.Views; + +public partial class ChatWindow +{ + private void BtnFailedOnlyFilter_Click(object sender, RoutedEventArgs e) { } + + private void BtnRunningOnlyFilter_Click(object sender, RoutedEventArgs e) + { + _runningOnlyFilter = false; + UpdateConversationRunningFilterUi(); + PersistConversationListPreferences(); + RefreshConversationList(); + } + + private void BtnQuickRunningFilter_Click(object sender, RoutedEventArgs e) + => BtnRunningOnlyFilter_Click(sender, e); + + private void BtnQuickHotSort_Click(object sender, RoutedEventArgs e) + { + _sortConversationsByRecent = false; + UpdateConversationSortUi(); + PersistConversationListPreferences(); + RefreshConversationList(); + } + + private void BtnConversationSort_Click(object sender, RoutedEventArgs e) + { + _sortConversationsByRecent = !_sortConversationsByRecent; + UpdateConversationSortUi(); + PersistConversationListPreferences(); + RefreshConversationList(); + } + + private void UpdateConversationFailureFilterUi() + { + _failedOnlyFilter = false; + UpdateSidebarModeMenu(); + } + + private void UpdateConversationRunningFilterUi() + { + if (BtnRunningOnlyFilter == null || RunningOnlyFilterLabel == null) + return; + + BtnRunningOnlyFilter.Background = _runningOnlyFilter + ? BrushFromHex("#DBEAFE") + : Brushes.Transparent; + BtnRunningOnlyFilter.BorderBrush = _runningOnlyFilter + ? BrushFromHex("#93C5FD") + : Brushes.Transparent; + BtnRunningOnlyFilter.BorderThickness = _runningOnlyFilter + ? new Thickness(1) + : new Thickness(0); + RunningOnlyFilterLabel.Foreground = _runningOnlyFilter + ? BrushFromHex("#1D4ED8") + : (TryFindResource("SecondaryText") as Brush ?? Brushes.Gray); + RunningOnlyFilterLabel.Text = _runningConversationCount > 0 + ? $"진행 {_runningConversationCount}" + : "진행"; + BtnRunningOnlyFilter.ToolTip = _runningOnlyFilter + ? "실행 중인 대화만 표시 중" + : _runningConversationCount > 0 + ? $"현재 실행 중인 대화 {_runningConversationCount}개 보기" + : "현재 실행 중인 대화만 보기"; + UpdateSidebarModeMenu(); + } + + private void UpdateConversationSortUi() + { + if (BtnConversationSort == null || ConversationSortLabel == null) + return; + + ConversationSortLabel.Text = _sortConversationsByRecent ? "최근" : "활동"; + BtnConversationSort.Background = _sortConversationsByRecent + ? BrushFromHex("#EFF6FF") + : BrushFromHex("#F8FAFC"); + BtnConversationSort.BorderBrush = _sortConversationsByRecent + ? BrushFromHex("#93C5FD") + : BrushFromHex("#E2E8F0"); + BtnConversationSort.BorderThickness = new Thickness(1); + ConversationSortLabel.Foreground = _sortConversationsByRecent + ? BrushFromHex("#1D4ED8") + : (TryFindResource("SecondaryText") as Brush ?? Brushes.Gray); + BtnConversationSort.ToolTip = _sortConversationsByRecent + ? "최신 업데이트 순으로 보는 중" + : "에이전트 활동량과 실패를 우선으로 보는 중"; + } + + private void ApplyConversationListPreferences(ChatConversation? conv) + { + _failedOnlyFilter = false; + _runningOnlyFilter = false; + _sortConversationsByRecent = string.Equals(conv?.ConversationSortMode, "recent", StringComparison.OrdinalIgnoreCase); + UpdateConversationFailureFilterUi(); + UpdateConversationRunningFilterUi(); + UpdateConversationSortUi(); + } + + private void PersistConversationListPreferences() + { + lock (_convLock) + { + var session = _appState.ChatSession; + if (session == null) + return; + + session.SaveConversationListPreferences(_activeTab, _failedOnlyFilter, _runningOnlyFilter, _sortConversationsByRecent, _storage); + _currentConversation = session.CurrentConversation; + } + } +} diff --git a/src/AxCopilot/Views/ChatWindow.xaml.cs b/src/AxCopilot/Views/ChatWindow.xaml.cs index 4cfa2fc..b572378 100644 --- a/src/AxCopilot/Views/ChatWindow.xaml.cs +++ b/src/AxCopilot/Views/ChatWindow.xaml.cs @@ -2093,90 +2093,6 @@ public partial class ChatWindow : Window _conversationSearchTimer.Start(); } - private void BtnFailedOnlyFilter_Click(object sender, RoutedEventArgs e) { } - - private void BtnRunningOnlyFilter_Click(object sender, RoutedEventArgs e) - { - _runningOnlyFilter = false; - UpdateConversationRunningFilterUi(); - PersistConversationListPreferences(); - RefreshConversationList(); - } - - private void BtnQuickRunningFilter_Click(object sender, RoutedEventArgs e) - => BtnRunningOnlyFilter_Click(sender, e); - - private void BtnQuickHotSort_Click(object sender, RoutedEventArgs e) - { - _sortConversationsByRecent = false; - UpdateConversationSortUi(); - PersistConversationListPreferences(); - RefreshConversationList(); - } - - private void BtnConversationSort_Click(object sender, RoutedEventArgs e) - { - _sortConversationsByRecent = !_sortConversationsByRecent; - UpdateConversationSortUi(); - PersistConversationListPreferences(); - RefreshConversationList(); - } - - private void UpdateConversationFailureFilterUi() - { - _failedOnlyFilter = false; - UpdateSidebarModeMenu(); - } - - private void UpdateConversationRunningFilterUi() - { - if (BtnRunningOnlyFilter == null || RunningOnlyFilterLabel == null) - return; - - BtnRunningOnlyFilter.Background = _runningOnlyFilter - ? BrushFromHex("#DBEAFE") - : Brushes.Transparent; - BtnRunningOnlyFilter.BorderBrush = _runningOnlyFilter - ? BrushFromHex("#93C5FD") - : Brushes.Transparent; - BtnRunningOnlyFilter.BorderThickness = _runningOnlyFilter - ? new Thickness(1) - : new Thickness(0); - RunningOnlyFilterLabel.Foreground = _runningOnlyFilter - ? BrushFromHex("#1D4ED8") - : (TryFindResource("SecondaryText") as Brush ?? Brushes.Gray); - RunningOnlyFilterLabel.Text = _runningConversationCount > 0 - ? $"진행 {_runningConversationCount}" - : "진행"; - BtnRunningOnlyFilter.ToolTip = _runningOnlyFilter - ? "실행 중인 대화만 표시 중" - : _runningConversationCount > 0 - ? $"현재 실행 중인 대화 {_runningConversationCount}개 보기" - : "현재 실행 중인 대화만 보기"; - UpdateSidebarModeMenu(); - } - - private void UpdateConversationSortUi() - { - if (BtnConversationSort == null || ConversationSortLabel == null) - return; - - ConversationSortLabel.Text = _sortConversationsByRecent ? "최근" : "활동"; - BtnConversationSort.Background = _sortConversationsByRecent - ? BrushFromHex("#EFF6FF") - : BrushFromHex("#F8FAFC"); - BtnConversationSort.BorderBrush = _sortConversationsByRecent - ? BrushFromHex("#93C5FD") - : BrushFromHex("#E2E8F0"); - BtnConversationSort.BorderThickness = new Thickness(1); - ConversationSortLabel.Foreground = _sortConversationsByRecent - ? BrushFromHex("#1D4ED8") - : (TryFindResource("SecondaryText") as Brush ?? Brushes.Gray); - BtnConversationSort.ToolTip = _sortConversationsByRecent - ? "최신 업데이트 순으로 보는 중" - : "에이전트 활동량과 실패를 우선으로 보는 중"; - } - private static string FormatDate(DateTime dt) { var diff = DateTime.Now - dt; @@ -6259,29 +6175,6 @@ public partial class ChatWindow : Window UpdateTaskSummaryIndicators(); } - private void ApplyConversationListPreferences(ChatConversation? conv) - { - _failedOnlyFilter = false; - _runningOnlyFilter = false; - _sortConversationsByRecent = string.Equals(conv?.ConversationSortMode, "recent", StringComparison.OrdinalIgnoreCase); - UpdateConversationFailureFilterUi(); - UpdateConversationRunningFilterUi(); - UpdateConversationSortUi(); - } - - private void PersistConversationListPreferences() - { - lock (_convLock) - { - var session = _appState.ChatSession; - if (session == null) - return; - - session.SaveConversationListPreferences(_activeTab, _failedOnlyFilter, _runningOnlyFilter, _sortConversationsByRecent, _storage); - _currentConversation = session.CurrentConversation; - } - } - private static string GetRunStatusLabel(string? status) => status switch {