Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show activity log. #233

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/Application/Features/Dashboard/DTOs/ActivityLogDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Cfo.Cats.Domain.Entities.Participants;

namespace Cfo.Cats.Application.Features.Dashboard.DTOs;

public class ActivityLogDto
{
public string ParticipantId { get; set; } = default!;
public string ParticipantName { get;set; } = default!;

public TimelineEventType EventType { get;set; } = default!;

public string Line1 { get;set; } = default!;
public string? Line2 {get;set;}
public string? Line3 {get;set;}
public string CreatedBy {get;set;} = default!;
public DateTime Created { get; set;}

private class Mapper : Profile
{
public Mapper()
{
#nullable disable
CreateMap<Timeline, ActivityLogDto>(MemberList.None)
.ForMember(t => t.ParticipantId, o => o.MapFrom(s => s.ParticipantId))
.ForMember(t => t.ParticipantName, o => o.MapFrom(s => s.Participant.FirstName + " " + s.Participant.LastName))
.ForMember(t => t.EventType, o => o.MapFrom(s => s.EventType))
.ForMember(t => t.Line1, o => o.MapFrom(s => s.Line1))
.ForMember(t => t.Line2, o => o.MapFrom(s => s.Line2))
.ForMember(t => t.Line3, o => o.MapFrom(s => s.Line3))
.ForMember(t => t.CreatedBy, o => o.MapFrom(s => s.CreatedByUser.DisplayName))
.ForMember(t => t.Created, o => o.MapFrom(s => s.Created));

}
}


}
41 changes: 41 additions & 0 deletions src/Application/Features/Dashboard/Queries/GetActivityLog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Cfo.Cats.Application.Common.Security;
using Cfo.Cats.Application.Features.Dashboard.DTOs;
using Cfo.Cats.Application.Features.Dashboard.Specifications;
using Cfo.Cats.Application.SecurityConstants;
using Cfo.Cats.Domain.Entities.Participants;
using DocumentFormat.OpenXml.Vml.Spreadsheet;

namespace Cfo.Cats.Application.Features.Dashboard.Queries;

