연속 개선: 권한 상태 간소화·설정창 외부 진입 안정화·컴포저 반응형 보강
Some checks failed
Release Gate / gate (push) Has been cancelled
Some checks failed
Release Gate / gate (push) Has been cancelled
- 권한 상태 텍스트(/permissions,/allowed-tools)를 운영 모드 포함 축약형으로 재정리 - 하단 권한 버튼 툴팁에 운영 모드/기본값/예외 개수 정보를 일관 반영 - 탭 전환 시 좌측 메뉴 Visibility 재할당을 최소화해 UI 흔들림 완화 - 상단 모델 라벨에 MaxWidth+말줄임 적용으로 긴 모델명 레이아웃 깨짐 방지 - AX Agent 설정창 오픈 시 리소스 병합 예외를 방어하고 외부 진입 경로를 Dispatcher 기반으로 안정화 - UI 체크리스트/개발문서/README에 2026-04-04 12:41 기준 점검 이력 업데이트 - 검증: build 경고0/오류0, 운영모드 필터 18건 통과, 전체 테스트 436건 통과
This commit is contained in:
@@ -222,7 +222,7 @@ public class MyHandler : IActionHandler
|
|||||||
|
|
||||||
### v0.7.3 — AX Agent 권한 코어 재구성 + 입력 계층 정리
|
### v0.7.3 — AX Agent 권한 코어 재구성 + 입력 계층 정리
|
||||||
|
|
||||||
업데이트: 2026-04-04 12:33 (KST)
|
업데이트: 2026-04-04 12:41 (KST)
|
||||||
|
|
||||||
| 분류 | 내용 |
|
| 분류 | 내용 |
|
||||||
|------|------|
|
|------|------|
|
||||||
@@ -270,6 +270,9 @@ public class MyHandler : IActionHandler
|
|||||||
| 권한 팝업 밀도 재정돈 | 권한 섹션 헤더/카드/행의 패딩·폰트·줄간격을 조정해 과밀 영역을 완화하고 Codex/Claude형 스캔 속도에 맞춤 |
|
| 권한 팝업 밀도 재정돈 | 권한 섹션 헤더/카드/행의 패딩·폰트·줄간격을 조정해 과밀 영역을 완화하고 Codex/Claude형 스캔 속도에 맞춤 |
|
||||||
| 좌측/컴포저 라벨 정리 | 좌측 기본 카테고리 라벨을 `주제 선택/작업 선택`으로 통일하고, 입력 상단 바 패딩·간격을 미세 조정해 단일 라인 정돈 강화 |
|
| 좌측/컴포저 라벨 정리 | 좌측 기본 카테고리 라벨을 `주제 선택/작업 선택`으로 통일하고, 입력 상단 바 패딩·간격을 미세 조정해 단일 라인 정돈 강화 |
|
||||||
| 체크리스트 실행 결과 기록 | `docs/UI_UX_CHECKLIST.md`에 2026-04-04 12:22 기준 점검 결과(운영모드 필터 18건 + 전체 436건 통과)를 기록 |
|
| 체크리스트 실행 결과 기록 | `docs/UI_UX_CHECKLIST.md`에 2026-04-04 12:22 기준 점검 결과(운영모드 필터 18건 + 전체 436건 통과)를 기록 |
|
||||||
|
| 권한 상태 표시 간소화 | 권한 상태 텍스트(`/permissions`, `/allowed-tools`)를 운영 모드 포함 축약형으로 정리하고 권한 버튼 툴팁에 동일 정보를 반영 |
|
||||||
|
| 설정창 외부 진입 안정화 | AX Agent 설정창 오픈 시 리소스 병합 실패를 방어하고, 외부 진입 경로를 Dispatcher 기반으로 안정화 |
|
||||||
|
| 모델 라벨 반응형 보강 | 컴포저 상단 모델 라벨에 말줄임(`MaxWidth` + `CharacterEllipsis`)을 적용해 좁은 폭에서 레이아웃 깨짐을 방지 |
|
||||||
| Slash palette 상태 분리 시작 | `ChatWindow`에 몰려 있던 slash 상태를 `SlashPaletteState`로 분리해 이후 Codex/Claude형 composer 개편 기반 마련 |
|
| Slash palette 상태 분리 시작 | `ChatWindow`에 몰려 있던 slash 상태를 `SlashPaletteState`로 분리해 이후 Codex/Claude형 composer 개편 기반 마련 |
|
||||||
| 런처 이미지 미리보기 추가 | `#` 클립보드 이미지 항목에서 `Shift+Enter`로 전용 미리보기 창을 열고, 줌·원본 해상도 확인·PNG/JPEG/BMP 저장·클립보드 복사를 지원 |
|
| 런처 이미지 미리보기 추가 | `#` 클립보드 이미지 항목에서 `Shift+Enter`로 전용 미리보기 창을 열고, 줌·원본 해상도 확인·PNG/JPEG/BMP 저장·클립보드 복사를 지원 |
|
||||||
| 검증 | `dotnet build` 경고 0 / 오류 0, `dotnet test` 436 passed / 0 failed |
|
| 검증 | `dotnet build` 경고 0 / 오류 0, `dotnet test` 436 passed / 0 failed |
|
||||||
|
|||||||
@@ -3239,6 +3239,37 @@ else:
|
|||||||
- `dotnet build src/AxCopilot/AxCopilot.csproj` 통과 (경고 0, 오류 0).
|
- `dotnet build src/AxCopilot/AxCopilot.csproj` 통과 (경고 0, 오류 0).
|
||||||
- `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj` 통과 (436 passed, 0 failed).
|
- `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj` 통과 (436 passed, 0 failed).
|
||||||
|
|
||||||
|
## 2026-04-04 추가 진행 기록 (연속 실행 24차: 권한/설정 안정화 보강 + 시나리오 점검)
|
||||||
|
|
||||||
|
업데이트: 2026-04-04 12:41 (KST)
|
||||||
|
|
||||||
|
### 1) 권한 상태 표시 간소화
|
||||||
|
- `/permissions`, `/allowed-tools` 상태 텍스트를 축약형으로 재정리:
|
||||||
|
- 현재 권한 모드
|
||||||
|
- 운영 모드
|
||||||
|
- 기본값/예외 개수
|
||||||
|
- 예외 미리보기(최대 3개)
|
||||||
|
- 하단 권한 버튼 툴팁에도 동일한 운영 모드/기본값/예외 정보를 반영.
|
||||||
|
|
||||||
|
### 2) 좌측 패널 전환 안정화
|
||||||
|
- `UpdateSidebarModeMenu()`에서 탭별 메뉴 표시를 동일 값 재할당하지 않도록 보강해 전환 시 불필요한 렌더 흔들림을 완화.
|
||||||
|
|
||||||
|
### 3) 컴포저 반응형 보강
|
||||||
|
- 상단 모델 라벨에 `MaxWidth=280`, `TextTrimming=CharacterEllipsis` 적용.
|
||||||
|
- 긴 모델명 선택 시 컴포저 레이아웃 깨짐을 방지.
|
||||||
|
|
||||||
|
### 4) AX Agent 설정창 오픈 안정성 보강
|
||||||
|
- 설정창 리소스 병합 실패 시에도 창 오픈이 유지되도록 예외 방어 추가.
|
||||||
|
- `OpenAgentSettingsFromExternal()`를 Dispatcher 경유로 변경해 트레이/외부 진입 시 타이밍 이슈를 완화.
|
||||||
|
|
||||||
|
### 5) 시나리오/회귀 점검
|
||||||
|
- 운영 모드 필터 테스트(18건) 재통과:
|
||||||
|
- `OperationModePolicyTests`
|
||||||
|
- `OperationModeReadinessTests`
|
||||||
|
- `LlmOperationModeTests`
|
||||||
|
- 전체 테스트 436건 재통과.
|
||||||
|
- `dotnet build` 경고 0 / 오류 0 유지.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -54,3 +54,12 @@
|
|||||||
- [x] AX Agent 설정 권한 순환 순서와 `/sandbox-toggle` 순환 순서 일치 확인
|
- [x] AX Agent 설정 권한 순환 순서와 `/sandbox-toggle` 순환 순서 일치 확인
|
||||||
- [x] 운영 모드 회귀 필터 테스트 18건 통과 (`OperationModePolicy/Readiness/LlmOperationMode`)
|
- [x] 운영 모드 회귀 필터 테스트 18건 통과 (`OperationModePolicy/Readiness/LlmOperationMode`)
|
||||||
- [x] 전체 테스트 436건 통과
|
- [x] 전체 테스트 436건 통과
|
||||||
|
|
||||||
|
점검 시각: 2026-04-04 12:41 (KST)
|
||||||
|
|
||||||
|
- [x] 권한 버튼 툴팁에 운영 모드 + 기본 권한 + 예외 개수 표시 확인
|
||||||
|
- [x] 권한 상태 텍스트(`/permissions`, `/allowed-tools`)를 축약형으로 정리 확인
|
||||||
|
- [x] 모델 라벨 말줄임 처리(`MaxWidth`, `CharacterEllipsis`) 적용 확인
|
||||||
|
- [x] 설정창 외부 진입(`OpenAgentSettingsFromExternal`) Dispatcher 경유 오픈 경로 확인
|
||||||
|
- [x] 운영 모드 필터 테스트 18건 재통과
|
||||||
|
- [x] 전체 테스트 436건 재통과
|
||||||
|
|||||||
@@ -1115,6 +1115,8 @@
|
|||||||
VerticalAlignment="Center" Margin="0,0,5,0"/>
|
VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||||
<TextBlock x:Name="ModelLabel" FontSize="12.5"
|
<TextBlock x:Name="ModelLabel" FontSize="12.5"
|
||||||
Foreground="{DynamicResource SecondaryText}"
|
Foreground="{DynamicResource SecondaryText}"
|
||||||
|
MaxWidth="280"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
VerticalAlignment="Center"/>
|
VerticalAlignment="Center"/>
|
||||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="9"
|
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="9"
|
||||||
Foreground="{DynamicResource SecondaryText}"
|
Foreground="{DynamicResource SecondaryText}"
|
||||||
|
|||||||
@@ -717,9 +717,12 @@ public partial class ChatWindow : Window
|
|||||||
if (SidebarChatMenu == null || SidebarCoworkMenu == null || SidebarCodeMenu == null)
|
if (SidebarChatMenu == null || SidebarCoworkMenu == null || SidebarCodeMenu == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SidebarChatMenu.Visibility = _activeTab == "Chat" ? Visibility.Visible : Visibility.Collapsed;
|
var chatVisible = _activeTab == "Chat" ? Visibility.Visible : Visibility.Collapsed;
|
||||||
SidebarCoworkMenu.Visibility = _activeTab == "Cowork" ? Visibility.Visible : Visibility.Collapsed;
|
var coworkVisible = _activeTab == "Cowork" ? Visibility.Visible : Visibility.Collapsed;
|
||||||
SidebarCodeMenu.Visibility = _activeTab == "Code" ? Visibility.Visible : Visibility.Collapsed;
|
var codeVisible = _activeTab == "Code" ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
if (SidebarChatMenu.Visibility != chatVisible) SidebarChatMenu.Visibility = chatVisible;
|
||||||
|
if (SidebarCoworkMenu.Visibility != coworkVisible) SidebarCoworkMenu.Visibility = coworkVisible;
|
||||||
|
if (SidebarCodeMenu.Visibility != codeVisible) SidebarCodeMenu.Visibility = codeVisible;
|
||||||
|
|
||||||
if (SidebarModeBadgeTitle != null && SidebarModeBadgeIcon != null)
|
if (SidebarModeBadgeTitle != null && SidebarModeBadgeIcon != null)
|
||||||
{
|
{
|
||||||
@@ -2139,7 +2142,10 @@ public partial class ChatWindow : Window
|
|||||||
_ => "\uE8D7",
|
_ => "\uE8D7",
|
||||||
};
|
};
|
||||||
if (BtnPermission != null)
|
if (BtnPermission != null)
|
||||||
BtnPermission.ToolTip = $"{summary.Description}\n기본값 {PermissionModeCatalog.ToDisplayLabel(summary.DefaultMode)} · override {summary.OverrideCount}개";
|
{
|
||||||
|
var operationMode = OperationModePolicy.Normalize(_settings.Settings.OperationMode);
|
||||||
|
BtnPermission.ToolTip = $"{summary.Description}\n운영 모드: {operationMode}\n기본값 {PermissionModeCatalog.ToDisplayLabel(summary.DefaultMode)} · 예외 {summary.OverrideCount}개";
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.Equals(_lastPermissionBannerMode, perm, StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(_lastPermissionBannerMode, perm, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@@ -2275,10 +2281,11 @@ public partial class ChatWindow : Window
|
|||||||
lock (_convLock) currentConversation = _currentConversation;
|
lock (_convLock) currentConversation = _currentConversation;
|
||||||
var summary = _appState.GetPermissionSummary(currentConversation);
|
var summary = _appState.GetPermissionSummary(currentConversation);
|
||||||
var mode = PermissionModeCatalog.NormalizeGlobalMode(summary.EffectiveMode);
|
var mode = PermissionModeCatalog.NormalizeGlobalMode(summary.EffectiveMode);
|
||||||
|
var operationMode = OperationModePolicy.Normalize(_settings.Settings.OperationMode);
|
||||||
var overrides = summary.TopOverrides.Count > 0
|
var overrides = summary.TopOverrides.Count > 0
|
||||||
? string.Join(", ", summary.TopOverrides.Select(x => $"{x.Key}:{x.Value}"))
|
? string.Join(", ", summary.TopOverrides.Take(3).Select(x => $"{x.Key}:{PermissionModeCatalog.ToDisplayLabel(x.Value)}"))
|
||||||
: "없음";
|
: "없음";
|
||||||
return $"현재 권한 모드: {PermissionModeCatalog.ToDisplayLabel(mode)} ({mode})\n설명: {summary.Description}\n기본값: {PermissionModeCatalog.ToDisplayLabel(summary.DefaultMode)} · override: {summary.OverrideCount}개\n상위 override: {overrides}";
|
return $"현재 권한 모드: {PermissionModeCatalog.ToDisplayLabel(mode)}\n운영 모드: {operationMode}\n기본값: {PermissionModeCatalog.ToDisplayLabel(summary.DefaultMode)} · 예외 {summary.OverrideCount}개\n예외 미리보기: {overrides}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenPermissionPanelFromSlash(string command, string usageText)
|
private void OpenPermissionPanelFromSlash(string command, string usageText)
|
||||||
@@ -12972,13 +12979,19 @@ public partial class ChatWindow : Window
|
|||||||
_agentSettingsWindow = null;
|
_agentSettingsWindow = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var win = new AgentSettingsWindow(_settings)
|
var win = new AgentSettingsWindow(_settings);
|
||||||
{
|
if (IsLoaded && IsVisible)
|
||||||
Owner = IsLoaded && IsVisible ? this : null,
|
win.Owner = this;
|
||||||
};
|
|
||||||
_agentSettingsWindow = win;
|
_agentSettingsWindow = win;
|
||||||
win.Closed += (_, _) => _agentSettingsWindow = null;
|
win.Closed += (_, _) => _agentSettingsWindow = null;
|
||||||
win.Resources.MergedDictionaries.Add(Resources);
|
try
|
||||||
|
{
|
||||||
|
win.Resources.MergedDictionaries.Add(Resources);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// 리소스 병합 실패 시에도 설정창 자체는 열리도록 유지
|
||||||
|
}
|
||||||
|
|
||||||
bool changed;
|
bool changed;
|
||||||
try
|
try
|
||||||
@@ -12988,8 +13001,12 @@ public partial class ChatWindow : Window
|
|||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// 모달 창 오픈에 실패하면 일반 창으로라도 설정 접근을 보장
|
// 모달 창 오픈에 실패하면 일반 창으로라도 설정 접근을 보장
|
||||||
win.Show();
|
try
|
||||||
win.Activate();
|
{
|
||||||
|
win.Show();
|
||||||
|
win.Activate();
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!changed)
|
if (!changed)
|
||||||
@@ -13006,9 +13023,12 @@ public partial class ChatWindow : Window
|
|||||||
|
|
||||||
public void OpenAgentSettingsFromExternal()
|
public void OpenAgentSettingsFromExternal()
|
||||||
{
|
{
|
||||||
Show();
|
Dispatcher.BeginInvoke(() =>
|
||||||
Activate();
|
{
|
||||||
OpenAgentSettingsWindow();
|
Show();
|
||||||
|
Activate();
|
||||||
|
OpenAgentSettingsWindow();
|
||||||
|
}, DispatcherPriority.Input);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BtnInlineSettingsClose_Click(object sender, RoutedEventArgs e)
|
private void BtnInlineSettingsClose_Click(object sender, RoutedEventArgs e)
|
||||||
|
|||||||
Reference in New Issue
Block a user