Skip to content

Commit 3051445

Browse files
Add RealTime Comment Updates (#8868)
* Add Signal R package * Add SignalR Service * Push Comment Updates to All clients from controller * Hookup SignalR ClientSide * Two way comment push * Add Real Time Comment Updates
1 parent 5835f21 commit 3051445

21 files changed

Lines changed: 600 additions & 137 deletions
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System.Text.Json.Serialization;
2+
using APIViewWeb.LeanModels;
3+
4+
namespace APIViewWeb.DTOs
5+
{
6+
public enum CommentThreadUpdateAction
7+
{
8+
CommentCreated = 0,
9+
CommentTextUpdate,
10+
CommentResolved,
11+
CommentUnResolved,
12+
CommentUpVoteToggled,
13+
CommentDeleted
14+
}
15+
16+
public class CommentUpdatesDto
17+
{
18+
[JsonPropertyName("commentThreadUpdateAction")]
19+
public CommentThreadUpdateAction CommentThreadUpdateAction { get; set; }
20+
[JsonPropertyName("nodeId")]
21+
public string NodeId { get; set; }
22+
[JsonPropertyName("nodeIdHashed")]
23+
public string NodeIdHashed { get; set; }
24+
[JsonPropertyName("reviewId")]
25+
public string ReviewId { get; set; }
26+
[JsonPropertyName("revisionId")]
27+
public string RevisionId { get; set; }
28+
[JsonPropertyName("commentId")]
29+
public string CommentId { get; set; }
30+
[JsonPropertyName("elementId")]
31+
public string ElementId { get; set; }
32+
[JsonPropertyName("commentText")]
33+
public string CommentText { get; set; }
34+
[JsonPropertyName("comment")]
35+
public CommentItemModel Comment { get; set; }
36+
[JsonPropertyName("resolvedBy")]
37+
public string ResolvedBy { get; set; }
38+
[JsonPropertyName("associatedRowPositionInGroup")]
39+
public int? AssociatedRowPositionInGroup { get; set; }
40+
[JsonPropertyName("allowAnyOneToResolve")]
41+
public bool? AllowAnyOneToResolve { get; set; }
42+
}
43+
}

src/dotnet/APIView/APIViewWeb/Helpers/APIHelpers.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public PagedList(IEnumerable<T> items, int noOfItemsRead, int totalCount, int pa
7373
public class LeanJsonResult : JsonResult
7474
{
7575
private readonly int _statusCode;
76+
private readonly string _locationUrl;
7677

7778
private static readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions
7879
{
@@ -88,6 +89,12 @@ public LeanJsonResult(object value, int statusCode) : base(value)
8889
_statusCode = statusCode;
8990
}
9091

92+
public LeanJsonResult(object value, int statusCode, string locationUrl) : base(value)
93+
{
94+
_statusCode = statusCode;
95+
_locationUrl = locationUrl;
96+
}
97+
9198
public override async Task ExecuteResultAsync(ActionContext context)
9299
{
93100
if (context == null)
@@ -99,6 +106,7 @@ public override async Task ExecuteResultAsync(ActionContext context)
99106

100107
response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
101108
response.StatusCode = _statusCode;
109+
response.Headers["Location"] = _locationUrl;
102110

103111
var serializedValue = JsonSerializer.Serialize(Value, _serializerOptions);
104112
await response.WriteAsync(serializedValue);

src/dotnet/APIView/APIViewWeb/Hubs/SignalRHub.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System.Threading.Tasks;
2+
using APIViewWeb.DTOs;
23
using Microsoft.AspNetCore.Authorization;
34
using Microsoft.AspNetCore.SignalR;
4-
using Microsoft.Extensions.Logging;
55

66
namespace APIViewWeb.Hubs
77
{
@@ -26,5 +26,14 @@ public async Task PushComment(string reviewId, string elementId, string partialV
2626
await Clients.Others.SendAsync("ReceiveComment", reviewId, elementId, partialViewResult);
2727
}
2828
}
29-
}
29+
30+
/// <summary>
31+
/// Endpoint Consumed by Client SPA
32+
/// </summary>
33+
/// <returns></returns>
34+
public async Task PushCommentUpdates(CommentUpdatesDto commentUpdatesDto)
35+
{
36+
await Clients.All.SendAsync("ReceiveCommentUpdates", commentUpdatesDto);
37+
}
38+
}
3039
}

src/dotnet/APIView/APIViewWeb/LeanControllers/CommentsController.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using APIViewWeb.Helpers;
2+
using APIViewWeb.Hubs;
23
using APIViewWeb.LeanModels;
34
using APIViewWeb.Managers;
45
using Microsoft.AspNetCore.Http;
56
using Microsoft.AspNetCore.Mvc;
7+
using Microsoft.AspNetCore.SignalR;
68
using Microsoft.Extensions.Logging;
79
using System;
810
using System.Collections.Generic;
@@ -19,8 +21,8 @@ public class CommentsController : BaseApiController
1921
private readonly IReviewManager _reviewManager;
2022
private readonly INotificationManager _notificationManager;
2123

22-
public CommentsController(ILogger<CommentsController> logger,
23-
ICommentsManager commentManager, IReviewManager reviewManager, INotificationManager notificationManager)
24+
public CommentsController(ILogger<CommentsController> logger, ICommentsManager commentManager,
25+
IReviewManager reviewManager, INotificationManager notificationManager)
2426
{
2527
_logger = logger;
2628
_commentsManager = commentManager;
@@ -126,7 +128,7 @@ public async Task<ActionResult> CreateCommentAsync(
126128
{
127129
await _notificationManager.SubscribeAsync(review, User);
128130
}
129-
return CreatedAtAction("GetComments", new { reviewId = reviewId }, comment);
131+
return new LeanJsonResult(comment, StatusCodes.Status201Created, Url.Action("GetComments", new { reviewId = reviewId }));
130132
}
131133

132134
/// <summary>

src/dotnet/APIView/APIViewWeb/LeanModels/ChangeHistory.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace APIViewWeb.LeanModels
66
{
7+
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
78
[JsonConverter(typeof(StringEnumConverter))]
89
public enum AICommentChangeAction
910
{
@@ -12,6 +13,7 @@ public enum AICommentChangeAction
1213
Modified
1314
}
1415

16+
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
1517
[JsonConverter(typeof(StringEnumConverter))]
1618
public enum ReviewChangeAction
1719
{
@@ -24,6 +26,7 @@ public enum ReviewChangeAction
2426
UnDeleted
2527
}
2628

29+
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
2730
[JsonConverter(typeof(StringEnumConverter))]
2831
public enum APIRevisionChangeAction
2932
{
@@ -34,6 +37,7 @@ public enum APIRevisionChangeAction
3437
UnDeleted
3538
}
3639

40+
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
3741
[JsonConverter(typeof(StringEnumConverter))]
3842
public enum CommentChangeAction
3943
{

src/dotnet/APIView/APIViewWeb/LeanModels/CommentItemModel.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
namespace APIViewWeb.LeanModels
77
{
8+
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
89
[JsonConverter(typeof(StringEnumConverter))]
910
public enum CommentType
1011
{
@@ -14,6 +15,7 @@ public enum CommentType
1415

1516
public class CommentItemModel
1617
{
18+
[System.Text.Json.Serialization.JsonPropertyName("id")]
1719
[JsonProperty("id")]
1820
public string Id { get; set; } = IdHelper.GenerateId();
1921
public string ReviewId { get; set; }

0 commit comments

Comments
 (0)