public static class GetActivityLog
{
[RequestAuthorize(Policy = SecurityPolicies.AuthorizedUser)]
public class Query : ActivityLogFilter, IRequest<PaginatedData<ActivityLogDto>>
{
public ActivityLogSpecification Specification => new(this);

}

public class Handler(IUnitOfWork unitOfWork, IMapper mapper) : IRequestHandler<Query, PaginatedData<ActivityLogDto>>
{
public async Task<PaginatedData<ActivityLogDto>> Handle(Query request, CancellationToken cancellationToken)
{
var data = await unitOfWork.DbContext.Timelines.AsNoTracking()
.OrderBy($"{request.OrderBy} {request.SortDirection}")
.ProjectToPaginatedDataAsync<Timeline, ActivityLogDto>(request.Specification, request.PageNumber, request.PageSize, mapper.ConfigurationProvider, cancellationToken );

return data!;
}
}

public class Validator : AbstractValidator<Query>
{
public Validator()
{
RuleFor(x => x.CurrentUser)
.NotNull();
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Cfo.Cats.Application.Common.Security;

namespace Cfo.Cats.Application.Features.Dashboard.Specifications;

public class ActivityLogFilter : PaginationFilter
{
public UserProfile? CurrentUser { get;set; }
public ActivityLogListView ListView { get; set; } = ActivityLogListView.All;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Cfo.Cats.Application.Features.Dashboard.Specifications;

public enum ActivityLogListView
{
[Description("All")]
All,
[Description("Created Today")]
CreatedToday,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Cfo.Cats.Domain.Entities.Participants;

namespace Cfo.Cats.Application.Features.Dashboard.Specifications;

public class ActivityLogSpecification : Specification<Timeline>
{
public ActivityLogSpecification(ActivityLogFilter filter)
{
#nullable disable

var today = DateTime.Now.ToUniversalTime().Date;



Query.Where(t => t.Participant.OwnerId == filter.CurrentUser.UserId, filter.CurrentUser.AssignedRoles is []);

Query.Where(t => t.Participant.Owner.TenantId.StartsWith(filter.CurrentUser.TenantId));

Query.Where(
p => p.Created >= DateTime.Now.Date,
filter.ListView == ActivityLogListView.CreatedToday
);
}
}
2 changes: 2 additions & 0 deletions src/Domain/Entities/Participants/Timeline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,7 @@ public static Timeline CreateTimeline(string participantId, TimelineEventType ev
}

public virtual ApplicationUser? CreatedByUser { get; private set; }

public virtual Participant? Participant { get; private set; }
}

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public void Configure(EntityTypeBuilder<Timeline> builder)

builder.HasKey(t => t.Id);

builder.HasOne<Domain.Entities.Participants.Participant>()
builder.HasOne(t => t.Participant)
.WithMany()
.HasForeignKey("ParticipantId");

Expand Down
147 changes: 147 additions & 0 deletions src/Server.UI/Pages/Dashboard/Components/ActivityLog.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
@using Cfo.Cats.Application.Features.Dashboard.DTOs
@using Cfo.Cats.Application.Features.Dashboard.Specifications
@using Cfo.Cats.Application.Features.Dashboard.Queries
@using Humanizer

<style>
.mud-table-toolbar {
height: 120px !important;
}

.pointer-cursor {
cursor: pointer;
}

</style>
@inherits CatsComponentBase

<MudCard>
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.h6">Activity Log</MudText>
</CardHeaderContent>
</MudCardHeader>
<MudCardContent>
<MudDataGrid ServerData="@(ServerReload)" T="ActivityLogDto" FixedHeader="true" FixedFooter="true"
Virtualize="true" @bind-RowsPerPage="defaultPageSize" Height="500px" Loading="@loading" Hover="true" RowClick="@RowClicked"
RowClass="pointer-cursor" @ref="table">
<ToolBarContent>
<div class="d-flex align-start flex-grow-1">
<div class="d-flex gap-4">
<MudIcon Icon="@Icons.Material.Filled.PendingActions" Size="Size.Large"/>
<div class="d-flex flex-column">
<MudText Typo="Typo.caption" Class="mb-2">Activity Log</MudText>
<MudEnumSelect Style="min-width:160px" TEnum="ActivityLogListView" ValueChanged="OnChangedListView" Value="Query.ListView" Dense="true" Label="List View">
</MudEnumSelect>
</div>
</div>
<div class="flex-grow-1"/>

<div class="d-flex flex-column justify-end">
<div class="d-flex">
<MudButton Variant="Variant.Outlined"
Size="Size.Small"
OnClick="@(() => OnRefresh())"
StartIcon="@Icons.Material.Filled.Refresh" IconColor="Color.Surface" Color="Color.Primary"
Style="margin-right: 4px; margin-bottom:4px">
@ConstantString.Refresh
</MudButton>
</div>
</div>
</div>
</ToolBarContent>
<Columns>
<PropertyColumn Property="x => x.ParticipantId" Title="Participant Id"></PropertyColumn>
<PropertyColumn Property="x => x.ParticipantName" Title="Participant" Sortable="false"></PropertyColumn>
<PropertyColumn Property="x => x.EventType" Sortable="true"> </PropertyColumn>
<PropertyColumn Property="x => x.Line1" Title="Details" Sortable="false">
<CellTemplate>
<div class="d-flex flex-column">
<MudText Typo="Typo.body2">@context.Item.Line1</MudText>
@if (context.Item.Line2 is not null)
{
<MudText Typo="Typo.body2">@context.Item.Line2</MudText>
}
@if (context.Item.Line3 is not null)
{
<MudText Typo="Typo.body2">@context.Item.Line3</MudText>
}
</div>
</CellTemplate>
</PropertyColumn>
<PropertyColumn Property="x => x.CreatedBy" Title="Created" Sortable="true" SortBy="x => x.Created">
<CellTemplate>
<div class="d-flex flex-column">
<MudText Typo="Typo.body2">@context.Item.CreatedBy</MudText>
<MudText Typo="Typo.body2" Class="mud-text-secondary">@context.Item.Created.Humanize()
</MudText>
</div>
</CellTemplate>
</PropertyColumn>
</Columns>
<NoRecordsContent>
<MudText>@ConstantString.NoRecords</MudText>
</NoRecordsContent>
<LoadingContent>
<MudText>@ConstantString.Loading</MudText>
</LoadingContent>
<PagerContent>
<MudDataGridPager PageSizeOptions="@(new[] { 10, 15, 30, 50, 100, 500, 1000 })" />
</PagerContent>
</MudDataGrid>
</MudCardContent>
</MudCard>

@code
{
[CascadingParameter]
public UserProfile? UserProfile { get; set; }

private GetActivityLog.Query Query { get; } = new();

private MudDataGrid<ActivityLogDto> table = null!;

private bool loading;

private int defaultPageSize = 15;

private readonly ActivityLogDto currentDto = new();

private async Task<GridData<ActivityLogDto>> ServerReload(GridState<ActivityLogDto> state)
{
try
{
loading = true;
Query.CurrentUser = UserProfile;
Query.OrderBy = state.SortDefinitions.FirstOrDefault()?.SortBy ?? "Created";
Query.SortDirection = state.SortDefinitions.FirstOrDefault()?.Descending ?? true ? SortDirection.Descending.ToString() :
SortDirection.Ascending.ToString();
Query.PageNumber = state.Page + 1;
Query.PageSize = state.PageSize;

var result = await GetNewMediator().Send(Query).ConfigureAwait(false);
return new GridData<ActivityLogDto> { TotalItems = result.TotalItems, Items = result.Items };
}
finally
{
loading = false;
}
}

private async Task OnRefresh()
{
await table.ReloadServerData();
}

private async Task OnChangedListView(ActivityLogListView listview)
{
Query.ListView = listview;
await table.ReloadServerData();
}

private void RowClicked(DataGridRowClickEventArgs<ActivityLogDto> args)
{
Navigation.NavigateTo($"/pages/participants/{args.Item.ParticipantId}");
}

}
Loading
Loading