Skip to content

Commit c1f17b8

Browse files
Copiloteinari
andcommitted
feat: add revision/generation dropdowns in workbench and expose compensation content via API
- Add Content to EventCompensation concept and OriginalContent to AppendedEvent - Update EventConverter to populate compensation content and original content - Add EventCompensation gRPC contract class with content - Update AppendedEvent contract with OriginalContent and Compensations - Add GetAllGenerationsForEventType API endpoint - Update AppendedEventConverters at kernel service and API layers - Add EventCompensation HTTP API model - Update proto files (events.proto, eventsequences.proto) - Regenerate TypeScript proxies (AppendedEvent, EventCompensation, AllEventTypeGenerations) - Add revision dropdown in EventDetails for compensated events - Add generation dropdown in TypeDetails for event types with multiple generations - Add translation strings for revision/generation UI Co-authored-by: einari <134365+einari@users.noreply.github.com>
1 parent aaa9765 commit c1f17b8

File tree

25 files changed

+588
-27
lines changed

25 files changed

+588
-27
lines changed

Source/Clients/Api/EventTypes/EventTypeQueries.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,16 @@ public ISubject<IEnumerable<EventTypeRegistration>> AllEventTypesWithSchemas([Fr
6161
observable.Subscribe(subject);
6262
return subject;
6363
}
64+
65+
/// <summary>
66+
/// Gets all generations for a specific event type.
67+
/// </summary>
68+
/// <param name="eventStore">The event store to get event type generations for.</param>
69+
/// <param name="eventTypeId">The event type identifier to get generations for.</param>
70+
/// <returns>Collection of event type registrations, one per generation.</returns>
71+
[HttpGet("{eventTypeId}/generations")]
72+
public async Task<IEnumerable<EventTypeRegistration>> AllEventTypeGenerations(
73+
[FromRoute] string eventStore,
74+
[FromRoute] string eventTypeId) =>
75+
(await _eventTypes.GetAllGenerationsForEventType(new() { EventStore = eventStore, EventTypeId = eventTypeId })).ToApi();
6476
}

Source/Clients/Api/Events/AppendedEvent.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,11 @@ namespace Cratis.Chronicle.Api.Events;
88
/// </summary>
99
/// <param name="Context">The context for the event.</param>
1010
/// <param name="Content">The JSON representation content of the event.</param>
11-
public record AppendedEvent(EventContext Context, string Content);
11+
/// <param name="OriginalContent">The original JSON content before any compensations. Only present when compensated.</param>
12+
/// <param name="Compensations">The compensations applied to this event, if any.</param>
13+
public record AppendedEvent(
14+
EventContext Context,
15+
string Content,
16+
string OriginalContent = "",
17+
IEnumerable<EventCompensation>? Compensations = null);
18+

Source/Clients/Api/Events/AppendedEventConverters.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Cratis. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4+
using Cratis.Chronicle.Api.Identities;
5+
46
namespace Cratis.Chronicle.Api.Events;
57

68
/// <summary>
@@ -15,7 +17,9 @@ internal static class AppendedEventConverters
1517
/// <returns>The converted appended event.</returns>
1618
public static AppendedEvent ToApi(this Contracts.Events.AppendedEvent appendedEvent) => new(
1719
appendedEvent.Context.ToApi(),
18-
appendedEvent.Content);
20+
appendedEvent.Content,
21+
appendedEvent.OriginalContent,
22+
appendedEvent.Compensations.Select(c => c.ToApi()).ToArray());
1923

2024
/// <summary>
2125
/// Converts a collection of contract <see cref="Contracts.Events.AppendedEvent"/> to a collection of <see cref="AppendedEvent"/>.
@@ -35,4 +39,16 @@ public static IEnumerable<AppendedEvent> ToApi(this IEnumerable<Contracts.Events
3539
Context = appendedEvent.Context.ToContract(),
3640
Content = appendedEvent.Content
3741
};
42+
43+
/// <summary>
44+
/// Converts a contract <see cref="Contracts.Events.EventCompensation"/> to an <see cref="EventCompensation"/>.
45+
/// </summary>
46+
/// <param name="compensation">The contract compensation to convert.</param>
47+
/// <returns>The converted compensation.</returns>
48+
public static EventCompensation ToApi(this Contracts.Events.EventCompensation compensation) => new(
49+
compensation.Generation,
50+
compensation.CorrelationId,
51+
compensation.CausedBy.ToApi(),
52+
compensation.Occurred,
53+
compensation.Content);
3854
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) Cratis. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Cratis.Chronicle.Api.Identities;
5+
6+
namespace Cratis.Chronicle.Api.Events;
7+
8+
/// <summary>
9+
/// Represents a compensation applied to an event.
10+
/// </summary>
11+
/// <param name="Generation">The event type generation of this compensation.</param>
12+
/// <param name="CorrelationId">The correlation id of the compensation.</param>
13+
/// <param name="CausedBy">Who or what caused the compensation.</param>
14+
/// <param name="Occurred">When the compensation occurred.</param>
15+
/// <param name="Content">The JSON content of the compensating event.</param>
16+
public record EventCompensation(
17+
uint Generation,
18+
string CorrelationId,
19+
Identity CausedBy,
20+
DateTimeOffset Occurred,
21+
string Content);

