From 08c495943bd6dad7636e2997cce3bcc5efe08f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Sun, 29 Mar 2026 15:30:57 +0300 Subject: [PATCH] =?UTF-8?q?RolePermission=20ve=20UserPermission=20css=20d?= =?UTF-8?q?=C3=BCzenlemesi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/role-management/RolesPermission.tsx | 167 ++++++++++++---- .../admin/user-management/UsersPermission.tsx | 180 +++++++++++++++--- 2 files changed, 277 insertions(+), 70 deletions(-) diff --git a/ui/src/views/admin/role-management/RolesPermission.tsx b/ui/src/views/admin/role-management/RolesPermission.tsx index 39b4272..c7cac85 100644 --- a/ui/src/views/admin/role-management/RolesPermission.tsx +++ b/ui/src/views/admin/role-management/RolesPermission.tsx @@ -1,3 +1,4 @@ +import { FaChevronRight, FaChevronDown } from 'react-icons/fa' import Container from '@/components/shared/Container' import { Button, Checkbox, Dialog, Input, Menu, toast } from '@/components/ui' import { useConfig } from '@/components/ui/ConfigProvider' @@ -8,13 +9,14 @@ import { PermissionGroupDto, PermissionWithGroupName, PermissionWithStyle, - UpdatePermissionDto, } from '@/proxy/admin/models' import { getPermissions, updatePermissions } from '@/services/identity.service' import { useStoreActions, useStoreState } from '@/store' import { useLocalization } from '@/utils/hooks/useLocalization' import { ChangeEvent, useEffect, useMemo, useState } from 'react' +type OpenState = Record + function RolesPermission({ open, onDialogClose, @@ -24,6 +26,24 @@ function RolesPermission({ onDialogClose: () => void name: string }) { + // Collapse/expand state + const [openPermissions, setOpenPermissions] = useState({}) + + // Parent izinleri aç/kapat + const togglePermission = (permName: string) => { + setOpenPermissions((prev) => ({ ...prev, [permName]: !prev[permName] })) + } + + // Parent izin mi? + function isParent(permission: PermissionWithStyle) { + return selectedGroupPermissions.some((p) => p.parentName === permission.name) + } + + // Belirli parent'ın alt izinleri + function getChildren(parentName: string) { + if (!parentName) return [] + return selectedGroupPermissions.filter((p) => p.parentName === parentName) + } const providerName = 'R' const { translate } = useLocalization() const { getConfig } = useStoreActions((a) => a.abpConfig) @@ -135,6 +155,28 @@ function RolesPermission({ } } + // --- Expand/Collapse All fonksiyonları (tüm state ve yardımcı fonksiyonlardan sonra) --- + const handleExpandAll = () => { + const expanded: OpenState = {} + function expandRecursively(perms: PermissionWithStyle[]) { + perms.forEach((perm) => { + if (isParent(perm)) { + expanded[perm.name || ''] = true + // Alt parent'ları da recursive aç + const children = getChildren(perm.name || '') + expandRecursively(children) + } + }) + } + // Tüm parent ve alt parent'ları recursive olarak aç + expandRecursively(selectedGroupPermissions) + setOpenPermissions(expanded) + } + + const handleCollapseAll = () => { + setOpenPermissions({}) + } + function getPermissionsWithGroupName(groups: PermissionGroupDto[]): PermissionWithGroupName[] { return groups.reduce( (acc, val) => [ @@ -174,34 +216,43 @@ function RolesPermission({ [selectedGroupPermissions], ) + // Collapse/expand için recursive düzende izinleri döndür const filteredPermissions = useMemo(() => { - if (!searchTerm) { - return selectedGroupPermissions - } - const lowerTerm = searchTerm.toLowerCase() - // 1️⃣ Sadece 1. kırınımdakileri (parent olmayanları değil) ara - const topLevelMatches = selectedGroupPermissions.filter( + // Filtreli veya tüm parent izinler + const parents = selectedGroupPermissions.filter( (p) => - !p.parentName && // parentName yoksa bu 1. kırınım demektir - translate('::' + p.displayName) - .toLowerCase() - .includes(lowerTerm), + !p.parentName && + (searchTerm === '' || + translate('::' + p.displayName) + .toLowerCase() + .includes(lowerTerm)), ) - // 2️⃣ Her bulunan parent’ın altındaki child izinleri ekle - const result: PermissionWithStyle[] = [] - topLevelMatches.forEach((parent) => { - result.push(parent) + // Recursive children builder (her seviye için doğru level) + function buildTree( + parent: PermissionWithStyle, + level: number, + ): (PermissionWithStyle & { level: number })[] { + const arr = [{ ...parent, level }] + const parentKey = parent.name || '' + if (openPermissions[parentKey] || searchTerm) { + const children = getChildren(parentKey) + children.forEach((child) => { + arr.push(...buildTree(child, level + 1)) + }) + } + return arr + } - // Alt kırılımları bul - const children = selectedGroupPermissions.filter((child) => child.parentName === parent.name) - result.push(...children) + // Tüm parentlar ve altlarını sırayla ekle + let result: (PermissionWithStyle & { level: number })[] = [] + parents.forEach((parent) => { + result = result.concat(buildTree(parent, 0)) }) - return result - }, [selectedGroupPermissions, searchTerm, translate]) + }, [selectedGroupPermissions, searchTerm, translate, openPermissions]) const onSelectAll = (value: boolean, e: ChangeEvent) => { if (!permissionList) { @@ -284,6 +335,14 @@ function RolesPermission({ {translate('AbpPermissionManagement::SelectAllInThisTab')} + + + + @@ -310,26 +369,56 @@ function RolesPermission({

- setSearchTerm(e.target.value)} - /> +
+ setSearchTerm(e.target.value)} + /> +
- {filteredPermissions.map((permission) => ( -
- onClickCheckbox(permission)} - > - {translate('::' + permission.displayName)} - -
- ))} + {filteredPermissions.map((permission) => { + const isParentPerm = isParent(permission) + const permKey = permission.name || '' + const children = getChildren(permKey) + return ( +
+
+ {/* Expand Icon */} + {isParentPerm ? ( + + ) : ( +
+ )} + + {/* Checkbox */} + onClickCheckbox(permission)} + > + + {translate('::' + permission.displayName)} + + +
+
+ ) + })}
diff --git a/ui/src/views/admin/user-management/UsersPermission.tsx b/ui/src/views/admin/user-management/UsersPermission.tsx index 3134b3a..773aeb7 100644 --- a/ui/src/views/admin/user-management/UsersPermission.tsx +++ b/ui/src/views/admin/user-management/UsersPermission.tsx @@ -1,6 +1,6 @@ -import AdaptableCard from '@/components/shared/AdaptableCard' -import Container from '@/components/shared/Container' -import { Badge, Button, Checkbox, Dialog, Menu, toast } from '@/components/ui' +import { FaChevronRight, FaChevronDown } from 'react-icons/fa' +import { Badge, Button, Checkbox, Dialog, Input, Menu, toast } from '@/components/ui' +type OpenState = Record import { useConfig } from '@/components/ui/ConfigProvider' import Notification from '@/components/ui/Notification' import { @@ -10,7 +10,6 @@ import { PermissionWithGroupName, PermissionWithStyle, ProviderInfoDto, - UpdatePermissionDto, } from '@/proxy/admin/models' import { getPermissions, updatePermissions } from '@/services/identity.service' import { useStoreActions, useStoreState } from '@/store' @@ -39,6 +38,44 @@ function UsersPermission({ [], ) + // Collapse/expand state + const [openPermissions, setOpenPermissions] = useState({}) + + // Parent izinleri aç/kapat + const togglePermission = (permName: string) => { + setOpenPermissions((prev) => ({ ...prev, [permName]: !prev[permName] })) + } + + // Parent izin mi? + function isParent(permission: PermissionWithStyle) { + return selectedGroupPermissions.some((p) => p.parentName === permission.name) + } + + // Belirli parent'ın alt izinleri + function getChildren(parentName: string) { + if (!parentName) return [] + return selectedGroupPermissions.filter((p) => p.parentName === parentName) + } + // --- Expand/Collapse All fonksiyonları --- + const handleExpandAll = () => { + const expanded: OpenState = {} + function expandRecursively(perms: PermissionWithStyle[]) { + perms.forEach((perm) => { + if (isParent(perm)) { + expanded[perm.name || ''] = true + const children = getChildren(perm.name || '') + expandRecursively(children) + } + }) + } + expandRecursively(selectedGroupPermissions) + setOpenPermissions(expanded) + } + + const handleCollapseAll = () => { + setOpenPermissions({}) + } + const mode = useStoreState((state) => state.theme.mode) const { direction } = useConfig() @@ -216,6 +253,42 @@ function UsersPermission({ return false } + // --- Search ve recursive treeview --- + // Collapse/expand için recursive düzende izinleri döndür + const [searchTerm, setSearchTerm] = useState('') + const filteredPermissions = useMemo(() => { + const lowerTerm = searchTerm.toLowerCase() + // Filtreli veya tüm parent izinler + const parents = selectedGroupPermissions.filter( + (p) => + !p.parentName && + (searchTerm === '' || + translate('::' + p.displayName) + .toLowerCase() + .includes(lowerTerm)), + ) + // Recursive children builder (her seviye için doğru level) + function buildTree( + parent: PermissionWithStyle, + level: number, + ): (PermissionWithStyle & { level: number })[] { + const arr = [{ ...parent, level }] + const parentKey = parent.name || '' + if (openPermissions[parentKey] || searchTerm) { + const children = getChildren(parentKey) + children.forEach((child) => { + arr.push(...buildTree(child, level + 1)) + }) + } + return arr + } + let result: (PermissionWithStyle & { level: number })[] = [] + parents.forEach((parent) => { + result = result.concat(buildTree(parent, 0)) + }) + return result + }, [selectedGroupPermissions, searchTerm, translate, openPermissions]) + return permissionList ? ( -
+
{translate('::Permission')} - {name}

@@ -239,12 +312,18 @@ function UsersPermission({ {translate('AbpPermissionManagement::SelectAllInThisTab')} + +
-
+
{permissionList?.groups.map((group) => (
-
-
- {selectedGroupPermissions.map((permission) => ( -
- 0 ? true : false} - checked={permission.isGranted} - onChange={() => onClickCheckbox(permission)} - > - {translate('::' + permission.displayName)} - {permission.grantedProviders.map((provider) => ( - - ))} - -
- ))} +
+
+ setSearchTerm(e.target.value)} + /> +
+
+ {filteredPermissions.map((permission) => { + const isParentPerm = isParent(permission) + const permKey = permission.name || '' + const children = getChildren(permKey) + return ( +
+
+ {/* Expand Icon */} + {isParentPerm ? ( + + ) : ( +
+ )} + + {/* Checkbox */} + onClickCheckbox(permission)} + disabled={permission.grantedProviders.some((provider) => provider.providerName === 'R')} + > + + {translate('::' + permission.displayName)} + {permission.grantedProviders.map((provider) => { + const badgeContent = provider.providerName !== providerName + ? `${provider.providerName}: ${provider.providerKey}` + : provider.providerName; + return ( + + ); + })} + + +
+
+ ) + })}