MenuGroup güncellemesi

This commit is contained in:
Sedat Öztürk 2025-10-12 21:45:03 +03:00
parent a6490b5153
commit 8c0863b11c
9 changed files with 970 additions and 932 deletions

View file

@ -54,7 +54,6 @@ public class MenuAppService : CrudAppService<
query = query.Where(a => !a.IsDisabled); query = query.Where(a => !a.IsDisabled);
//Tenant üzerinden MenuGrup bilgisi alınıp sadece o menüler listelenecek //Tenant üzerinden MenuGrup bilgisi alınıp sadece o menüler listelenecek
// 🔹 Tenant'a göre filtrele
if (CurrentTenant.IsAvailable) if (CurrentTenant.IsAvailable)
{ {
var tenant = await _tenantRepository.FindAsync(CurrentTenant.Id.Value); var tenant = await _tenantRepository.FindAsync(CurrentTenant.Id.Value);

View file

@ -25,7 +25,7 @@ public class PlatformPermissionGroupDto : PermissionGroupDto
public class PlatformPermissionGrantInfoDto : PermissionGrantInfoDto public class PlatformPermissionGrantInfoDto : PermissionGrantInfoDto
{ {
public string[] MenuGroup { get; set; } = []; public string MenuGroup { get; set; } = string.Empty;
} }
[Dependency(ReplaceServices = true)] [Dependency(ReplaceServices = true)]
@ -75,7 +75,7 @@ public class PlatformPermissionAppService : PermissionAppService
AllowedProviders = permission.AllowedProviders, AllowedProviders = permission.AllowedProviders,
GrantedProviders = permission.GrantedProviders, GrantedProviders = permission.GrantedProviders,
IsGranted = permission.IsGranted, IsGranted = permission.IsGranted,
MenuGroup = JsonSerializer.Deserialize<string[]>(menuGroup) ?? [] MenuGroup = menuGroup ?? string.Empty
}; };
newGroup.Permissions.Add(newPermission); newGroup.Permissions.Add(newPermission);

File diff suppressed because it is too large Load diff

View file

@ -82,7 +82,7 @@ public class PermissionDefinitionRecordSeedDto
public string DisplayName { get; set; } public string DisplayName { get; set; }
public bool IsEnabled { get; set; } public bool IsEnabled { get; set; }
public int MultiTenancySide { get; set; } public int MultiTenancySide { get; set; }
public string[] MenuGroup { get; set; } public string MenuGroup { get; set; }
} }
public class CurrencySeedDto public class CurrencySeedDto

View file

