[v2.0.0] AgentSettingsPanel 기능 완성 — 서비스·모델·작업폴더·MCP

AgentSettingsPanel.xaml.cs:
- BtnServiceSelector_Click: ServiceSelectorRequested 콜백 실행 (ChatWindow 위임)
- BtnModelSelector_Click: ModelSelectorRequested 콜백 실행 (ChatWindow 위임)
- ServiceSelectorRequested / ModelSelectorRequested / WorkFolderBrowseRequested Action 추가
- LoadFromSettings: UpdateWorkFolder() + BuildMcpServerList() 호출 추가
- LoadFromSettings: PanelWorkFolder 가시성 제어 추가
- UpdateActiveTab: PanelWorkFolder 가시성 제어 추가
- BtnWorkFolderBrowse_Click, UpdateWorkFolder, BuildMcpServerList, McpToggle_Changed 추가
- using System.Linq / using AxCopilot.Models 추가

AgentSettingsPanel.xaml:
- PanelWorkFolder 섹션 추가 (Code 탭 전용 — 폴더 표시 + 탐색 버튼)
- PanelMcpServers 섹션 추가 (도구 관리 뒤, 고급 앞)

ChatWindow.MoodMenu.cs:
- ToggleSettingsPanel(): 패널 열 때 ServiceSelector/ModelSelector/WorkFolder 콜백 연결

빌드: 경고 0, 오류 0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 08:38:51 +09:00
parent 0e8d58d3aa
commit 23d1534536
3 changed files with 166 additions and 3 deletions

View File

@@ -447,6 +447,10 @@ public partial class ChatWindow
SettingsPanel.CloseRequested += OnSettingsPanelClose;
SettingsPanel.SettingsChanged -= OnSettingsPanelChanged;
SettingsPanel.SettingsChanged += OnSettingsPanelChanged;
// 콜백 연결 — ChatWindow 기존 구현에 위임
SettingsPanel.ServiceSelectorRequested = () => BtnModelSelector_Click(BtnModelSelector, new System.Windows.RoutedEventArgs());
SettingsPanel.ModelSelectorRequested = () => BtnModelSelector_Click(BtnModelSelector, new System.Windows.RoutedEventArgs());
SettingsPanel.WorkFolderBrowseRequested = () => BrowseWorkFolder();
SettingsPanel.IsOpen = true;
}
}

View File

@@ -291,6 +291,44 @@
</Grid>
</StackPanel>
<!-- 작업 폴더 (Code 탭 전용) -->
<StackPanel x:Name="PanelWorkFolder" Visibility="Collapsed" Margin="0,8,0,0">
<Grid Margin="0,0,0,6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="작업 폴더" Foreground="{DynamicResource SecondaryText}" FontSize="12"
VerticalAlignment="Center"/>
</Grid>
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Background="{DynamicResource HintBackground}" CornerRadius="6" Padding="8,5">
<TextBlock x:Name="TxtWorkFolder" Text="(미지정)" FontSize="11"
Foreground="{DynamicResource SecondaryText}"
TextTrimming="CharacterEllipsis" MaxWidth="170"/>
</Border>
<Border Grid.Column="1" CornerRadius="6" Padding="10,5" Margin="6,0,0,0" Cursor="Hand"
MouseLeftButtonUp="BtnWorkFolderBrowse_Click">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="{DynamicResource ItemBackground}"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource ItemHoverBackground}"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="&#xE838;" FontFamily="Segoe MDL2 Assets" FontSize="12"
Foreground="#FFB74D" VerticalAlignment="Center"/>
</Border>
</Grid>
</StackPanel>
<Border Height="1" Background="{DynamicResource BorderColor}" Margin="0,8,0,16"/>
<!-- ═══ 도구 관리 ═══ -->
@@ -303,6 +341,16 @@
<Border Height="1" Background="{DynamicResource BorderColor}" Margin="0,8,0,16"/>
<!-- ═══ MCP 서버 ═══ -->
<TextBlock Text="MCP 서버" FontSize="13" FontWeight="SemiBold"
Foreground="{DynamicResource PrimaryText}" Margin="0,0,0,8"/>
<StackPanel x:Name="PanelMcpServers" Margin="0,0,0,8">
<!-- 코드비하인드에서 동적 생성 -->
</StackPanel>
<Border Height="1" Background="{DynamicResource BorderColor}" Margin="0,8,0,16"/>
<!-- ═══ 고급 ═══ -->
<TextBlock Text="고급" FontSize="13" FontWeight="SemiBold"
Foreground="{DynamicResource PrimaryText}" Margin="0,0,0,8"/>

View File

