From 982dee994c512597dc260d2f75d80af6e11b87ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Tue, 27 Jan 2026 19:59:31 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=EB=A9=94=EB=89=B4=20=EB=8F=99?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20UI/=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 테넌트 선택: 헤더에서 선택된 테넌트 기준으로 동작 - UI 개선: 레벨 뱃지(Lv.2, Lv.3), 동기화 필요 메뉴만 체크박스 활성화 - 전체선택 체크박스 추가 (로컬/원격 각각) - 선택된 메뉴 개수 표시 (Push/Pull 버튼 옆) - 상위 메뉴 선택 시 하위 메뉴 자동 선택 - Pull 시 부모 메뉴 이름 기반 매핑 수정 Co-Authored-By: Claude Opus 4.5 --- app/Http/Controllers/MenuSyncController.php | 34 +++++---- .../views/menus/_sync_menu_item.blade.php | 48 +++++++++---- resources/views/menus/sync.blade.php | 71 ++++++++++++++++--- 3 files changed, 119 insertions(+), 34 deletions(-) diff --git a/app/Http/Controllers/MenuSyncController.php b/app/Http/Controllers/MenuSyncController.php index a99e5cad..7713356a 100644 --- a/app/Http/Controllers/MenuSyncController.php +++ b/app/Http/Controllers/MenuSyncController.php @@ -12,7 +12,14 @@ class MenuSyncController extends Controller { - protected int $tenantId = 1; // MNG 메뉴는 tenant_id=1 + /** + * 현재 선택된 테넌트 ID + */ + protected function getTenantId(): int + { + $tenantId = session('selected_tenant_id'); + return ($tenantId && $tenantId !== 'all') ? (int) $tenantId : 1; + } /** * 환경 설정 조회 @@ -20,7 +27,7 @@ class MenuSyncController extends Controller private function getEnvironments(): array { $setting = TenantSetting::withoutGlobalScopes() - ->where('tenant_id', $this->tenantId) + ->where('tenant_id', $this->getTenantId()) ->where('setting_group', 'menu_sync') ->where('setting_key', 'environments') ->first(); @@ -85,7 +92,7 @@ public function saveSettings(Request $request): JsonResponse TenantSetting::withoutGlobalScopes()->updateOrCreate( [ - 'tenant_id' => $this->tenantId, + 'tenant_id' => $this->getTenantId(), 'setting_group' => 'menu_sync', 'setting_key' => 'environments', ], @@ -178,7 +185,7 @@ public function push(Request $request): JsonResponse // 선택된 메뉴 조회 $menus = Menu::withoutGlobalScopes() - ->where('tenant_id', $this->tenantId) + ->where('tenant_id', $this->getTenantId()) ->whereIn('id', $validated['menu_ids']) ->get(); @@ -316,7 +323,7 @@ public function testConnection(Request $request): JsonResponse private function getMenuTree(?int $parentId = null): array { $menus = Menu::withoutGlobalScopes() - ->where('tenant_id', $this->tenantId) + ->where('tenant_id', $this->getTenantId()) ->where('parent_id', $parentId) ->orderBy('sort_order') ->get(); @@ -340,7 +347,7 @@ private function getMenuTree(?int $parentId = null): array private function getChildrenData(int $parentId): array { $children = Menu::withoutGlobalScopes() - ->where('tenant_id', $this->tenantId) + ->where('tenant_id', $this->getTenantId()) ->where('parent_id', $parentId) ->orderBy('sort_order') ->get(); @@ -411,17 +418,20 @@ private function flattenMenuNames(array $menus, string $prefix = ''): array } /** - * 이름으로 메뉴 필터링 + * 이름으로 메뉴 필터링 (부모 이름 포함) */ - private function filterMenusByName(array $menus, array $names): array + private function filterMenusByName(array $menus, array $names, ?string $parentName = null): array { $result = []; foreach ($menus as $menu) { if (in_array($menu['name'], $names)) { + // 부모 이름 추가 + $menu['parent_name'] = $parentName; $result[] = $menu; } if (! empty($menu['children'])) { - $result = array_merge($result, $this->filterMenusByName($menu['children'], $names)); + // 현재 메뉴를 부모로 전달 + $result = array_merge($result, $this->filterMenusByName($menu['children'], $names, $menu['name'])); } } return $result; @@ -435,7 +445,7 @@ private function importMenu(array $data, ?int $parentId = null): void // 부모 메뉴 찾기 if (! $parentId && ! empty($data['parent_name'])) { $parent = Menu::withoutGlobalScopes() - ->where('tenant_id', $this->tenantId) + ->where('tenant_id', $this->getTenantId()) ->where('name', $data['parent_name']) ->first(); $parentId = $parent?->id; @@ -444,7 +454,7 @@ private function importMenu(array $data, ?int $parentId = null): void // 기존 메뉴 찾기 또는 생성 $menu = Menu::withoutGlobalScopes()->updateOrCreate( [ - 'tenant_id' => $this->tenantId, + 'tenant_id' => $this->getTenantId(), 'name' => $data['name'], ], [ @@ -464,4 +474,4 @@ private function importMenu(array $data, ?int $parentId = null): void } } } -} \ No newline at end of file +} diff --git a/resources/views/menus/_sync_menu_item.blade.php b/resources/views/menus/_sync_menu_item.blade.php index 66ac41e5..e62b6ebd 100644 --- a/resources/views/menus/_sync_menu_item.blade.php +++ b/resources/views/menus/_sync_menu_item.blade.php @@ -3,34 +3,48 @@ $isRemoteOnly = $side === 'remote' && in_array($menu['name'], $diff['remote_only'] ?? []); $isBoth = in_array($menu['name'], $diff['both'] ?? []); + // 동기화 필요 여부 (로컬에서는 local_only만, 원격에서는 remote_only만 체크 가능) + $needsSync = $isLocalOnly || $isRemoteOnly; + $bgClass = ''; $badgeClass = ''; $badgeText = ''; if ($isLocalOnly) { - $bgClass = 'bg-green-50 border-green-200'; + $bgClass = 'bg-green-50'; $badgeClass = 'bg-green-100 text-green-700'; $badgeText = 'NEW'; } elseif ($isRemoteOnly) { - $bgClass = 'bg-purple-50 border-purple-200'; + $bgClass = 'bg-purple-50'; $badgeClass = 'bg-purple-100 text-purple-700'; $badgeText = 'NEW'; } else { - $bgClass = 'bg-white hover:bg-gray-50'; + $bgClass = 'hover:bg-gray-50'; } - - $paddingLeft = ($depth * 1.5) + 0.5; @endphp -
+@php + $menuKey = $side . '_' . ($menu['id'] ?? Str::slug($menu['name'])); +@endphp +