@ -2221,8 +2221,8 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
}), }),
CommandColumnJson = JsonSerializer.Serialize(new CommandColumnDto[] { CommandColumnJson = JsonSerializer.Serialize(new CommandColumnDto[] {
new() { new() {
Hint = "Manage", Hint = "Seed",
Text = "Manage", Text = "Seed",
AuthName = TenantManagementPermissions.Tenants.ManageConnectionStrings, AuthName = TenantManagementPermissions.Tenants.ManageConnectionStrings,
DialogName = "TenantsConnectionString", DialogName = "TenantsConnectionString",
DialogParameters = JsonSerializer.Serialize(new { DialogParameters = JsonSerializer.Serialize(new {
@ -4099,11 +4099,6 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
{ {
Visible = true Visible = true
}), }),
SelectionJson = JsonSerializer.Serialize(new SelectionDto
{
Mode = GridOptions.SelectionModeSingle,
AllowSelectAll = false
}),
ColumnOptionJson = JsonSerializer.Serialize(new ColumnOptionJson = JsonSerializer.Serialize(new
{ {
ColumnFixingEnabled = true, ColumnFixingEnabled = true,

View file

@ -1,5 +1,5 @@
using System; using System;
using System.Text.Json; using System.Linq;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.PermissionManagement; using Volo.Abp.PermissionManagement;
@ -7,17 +7,45 @@ namespace Kurs.Platform.Extensions;
public static class AbpPermissionsExtensions public static class AbpPermissionsExtensions
{ {
public static void SetMenuGroup(this PermissionDefinitionRecord permission, string[] menuGroup) /// <summary>
/// Menü gruplarını pipe karakteriyle ayrılmış string olarak kaydeder. (örnek: "Erp|Kurs")
/// </summary>
public static void SetMenuGroup(this PermissionDefinitionRecord permission, string menuGroup)
{ {
var json = JsonSerializer.Serialize(menuGroup); if (string.IsNullOrWhiteSpace(menuGroup))
permission.SetProperty(PlatformConsts.Permissions.MenuGroup, json); {
permission.SetProperty(PlatformConsts.Permissions.MenuGroup, null);
return;
} }
// 🔹 Gereksiz boşlukları temizle
var cleaned = string.Join(
'|',
menuGroup
.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Distinct()
);
// 🔹 Veritabanına "Erp|Kurs" formatında kaydet
permission.SetProperty(PlatformConsts.Permissions.MenuGroup, cleaned);
}
/// <summary>
/// Menü gruplarını veritabanındaki pipe formatından string[] olarak döndürür. (örnek: "Erp|Kurs" → ["Erp", "Kurs"])
/// </summary>
public static string[] GetMenuGroup(this PermissionDefinitionRecord permission) public static string[] GetMenuGroup(this PermissionDefinitionRecord permission)
{ {
var json = permission.GetProperty<string>(PlatformConsts.Permissions.MenuGroup); var value = permission.GetProperty<string>(PlatformConsts.Permissions.MenuGroup);
return string.IsNullOrWhiteSpace(json)
? [] if (string.IsNullOrWhiteSpace(value))
: JsonSerializer.Deserialize<string[]>(json); {
return Array.Empty<string>();
}
// 🔹 "Erp|Kurs" -> ["Erp", "Kurs"]
return value
.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Distinct()
.ToArray();
} }
} }

View file

@ -1,18 +1,24 @@
import * as fc from 'react-icons/fc' import * as fc from 'react-icons/fc'
import * as fa from 'react-icons/fa' import * as fa from 'react-icons/fa'
import type { ComponentType } from 'react'
export type NavigationIcons = Record<string, React.ComponentType<any>>; export type NavigationIcons = Record<string, ComponentType<any>>
const navigationIcon: NavigationIcons = {}; const navigationIcon: NavigationIcons = {}
// fc (Font Awesome) ikonlarıyla dinamik olarak navigationIcon nesnesini doldur function registerIcons(iconModule: Record<string, any>) {
for (const [key, Icon] of Object.entries(fc)) { for (const [key, Icon] of Object.entries(iconModule)) {
navigationIcon[key] = Icon; // Icon bileşenini doğrudan kullanıyoruz if (
Icon &&
(typeof Icon === 'function' ||
(typeof Icon === 'object' && 'render' in Icon))
) {
navigationIcon[key] = Icon as ComponentType<any>
}
}
} }
// fa (Font Awesome) ikonlarıyla navigationIcon nesnesini doldur registerIcons(fc)
for (const [key, Icon] of Object.entries(fa)) { registerIcons(fa)
navigationIcon[key] = Icon; // Icon bileşenini doğrudan kullanıyoruz
}
export default navigationIcon; export default navigationIcon

View file

@ -121,21 +121,23 @@ const FormButtons = (props: {
item.name != 'deleteSelectedRecords', item.name != 'deleteSelectedRecords',
) )
.map((item, i) => { .map((item, i) => {
const IconComp = navigationIcon[item.options?.icon] // React bileşeni olabilir ya da undefined
const hasValidIcon =
IconComp &&
(typeof IconComp === 'function' ||
(typeof IconComp === 'object' && 'render' in IconComp))
return ( return (
<Button <Button
key={'toolbarButton-' + i} key={'toolbarButton-' + i}
variant="default" variant="default"
size="xs" size="xs"
{...(item.options?.icon icon={
? { hasValidIcon ? <IconComp className="text-gray-400" /> : null // 🔒 güvenli render
icon: React.createElement(navigationIcon[item.options.icon], {
className: 'text-gray-400',
}),
} }
: {})} onClick={item.options?.onClick}
onClick={item.options.onClick}
> >
{item.options.text} {item.options?.text}
</Button> </Button>
) )
})} })}

View file

@ -8,6 +8,7 @@ import { ToolbarItem } from 'devextreme/ui/data_grid_types'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useDialogContext } from '../shared/DialogContext' import { useDialogContext } from '../shared/DialogContext'
import { usePWA } from '@/utils/hooks/usePWA' import { usePWA } from '@/utils/hooks/usePWA'
import { text } from 'stream/consumers'
type ToolbarModalData = { type ToolbarModalData = {
open: boolean open: boolean
@ -68,6 +69,7 @@ const useToolbar = ({
options: { options: {
icon: 'refresh', icon: 'refresh',
onClick: refreshData, onClick: refreshData,
text: translate('::ListForms.ListForm.Refresh'),
}, },
location: 'after', location: 'after',
}) })