Source/Kernel/Concepts/Events/AppendedEvent.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ namespace Cratis.Chronicle.Concepts.Events;
1212
/// <param name="Content">The content in the form of an <see cref="ExpandoObject"/>.</param>
1313
public record AppendedEvent(EventContext Context, ExpandoObject Content)
1414
{
15+
/// <summary>
16+
/// Gets the original content of the event as a JSON string, before any compensations were applied.
17+
/// Only populated when the event has been compensated.
18+
/// </summary>
19+
public string OriginalContent { get; init; } = string.Empty;
20+
1521
/// <summary>
1622
/// Gets the compensations applied to this event, if any.
1723
/// </summary>

Source/Kernel/Concepts/Events/EventCompensation.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ namespace Cratis.Chronicle.Concepts.Events;
1414
/// <param name="Causation">The chain of <see cref="Causation"/> for the compensation.</param>
1515
/// <param name="CausedBy">The <see cref="Identity"/> that caused the compensation.</param>
1616
/// <param name="Occurred">When the compensation occurred.</param>
17+
/// <param name="Content">The compensating content as a JSON string.</param>
1718
public record EventCompensation(
1819
EventTypeGeneration EventTypeGeneration,
1920
CorrelationId CorrelationId,
2021
IEnumerable<Causation> Causation,
2122
Identity CausedBy,
22-
DateTimeOffset Occurred);
23+
DateTimeOffset Occurred,
24+
string Content = "");

Source/Kernel/Contracts/Contracts.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<TargetsForTfmSpecificContentInPackage></TargetsForTfmSpecificContentInPackage>
77
<AssemblyName>Cratis.Chronicle.Contracts</AssemblyName>
88
<RootNamespace>Cratis.Chronicle.Contracts</RootNamespace>
9-
<NoWarn>$(NoWarn);CS8618;PBN2008</NoWarn>
9+
<NoWarn>$(NoWarn);CS8618;PBN2008;PBN0022</NoWarn>
1010
</PropertyGroup>
1111
<ItemGroup>
1212
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />

Source/Kernel/Contracts/Events/AppendedEvent.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,18 @@ public class AppendedEvent
2020
/// </summary>
2121
[ProtoMember(2)]
2222
public string Content { get; set; }
23+
24+
/// <summary>
25+
/// Gets or sets the original JSON content before any compensations were applied.
26+
/// Only populated when the event has been compensated.
27+
/// </summary>
28+
[ProtoMember(3)]
29+
public string OriginalContent { get; set; } = string.Empty;
30+
31+
/// <summary>
32+
/// Gets or sets the compensations applied to this event, if any.
33+
/// </summary>
34+
[ProtoMember(4)]
35+
public IList<EventCompensation> Compensations { get; set; } = [];
2336
}
37+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) Cratis. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Cratis.Chronicle.Contracts.Identities;
5+
6+
namespace Cratis.Chronicle.Contracts.Events;
7+
8+
/// <summary>
9+
/// Represents a compensation applied to an event.
10+
/// </summary>
11+
[ProtoContract]
12+
public class EventCompensation
13+
{
14+
/// <summary>
15+
/// Gets or sets the generation of the event type for this compensation.
16+
/// </summary>
17+
[ProtoMember(1)]
18+
public uint Generation { get; set; }
19+
20+
/// <summary>
21+
/// Gets or sets the correlation id of the compensation.
22+
/// </summary>
23+
[ProtoMember(2)]
24+
public string CorrelationId { get; set; } = string.Empty;
25+
26+
/// <summary>
27+
/// Gets or sets who or what caused the compensation.
28+
/// </summary>
29+
[ProtoMember(3)]
30+
public Identity CausedBy { get; set; }
31+
32+
/// <summary>
33+
/// Gets or sets when the compensation occurred.
34+
/// </summary>
35+
[ProtoMember(4)]
36+
public DateTimeOffset Occurred { get; set; }
37+
38+
/// <summary>
39+
/// Gets or sets the JSON content of the compensating event.
40+
/// </summary>
41+
[ProtoMember(5)]
42+
public string Content { get; set; } = string.Empty;
43+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) Cratis. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
namespace Cratis.Chronicle.Contracts.Events;
5+
6+
/// <summary>
7+
/// Represents a request for getting all generations for a specific event type.
8+
/// </summary>
9+
[ProtoContract]
10+
public class GetEventTypeGenerationsRequest
11+
{
12+
/// <summary>
13+
/// Gets or sets the event store name.
14+
/// </summary>
15+
[ProtoMember(1)]
16+
public string EventStore { get; set; } = string.Empty;
17+
18+
/// <summary>
19+
/// Gets or sets the event type identifier.
20+
/// </summary>
21+
[ProtoMember(2)]
22+
public string EventTypeId { get; set; } = string.Empty;
23+
}

0 commit comments

Comments
 (0)