Skip to content

Commit a9febe0

Browse files
authored
Add support for showing Processes in Change History (#2651)
We're moving to a new way of recording data changes - processes. This adds support for showing these types of changes in the Change History UI. Process-specific views will follow later.
1 parent 97874af commit a9febe0

File tree

11 files changed

+52
-9
lines changed

11 files changed

+52
-9
lines changed

TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Mappings/ProcessEventMapping.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public void Configure(EntityTypeBuilder<ProcessEvent> builder)
1515
.HasConversion(
1616
v => JsonSerializer.Serialize(v, typeof(IEvent), IEvent.SerializerOptions),
1717
v => JsonSerializer.Deserialize<IEvent>(v, IEvent.SerializerOptions)!);
18-
builder.HasOne<Process>().WithMany(a => a.Events).HasForeignKey(ae => ae.ProcessId);
18+
builder.HasOne<Process>().WithMany(a => a.Events).HasForeignKey(ae => ae.ProcessId).HasConstraintName("fk_process_events_process_process_id");
1919
builder.HasIndex(e => new { e.PersonIds, e.EventName }).HasMethod("GIN").IsCreatedConcurrently();
2020
builder.HasIndex(e => e.ProcessId).IsCreatedConcurrently();
2121
}

TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Mappings/ProcessMapping.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public class ProcessMapping : IEntityTypeConfiguration<Process>
88
public void Configure(EntityTypeBuilder<Process> builder)
99
{
1010
builder.ToTable("processes");
11-
builder.HasOne<User>().WithMany().HasForeignKey(p => p.UserId);
11+
builder.HasOne(p => p.User).WithMany().HasForeignKey(p => p.UserId);
1212
builder.HasIndex(a => a.ProcessType);
1313
builder.HasIndex(a => a.PersonIds).HasMethod("GIN");
1414
}

TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Migrations/TrsDbContextModelSnapshot.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4562,7 +4562,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
45624562
.HasColumnType("text")
45634563
.HasColumnName("dqt_user_name");
45644564

4565-
b.PrimitiveCollection<HashSet<Guid>>("PersonIds")
4565+
b.PrimitiveCollection<List<Guid>>("PersonIds")
45664566
.IsRequired()
45674567
.HasColumnType("uuid[]")
45684568
.HasColumnName("person_ids");
@@ -20990,10 +20990,12 @@ protected override void BuildModel(ModelBuilder modelBuilder)
2099020990

2099120991
modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.Process", b =>
2099220992
{
20993-
b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.User", null)
20993+
b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.UserBase", "User")
2099420994
.WithMany()
2099520995
.HasForeignKey("UserId")
2099620996
.HasConstraintName("fk_processes_users_user_id");
20997+
20998+
b.Navigation("User");
2099720999
});
2099821000

2099921001
modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.ProcessEvent", b =>

TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/Process.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ public class Process
66
public required ProcessType ProcessType { get; init; }
77
public required DateTime Created { get; init; }
88
public required Guid? UserId { get; init; }
9+
public UserBase? User { get; }
910
public required Guid? DqtUserId { get; init; }
1011
public required string? DqtUserName { get; init; }
1112
public ICollection<ProcessEvent>? Events { get; }
12-
public required HashSet<Guid> PersonIds { get; init; }
13+
public required List<Guid> PersonIds { get; init; }
1314
}

TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/TrsDbContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ public static TrsDbContext Create(string connectionString, int? commandTimeout =
136136

137137
public DbSet<TrnRange> TrnRanges => Set<TrnRange>();
138138

139+
public DbSet<Process> Processes => Set<Process>();
140+
139141
public static void ConfigureOptions(DbContextOptionsBuilder optionsBuilder, string? connectionString = null, int? commandTimeout = null)
140142
{
141143
Action<NpgsqlDbContextOptionsBuilder> configureOptions = o => o.CommandTimeout(commandTimeout);

TeachingRecordSystem/src/TeachingRecordSystem.Core/IEventPublisher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public async Task PublishEventAsync(IEvent @event, ProcessContext processContext
1818
dbContext.Set<Process>().Add(processContext.Process);
1919
}
2020

21-
@event.PersonIds.ForEach(e => processContext.Process.PersonIds.Add(e));
21+
@event.PersonIds.Except(processContext.Process.PersonIds).ForEach(e => processContext.Process.PersonIds.Add(e));
2222

2323
var processEvent = new ProcessEvent
2424
{

TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/ChangeHistory.cshtml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
@page "/persons/{personId}/change-history"
22
@using TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.Timeline.Events
3+
@using TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.Timeline.Processes
34
@model TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.ChangeHistoryModel
45
@{
56
Layout = "Layout";
@@ -23,6 +24,7 @@ else
2324
var viewName = timelineItem.ItemType switch
2425
{
2526
TimelineItemType.Event => $"./Timeline/Events/{((TimelineEvent)timelineItem.ItemModel).Event.GetEventName()}.cshtml",
27+
TimelineItemType.Process => $"./Timeline/Processes/{((TimelineProcess)timelineItem.ItemModel).Process.ProcessType.ToString()}.cshtml",
2628
_ => $"./Timeline/{timelineItem.ItemType}.cshtml"
2729
};
2830

TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/ChangeHistory.cshtml.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
using Microsoft.AspNetCore.Mvc;
33
using Microsoft.AspNetCore.Mvc.RazorPages;
44
using TeachingRecordSystem.Core.DataStore.Postgres;
5+
using TeachingRecordSystem.Core.DataStore.Postgres.Models;
56
using TeachingRecordSystem.Core.Events.Legacy;
67
using TeachingRecordSystem.SupportUi.Infrastructure.Security;
78
using TeachingRecordSystem.SupportUi.Infrastructure.Security.Requirements;
9+
using TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.Timeline;
810
using TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.Timeline.Events;
11+
using TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.Timeline.Processes;
912

1013
namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail;
1114

@@ -144,7 +147,15 @@ e.person_ids @> ARRAY[{PersonId}]
144147
""")
145148
.ToListAsync();
146149

147-
var allResults = eventsWithUser.Select(MapTimelineEvent).ToArray();
150+
var processes = await dbContext.Processes
151+
.Where(p => p.PersonIds.Contains(PersonId))
152+
.Include(p => p.User)
153+
.Include(p => p.Events).AsSplitQuery()
154+
.ToListAsync();
155+
156+
var allResults = eventsWithUser.Select(MapTimelineEvent)
157+
.Concat(processes.Select(MapTimelineProcess))
158+
.ToArray();
148159

149160
TimelineItems = allResults
150161
.OrderByDescending(i => i.Timestamp)
@@ -187,6 +198,13 @@ private TimelineItem MapTimelineEvent(EventWithUser eventWithUser)
187198
return (TimelineItem)Activator.CreateInstance(timelineItemType, TimelineItemType.Event, PersonId, timelineEvent.Event.CreatedUtc.ToGmt(), timelineEvent)!;
188199
}
189200

201+
private TimelineItem MapTimelineProcess(Process process) =>
202+
new TimelineItem<TimelineProcess>(
203+
TimelineItemType.Process,
204+
PersonId,
205+
process.Created.ToGmt(),
206+
new TimelineProcess(process, new RaisedByUserInfo { Name = process.DqtUserName ?? process.User?.Name! }));
207+
190208
/// <summary>
191209
/// Flattened out record to allow Event, TRS User and DQT User to be returned in a single SQL query
192210
/// </summary>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using TeachingRecordSystem.Core.DataStore.Postgres.Models;
3+
4+
namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.Timeline.Processes;
5+
6+
public record TimelineProcess(Process Process, RaisedByUserInfo RaisedByUser)
7+
{
8+
public bool ContainsEvent<T>() where T : IEvent => Process.Events!.Select(pe => pe.Payload).OfType<T>().Any();
9+
10+
public T GetEvent<T>() where T : IEvent => Process.Events!.Select(pe => pe.Payload).OfType<T>().Single();
11+
12+
public bool TryGetEvent<T>([NotNullWhen(true)] out T? @event) where T : IEvent
13+
{
14+
@event = Process.Events!.Select(pe => pe.Payload).OfType<T>().SingleOrDefault();
15+
return @event is not null;
16+
}
17+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.Timeline.Events;
1+
namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.Timeline;
22

33
public record RaisedByUserInfo
44
{

0 commit comments

Comments
 (0)