@@ -1,7 +1,9 @@
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using AxCopilot.Models;
using AxCopilot.Services;
namespace AxCopilot.Views.Controls;
@@ -18,6 +20,15 @@ public partial class AgentSettingsPanel : UserControl
private bool _isOpen;
private bool _isLoading = true; // 초기 로드 중 이벤트 발생 방지
/// <summary>서비스 선택 요청 콜백 (ChatWindow.BtnModelSelector_Click으로 위임).</summary>
public Action? ServiceSelectorRequested;
/// <summary>모델 선택 요청 콜백 (ChatWindow.BtnModelSelector_Click으로 위임).</summary>
public Action? ModelSelectorRequested;
/// <summary>작업 폴더 탐색 요청 콜백 (ChatWindow.BrowseWorkFolder로 위임).</summary>
public Action? WorkFolderBrowseRequested;
/// <summary>설정 패널 열림/닫힘 상태.</summary>
public bool IsOpen
{
@@ -78,6 +89,7 @@ public partial class AgentSettingsPanel : UserControl
// 탭별 설정 표시
PanelCoworkSettings.Visibility = activeTab == "Cowork" ? Visibility.Visible : Visibility.Collapsed;
PanelCodeSettings.Visibility = activeTab == "Code" ? Visibility.Visible : Visibility.Collapsed;
PanelWorkFolder.Visibility = activeTab == "Code" ? Visibility.Visible : Visibility.Collapsed;
if (activeTab == "Cowork")
{
@@ -92,6 +104,11 @@ public partial class AgentSettingsPanel : UserControl
// 도구 토글 동적 생성
BuildToolToggles(settings, toolRegistry);
// 작업 폴더 표시 (Code 탭)
UpdateWorkFolder(settings);
// MCP 서버 목록 표시
BuildMcpServerList(settings);
_isLoading = false;
}
@@ -100,7 +117,8 @@ public partial class AgentSettingsPanel : UserControl
{
TxtCurrentTab.Text = tab;
PanelCoworkSettings.Visibility = tab == "Cowork" ? Visibility.Visible : Visibility.Collapsed;
PanelCodeSettings.Visibility = tab == "Code" ? Visibility.Visible : Visibility.Collapsed;
PanelCodeSettings.Visibility = tab == "Code" ? Visibility.Visible : Visibility.Collapsed;
PanelWorkFolder.Visibility = tab == "Code" ? Visibility.Visible : Visibility.Collapsed;
}
private void BuildToolToggles(SettingsService settings,
@@ -159,12 +177,105 @@ public partial class AgentSettingsPanel : UserControl
private void BtnServiceSelector_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// TODO: 서비스 선택 팝업 (Ollama/vLLM/Gemini/Claude)
ServiceSelectorRequested?.Invoke();
}
private void BtnModelSelector_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// TODO: 모델 선택 팝업 — ChatWindow의 기존 모델 선택 로직 재사용
ModelSelectorRequested?.Invoke();
}
private void BtnWorkFolderBrowse_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
WorkFolderBrowseRequested?.Invoke();
}
private void UpdateWorkFolder(SettingsService settings)
{
var folder = settings.Settings.Llm.WorkFolder;
if (TxtWorkFolder == null) return;
TxtWorkFolder.Text = string.IsNullOrWhiteSpace(folder)
? "(미지정)"
: System.IO.Path.GetFileName(folder) is { Length: > 0 } name ? name : folder;
TxtWorkFolder.ToolTip = folder;
}
private void BuildMcpServerList(SettingsService settings)
{
if (PanelMcpServers == null) return;
PanelMcpServers.Children.Clear();
var servers = settings.Settings.Llm.McpServers;
if (servers == null || servers.Count == 0)
{
PanelMcpServers.Children.Add(new TextBlock
{
Text = "등록된 MCP 서버 없음",
FontSize = 11,
Foreground = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray,
Margin = new Thickness(0, 0, 0, 4),
});
return;
}
foreach (var server in servers)
{
var grid = new System.Windows.Controls.Grid { Margin = new Thickness(0, 0, 0, 6) };
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(8) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
var dot = new System.Windows.Shapes.Ellipse
{
Width = 6, Height = 6,
Fill = server.Enabled
? new SolidColorBrush(Color.FromRgb(0x38, 0xA1, 0x69))
: new SolidColorBrush(Color.FromRgb(0x9E, 0x9E, 0x9E)),
VerticalAlignment = VerticalAlignment.Center,
};
Grid.SetColumn(dot, 0);
var nameLabel = new TextBlock
{
Text = server.Name,
FontSize = 11,
Foreground = TryFindResource("PrimaryText") as Brush ?? Brushes.White,
VerticalAlignment = VerticalAlignment.Center,
Margin = new Thickness(6, 0, 0, 0),
TextTrimming = System.Windows.TextTrimming.CharacterEllipsis,
};
Grid.SetColumn(nameLabel, 1);
var chk = new CheckBox
{
IsChecked = server.Enabled,
Tag = server.Name,
VerticalAlignment = VerticalAlignment.Center,
};
if (TryFindResource("ToggleSwitch") is Style toggleStyle)
chk.Style = toggleStyle;
chk.Checked += McpToggle_Changed;
chk.Unchecked += McpToggle_Changed;
Grid.SetColumn(chk, 2);
grid.Children.Add(dot);
grid.Children.Add(nameLabel);
grid.Children.Add(chk);
PanelMcpServers.Children.Add(grid);
}
}
private void McpToggle_Changed(object sender, RoutedEventArgs e)
{
if (_isLoading || sender is not CheckBox chk || chk.Tag is not string name) return;
var app = System.Windows.Application.Current as App;
var settings = app?.SettingsService;
if (settings == null) return;
var server = settings.Settings.Llm.McpServers?.FirstOrDefault(s => s.Name == name);
if (server == null) return;
server.Enabled = chk.IsChecked == true;
settings.Save();
SettingsChanged?.Invoke(this, EventArgs.Empty);
}
private void TxtApiEndpoint_LostFocus(object sender, RoutedEventArgs e)