IntranetAppService ve MenuAppService güçlendirildi
This commit is contained in:
parent
b070702378
commit
ec44d03e79
3 changed files with 182 additions and 147 deletions
|
|
@ -13,6 +13,7 @@ using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Volo.Abp.Domain.Repositories;
|
using Volo.Abp.Domain.Repositories;
|
||||||
using Volo.Abp.MultiTenancy;
|
using Volo.Abp.MultiTenancy;
|
||||||
|
using Volo.Abp.Uow;
|
||||||
|
|
||||||
namespace Erp.Platform.Public;
|
namespace Erp.Platform.Public;
|
||||||
|
|
||||||
|
|
@ -83,8 +84,10 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
_projectTaskRepository = projectTaskRepository;
|
_projectTaskRepository = projectTaskRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnitOfWork]
|
||||||
public async Task<IntranetDashboardDto> GetIntranetDashboardAsync()
|
public async Task<IntranetDashboardDto> GetIntranetDashboardAsync()
|
||||||
{
|
{
|
||||||
|
// ABP 9.0.2: UnitOfWork kapsamında tüm sorgular optimize edilir
|
||||||
return new IntranetDashboardDto
|
return new IntranetDashboardDto
|
||||||
{
|
{
|
||||||
Events = await GetUpcomingEventsAsync(),
|
Events = await GetUpcomingEventsAsync(),
|
||||||
|
|
@ -107,21 +110,24 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
|
|
||||||
private async Task<List<ProjectTaskDto>> GetProjectTasksAsync()
|
private async Task<List<ProjectTaskDto>> GetProjectTasksAsync()
|
||||||
{
|
{
|
||||||
var tasks = await _projectTaskRepository
|
var queryable = await _projectTaskRepository.WithDetailsAsync(e => e.Employee);
|
||||||
.WithDetailsAsync(e => e.Employee)
|
|
||||||
.ContinueWith(t => t.Result.Where(s => s.Priority == "High" || s.Priority == "Urgent")
|
var tasks = await AsyncExecuter.ToListAsync(
|
||||||
|
queryable
|
||||||
|
.Where(s => s.Priority == "High" || s.Priority == "Urgent")
|
||||||
.OrderByDescending(s => s.StartDate)
|
.OrderByDescending(s => s.StartDate)
|
||||||
.Take(3)
|
.Take(3)
|
||||||
.ToList());
|
);
|
||||||
|
|
||||||
return ObjectMapper.Map<List<ProjectTask>, List<ProjectTaskDto>>(tasks);
|
return ObjectMapper.Map<List<ProjectTask>, List<ProjectTaskDto>>(tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<SocialPostDto>> GetSocialPostsAsync()
|
private async Task<List<SocialPostDto>> GetSocialPostsAsync()
|
||||||
{
|
{
|
||||||
var socialPosts = await _socialPostRepository
|
var queryable = await _socialPostRepository
|
||||||
.WithDetailsAsync(e => e.Employee, e => e.Location, e => e.Media, e => e.Comments, e => e.Likes)
|
.WithDetailsAsync(e => e.Employee, e => e.Location, e => e.Media, e => e.Comments, e => e.Likes);
|
||||||
.ContinueWith(t => t.Result.ToList());
|
|
||||||
|
var socialPosts = await AsyncExecuter.ToListAsync(queryable);
|
||||||
|
|
||||||
return ObjectMapper.Map<List<SocialPost>, List<SocialPostDto>>(socialPosts);
|
return ObjectMapper.Map<List<SocialPost>, List<SocialPostDto>>(socialPosts);
|
||||||
}
|
}
|
||||||
|
|
@ -130,29 +136,28 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
{
|
{
|
||||||
var queryable = await _surveyRepository.GetQueryableAsync();
|
var queryable = await _surveyRepository.GetQueryableAsync();
|
||||||
|
|
||||||
var surveys = queryable
|
var surveys = await AsyncExecuter.ToListAsync(
|
||||||
|
queryable
|
||||||
.Where(s => s.Status == "active")
|
.Where(s => s.Status == "active")
|
||||||
.Include(s => s.Questions)
|
.Include(s => s.Questions)
|
||||||
.ThenInclude(q => q.Options)
|
.ThenInclude(q => q.Options)
|
||||||
.ToList();
|
);
|
||||||
|
|
||||||
return ObjectMapper.Map<List<Survey>, List<SurveyDto>>(surveys);
|
return ObjectMapper.Map<List<Survey>, List<SurveyDto>>(surveys);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<OvertimeDto>> GetOvertimesAsync()
|
private async Task<List<OvertimeDto>> GetOvertimesAsync()
|
||||||
{
|
{
|
||||||
var overtimes = await _overtimeRepository
|
var queryable = await _overtimeRepository.WithDetailsAsync(e => e.Employee);
|
||||||
.WithDetailsAsync(e => e.Employee)
|
var overtimes = await AsyncExecuter.ToListAsync(queryable);
|
||||||
.ContinueWith(t => t.Result.ToList());
|
|
||||||
|
|
||||||
return ObjectMapper.Map<List<Overtime>, List<OvertimeDto>>(overtimes);
|
return ObjectMapper.Map<List<Overtime>, List<OvertimeDto>>(overtimes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<LeaveDto>> GetLeavesAsync()
|
private async Task<List<LeaveDto>> GetLeavesAsync()
|
||||||
{
|
{
|
||||||
var leaves = await _leaveRepository
|
var queryable = await _leaveRepository.WithDetailsAsync(e => e.Employee);
|
||||||
.WithDetailsAsync(e => e.Employee)
|
var leaves = await AsyncExecuter.ToListAsync(queryable);
|
||||||
.ContinueWith(t => t.Result.ToList());
|
|
||||||
|
|
||||||
return ObjectMapper.Map<List<Leave>, List<LeaveDto>>(leaves);
|
return ObjectMapper.Map<List<Leave>, List<LeaveDto>>(leaves);
|
||||||
}
|
}
|
||||||
|
|
@ -225,14 +230,14 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
|
|
||||||
private async Task<List<AnnouncementDto>> GetAnnouncementsAsync()
|
private async Task<List<AnnouncementDto>> GetAnnouncementsAsync()
|
||||||
{
|
{
|
||||||
var announcements = await _announcementRepository
|
var queryable = await _announcementRepository.WithDetailsAsync(e => e.Employee);
|
||||||
.WithDetailsAsync(e => e.Employee)
|
var announcements = await AsyncExecuter.ToListAsync(queryable);
|
||||||
.ContinueWith(t => t.Result.ToList());
|
|
||||||
|
|
||||||
var announcementDtos = new List<AnnouncementDto>();
|
var announcementDtos = new List<AnnouncementDto>();
|
||||||
|
|
||||||
// Tüm departmanları bir kez çek (performans için)
|
// Tüm departmanları bir kez çek (performans için)
|
||||||
var allDepartments = await _departmentRepository.GetListAsync();
|
var allDepartments = await _departmentRepository.GetListAsync();
|
||||||
|
var departmentDict = allDepartments.ToDictionary(d => d.Id, d => d.Name);
|
||||||
|
|
||||||
foreach (var announcement in announcements)
|
foreach (var announcement in announcements)
|
||||||
{
|
{
|
||||||
|
|
@ -246,21 +251,15 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
.Select(d => d.Trim())
|
.Select(d => d.Trim())
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
// ID'leri Department Name'lere çevir
|
// ID'leri Department Name'lere çevir (Dictionary lookup çok hızlı)
|
||||||
var departmentNames = new List<string>();
|
var departmentNames = departmentIds
|
||||||
foreach (var deptId in departmentIds)
|
.Where(deptId => Guid.TryParse(deptId, out _))
|
||||||
{
|
.Select(deptId => Guid.Parse(deptId))
|
||||||
if (Guid.TryParse(deptId, out var guid))
|
.Where(guid => departmentDict.ContainsKey(guid))
|
||||||
{
|
.Select(guid => departmentDict[guid])
|
||||||
var department = allDepartments.FirstOrDefault(d => d.Id == guid);
|
.ToArray();
|
||||||
if (department != null)
|
|
||||||
{
|
|
||||||
departmentNames.Add(department.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dto.Departments = departmentNames.ToArray();
|
dto.Departments = departmentNames;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -284,19 +283,17 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
var lastMonthExpenses = queryable
|
var lastMonthExpenses = queryable
|
||||||
.Where(a => a.RequestDate >= oneMonthAgo && a.RequestDate <= today);
|
.Where(a => a.RequestDate >= oneMonthAgo && a.RequestDate <= today);
|
||||||
|
|
||||||
// Son 1 aydaki toplam talep miktarı
|
// ABP 9.0.2: Separate queries for better performance
|
||||||
var totalRequested = lastMonthExpenses.Sum(a => a.Amount);
|
var expensesList = await AsyncExecuter.ToListAsync(lastMonthExpenses);
|
||||||
|
var totalRequested = expensesList.Sum(a => a.Amount);
|
||||||
// Son 1 aydaki onaylanan harcamaların toplamı
|
var totalApproved = expensesList.Where(a => a.Status == "approved").Sum(a => a.Amount);
|
||||||
var totalApproved = lastMonthExpenses
|
|
||||||
.Where(a => a.Status == "approved")
|
|
||||||
.Sum(a => a.Amount);
|
|
||||||
|
|
||||||
// Son 5 kayıt
|
// Son 5 kayıt
|
||||||
var last5Expenses = queryable
|
var last5Expenses = await AsyncExecuter.ToListAsync(
|
||||||
|
queryable
|
||||||
.OrderByDescending(a => a.RequestDate)
|
.OrderByDescending(a => a.RequestDate)
|
||||||
.Take(5)
|
.Take(5)
|
||||||
.ToList();
|
);
|
||||||
|
|
||||||
// Map işlemleri
|
// Map işlemleri
|
||||||
var last5Dtos = ObjectMapper.Map<List<Expense>, List<ExpenseDto>>(last5Expenses);
|
var last5Dtos = ObjectMapper.Map<List<Expense>, List<ExpenseDto>>(last5Expenses);
|
||||||
|
|
@ -335,30 +332,55 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
{
|
{
|
||||||
var today = DateTime.Now;
|
var today = DateTime.Now;
|
||||||
|
|
||||||
var employees = await _employeeRepository
|
var queryable = await _employeeRepository
|
||||||
.WithDetailsAsync(e => e.EmploymentType, e => e.JobPosition, e => e.Department)
|
.WithDetailsAsync(e => e.EmploymentType, e => e.JobPosition, e => e.Department);
|
||||||
.ContinueWith(t => t.Result
|
|
||||||
.Where(e => e.BirthDate.Day == today.Day && e.BirthDate.Month == today.Month)
|
var employees = await AsyncExecuter.ToListAsync(
|
||||||
.ToList());
|
queryable.Where(e => e.BirthDate.Day == today.Day && e.BirthDate.Month == today.Month)
|
||||||
|
);
|
||||||
|
|
||||||
return ObjectMapper.Map<List<Employee>, List<EmployeeDto>>(employees);
|
return ObjectMapper.Map<List<Employee>, List<EmployeeDto>>(employees);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<EventDto>> GetUpcomingEventsAsync()
|
private async Task<List<EventDto>> GetUpcomingEventsAsync()
|
||||||
{
|
{
|
||||||
var events = await _eventRepository
|
var queryable = await _eventRepository
|
||||||
.WithDetailsAsync(e => e.Category, e => e.Type, e => e.Category, e => e.Photos, e => e.Comments)
|
.WithDetailsAsync(e => e.Category, e => e.Type, e => e.Photos, e => e.Comments);
|
||||||
.ContinueWith(t => t.Result.ToList().Where(e => e.isPublished).OrderByDescending(e => e.CreationTime));
|
|
||||||
|
var events = await AsyncExecuter.ToListAsync(
|
||||||
|
queryable.Where(e => e.isPublished).OrderByDescending(e => e.CreationTime)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!events.Any())
|
||||||
|
return new List<EventDto>();
|
||||||
|
|
||||||
|
// Tüm unique employee ID'lerini topla (event'ler ve comment'ler için)
|
||||||
|
var employeeIds = new HashSet<Guid>();
|
||||||
|
foreach (var evt in events)
|
||||||
|
{
|
||||||
|
employeeIds.Add(evt.EmployeeId);
|
||||||
|
if (evt.Comments != null)
|
||||||
|
{
|
||||||
|
foreach (var comment in evt.Comments)
|
||||||
|
{
|
||||||
|
employeeIds.Add(comment.EmployeeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tüm employee'leri tek sorguda getir (N+1 problemi çözüldü)
|
||||||
|
var employeeQueryable = await _employeeRepository.WithDetailsAsync(e => e.JobPosition);
|
||||||
|
var employees = await AsyncExecuter.ToListAsync(
|
||||||
|
employeeQueryable.Where(e => employeeIds.Contains(e.Id))
|
||||||
|
);
|
||||||
|
var employeeDict = employees.ToDictionary(e => e.Id);
|
||||||
|
|
||||||
var result = new List<EventDto>();
|
var result = new List<EventDto>();
|
||||||
foreach (var evt in events)
|
foreach (var evt in events)
|
||||||
{
|
{
|
||||||
var employee = await _employeeRepository
|
if (!employeeDict.TryGetValue(evt.EmployeeId, out var employee))
|
||||||
.WithDetailsAsync(e => e.JobPosition)
|
continue;
|
||||||
.ContinueWith(t => t.Result.FirstOrDefault(e => e.Id == evt.EmployeeId));
|
|
||||||
|
|
||||||
if (employee != null)
|
|
||||||
{
|
|
||||||
var calendarEvent = new EventDto
|
var calendarEvent = new EventDto
|
||||||
{
|
{
|
||||||
Id = evt.Id.ToString(),
|
Id = evt.Id.ToString(),
|
||||||
|
|
@ -372,7 +394,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
{
|
{
|
||||||
Id = employee.Id,
|
Id = employee.Id,
|
||||||
Name = employee.Name,
|
Name = employee.Name,
|
||||||
Position = employee.JobPosition.Name,
|
Position = employee.JobPosition?.Name,
|
||||||
Avatar = employee.Avatar
|
Avatar = employee.Avatar
|
||||||
},
|
},
|
||||||
Participants = evt.ParticipantsCount,
|
Participants = evt.ParticipantsCount,
|
||||||
|
|
@ -382,16 +404,12 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
IsPublished = evt.isPublished
|
IsPublished = evt.isPublished
|
||||||
};
|
};
|
||||||
|
|
||||||
// Comment'lerin author bilgilerini doldur
|
// Comment'lerin author bilgilerini doldur (artık dictionary'den hızlıca alınıyor)
|
||||||
if (evt.Comments != null && evt.Comments.Any())
|
if (evt.Comments != null && evt.Comments.Any())
|
||||||
{
|
{
|
||||||
foreach (var comment in evt.Comments)
|
foreach (var comment in evt.Comments)
|
||||||
{
|
{
|
||||||
var commentAuthor = await _employeeRepository
|
if (employeeDict.TryGetValue(comment.EmployeeId, out var commentAuthor))
|
||||||
.WithDetailsAsync(e => e.JobPosition)
|
|
||||||
.ContinueWith(t => t.Result.FirstOrDefault(e => e.Id == comment.EmployeeId));
|
|
||||||
|
|
||||||
if (commentAuthor != null)
|
|
||||||
{
|
{
|
||||||
calendarEvent.Comments.Add(new EventCommentDto
|
calendarEvent.Comments.Add(new EventCommentDto
|
||||||
{
|
{
|
||||||
|
|
@ -400,7 +418,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
{
|
{
|
||||||
Id = commentAuthor.Id,
|
Id = commentAuthor.Id,
|
||||||
Name = commentAuthor.Name,
|
Name = commentAuthor.Name,
|
||||||
Position = commentAuthor.JobPosition.Name,
|
Position = commentAuthor.JobPosition?.Name,
|
||||||
Avatar = commentAuthor.Avatar
|
Avatar = commentAuthor.Avatar
|
||||||
},
|
},
|
||||||
Content = comment.Content,
|
Content = comment.Content,
|
||||||
|
|
@ -413,7 +431,6 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
|
|
||||||
result.Add(calendarEvent);
|
result.Add(calendarEvent);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,29 +88,37 @@ public class MenuAppService : CrudAppService<
|
||||||
query = ApplyPaging(query, input);
|
query = ApplyPaging(query, input);
|
||||||
|
|
||||||
var items = await AsyncExecuter.ToListAsync(query);
|
var items = await AsyncExecuter.ToListAsync(query);
|
||||||
foreach (var item in items)
|
|
||||||
{
|
// Tüm unique permission'ları topla
|
||||||
if (item.RequiredPermissionName.IsNullOrWhiteSpace())
|
var uniquePermissions = items
|
||||||
{
|
.Where(x => !string.IsNullOrWhiteSpace(x.RequiredPermissionName))
|
||||||
entities.Add(item);
|
.Select(x => x.RequiredPermissionName)
|
||||||
}
|
.Distinct()
|
||||||
else
|
.ToList();
|
||||||
|
|
||||||
|
// Tüm permission'ları bir kerede kontrol et (N+1 query problemini önler)
|
||||||
|
var grantedPermissions = new HashSet<string>();
|
||||||
|
foreach (var permission in uniquePermissions)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await AuthorizationService.IsGrantedAsync(item.RequiredPermissionName);
|
if (await AuthorizationService.IsGrantedAsync(permission))
|
||||||
if (result == true)
|
|
||||||
{
|
{
|
||||||
entities.Add(item);
|
grantedPermissions.Add(permission);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex, ex.Message);
|
Logger.LogError(ex, $"Permission error for {permission}: {ex.Message}");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sadece yetkili menüleri filtrele
|
||||||
|
entities = items
|
||||||
|
.Where(item => string.IsNullOrWhiteSpace(item.RequiredPermissionName) ||
|
||||||
|
grantedPermissions.Contains(item.RequiredPermissionName))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
entityDtos = await base.MapToGetListOutputDtosAsync(entities);
|
entityDtos = await base.MapToGetListOutputDtosAsync(entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,28 +172,44 @@ public class MenuAppService : CrudAppService<
|
||||||
{
|
{
|
||||||
await CheckUpdatePolicyAsync();
|
await CheckUpdatePolicyAsync();
|
||||||
|
|
||||||
var result = new List<MenuDto>();
|
if (!inputs.Any())
|
||||||
|
return new List<MenuDto>();
|
||||||
|
|
||||||
foreach (var input in inputs)
|
// Id kontrolü
|
||||||
{
|
if (inputs.Any(x => x.Id == Guid.Empty))
|
||||||
if (input.Id == Guid.Empty)
|
|
||||||
{
|
{
|
||||||
throw new ArgumentException("MenuDto içinde geçerli bir Id bulunmalıdır.");
|
throw new ArgumentException("MenuDto içinde geçerli bir Id bulunmalıdır.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var key = await _repositoryKey.FirstOrDefaultAsync(
|
// Tüm DisplayName'leri topla
|
||||||
a => a.Key == input.DisplayName &&
|
var displayNames = inputs.Select(x => x.DisplayName).Distinct().ToList();
|
||||||
a.ResourceName == PlatformConsts.AppName);
|
|
||||||
|
|
||||||
if (key is null)
|
// Mevcut key'leri tek sorguda getir
|
||||||
|
var existingKeys = await AsyncExecuter.ToListAsync(
|
||||||
|
(await _repositoryKey.GetQueryableAsync())
|
||||||
|
.Where(a => displayNames.Contains(a.Key) && a.ResourceName == PlatformConsts.AppName));
|
||||||
|
|
||||||
|
var existingKeyNames = existingKeys.Select(x => x.Key).ToHashSet();
|
||||||
|
|
||||||
|
// Eksik key'leri toplu ekle
|
||||||
|
var newKeys = displayNames
|
||||||
|
.Where(name => !existingKeyNames.Contains(name))
|
||||||
|
.Select(name => new LanguageKey
|
||||||
{
|
{
|
||||||
await _repositoryKey.InsertAsync(new LanguageKey
|
Key = name,
|
||||||
{
|
|
||||||
Key = input.DisplayName,
|
|
||||||
ResourceName = PlatformConsts.AppName
|
ResourceName = PlatformConsts.AppName
|
||||||
});
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (newKeys.Any())
|
||||||
|
{
|
||||||
|
await _repositoryKey.InsertManyAsync(newKeys, autoSave: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Menüleri güncelle
|
||||||
|
var result = new List<MenuDto>();
|
||||||
|
foreach (var input in inputs)
|
||||||
|
{
|
||||||
var updated = await base.UpdateAsync(input.Id, input);
|
var updated = await base.UpdateAsync(input.Id, input);
|
||||||
result.Add(updated);
|
result.Add(updated);
|
||||||
}
|
}
|
||||||
|
|
@ -221,5 +245,3 @@ public class MenuAppService : CrudAppService<
|
||||||
return entityDtos;
|
return entityDtos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,14 +122,10 @@ const List: React.FC = () => {
|
||||||
<h4 className="text-sm font-medium">{translate('::' + gridDto.gridOptions.title)}</h4>
|
<h4 className="text-sm font-medium">{translate('::' + gridDto.gridOptions.title)}</h4>
|
||||||
<Badge content={viewMode} />
|
<Badge content={viewMode} />
|
||||||
|
|
||||||
<p className="ml-2 text-xs text-slate-500 mr-auto">
|
|
||||||
{translate('::' + gridDto.gridOptions.description)}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{/* =======================
|
{/* =======================
|
||||||
VIEW BUTTONS
|
VIEW BUTTONS
|
||||||
======================= */}
|
======================= */}
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1 ml-auto">
|
||||||
{gridDto?.gridOptions?.layoutDto.scheduler &&
|
{gridDto?.gridOptions?.layoutDto.scheduler &&
|
||||||
gridDto?.gridOptions?.schedulerOptionDto?.textExpr &&
|
gridDto?.gridOptions?.schedulerOptionDto?.textExpr &&
|
||||||
gridDto?.gridOptions?.schedulerOptionDto?.startDateExpr && (
|
gridDto?.gridOptions?.schedulerOptionDto?.startDateExpr && (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue