Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit c8d2b53

Browse files
committed
Add "Reviewers" section to PR details.
1 parent 98e8241 commit c8d2b53

File tree

18 files changed

+610
-34
lines changed

18 files changed

+610
-34
lines changed

src/GitHub.App/GitHub.App.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@
236236
<Compile Include="ViewModels\GitHubPane\PullRequestCreationViewModel.cs" />
237237
<Compile Include="ViewModels\GitHubPane\NotAGitHubRepositoryViewModel.cs" />
238238
<Compile Include="ViewModels\GitHubPane\NotAGitRepositoryViewModel.cs" />
239+
<Compile Include="ViewModels\GitHubPane\PullRequestReviewSummaryViewModel.cs" />
239240
<Compile Include="ViewModels\RepositoryFormViewModel.cs" />
240241
<Compile Include="ViewModels\TeamExplorer\RepositoryPublishViewModel.cs" />
241242
<Compile Include="Caches\CacheIndex.cs" />

src/GitHub.App/Resources.Designer.cs

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/GitHub.App/Resources.resx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,16 @@
294294
Please install Git for Windows from:
295295
https://git-scm.com/download/win</value>
296296
</data>
297+
<data name="Approved" xml:space="preserve">
298+
<value>Approved</value>
299+
</data>
300+
<data name="ChangesRequested" xml:space="preserve">
301+
<value>Changes Requested</value>
302+
</data>
303+
<data name="Commented" xml:space="preserve">
304+
<value>Commented</value>
305+
</data>
306+
<data name="InProgress" xml:space="preserve">
307+
<value>InProgress</value>
308+
</data>
297309
</root>

src/GitHub.App/SampleData/PullRequestDetailViewModelDesigner.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,34 @@ public PullRequestDetailViewModelDesigner()
6767
modelsDir.Files.Add(oldBranchModel);
6868
gitHubDir.Directories.Add(modelsDir);
6969

70+
Reviews = new[]
71+
{
72+
new PullRequestReviewSummaryViewModel
73+
{
74+
Id = 2,
75+
User = new AccountDesigner { Login = "grokys", IsUser = true },
76+
State = PullRequestReviewState.Pending,
77+
FileCommentCount = 0,
78+
},
79+
new PullRequestReviewSummaryViewModel
80+
{
81+
Id = 1,
82+
User = new AccountDesigner { Login = "jcansdale", IsUser = true },
83+
State = PullRequestReviewState.Approved,
84+
FileCommentCount = 5,
85+
},
86+
new PullRequestReviewSummaryViewModel
87+
{
88+
Id = 2,
89+
User = new AccountDesigner { Login = "shana", IsUser = true },
90+
State = PullRequestReviewState.ChangesRequested,
91+
FileCommentCount = 5,
92+
},
93+
new PullRequestReviewSummaryViewModel
94+
{
95+
},
96+
};
97+
7098
Files = new PullRequestFilesViewModelDesigner();
7199
}
72100

@@ -81,6 +109,7 @@ public PullRequestDetailViewModelDesigner()
81109
public bool IsCheckedOut { get; }
82110
public bool IsFromFork { get; }
83111
public string Body { get; }
112+
public IReadOnlyList<IPullRequestReviewSummaryViewModel> Reviews { get; }
84113
public IPullRequestFilesViewModel Files { get; set; }
85114
public IPullRequestCheckoutState CheckoutState { get; set; }
86115
public IPullRequestUpdateState UpdateState { get; set; }
@@ -92,6 +121,7 @@ public PullRequestDetailViewModelDesigner()
92121
public ReactiveCommand<Unit> Pull { get; }
93122
public ReactiveCommand<Unit> Push { get; }
94123
public ReactiveCommand<object> OpenOnGitHub { get; }
124+
public ReactiveCommand<object> ShowReview { get; }
95125

96126
public Task InitializeAsync(ILocalRepositoryModel localRepository, IConnection connection, string owner, string repo, int number) => Task.CompletedTask;
97127

src/GitHub.App/ViewModels/GitHubPane/PullRequestDetailViewModel.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public sealed class PullRequestDetailViewModel : PanePageViewModelBase, IPullReq
4242
string targetBranchDisplayName;
4343
int commentCount;
4444
string body;
45+
IReadOnlyList<IPullRequestReviewSummaryViewModel> reviews;
4546
IPullRequestCheckoutState checkoutState;
4647
IPullRequestUpdateState updateState;
4748
string operationError;
@@ -117,6 +118,7 @@ public PullRequestDetailViewModel(
117118
SubscribeOperationError(SyncSubmodules);
118119

119120
OpenOnGitHub = ReactiveCommand.Create();
121+
ShowReview = ReactiveCommand.Create().OnExecuteCompleted(DoShowReview);
120122
}
121123

122124
/// <summary>
@@ -244,6 +246,15 @@ public string OperationError
244246
private set { this.RaiseAndSetIfChanged(ref operationError, value); }
245247
}
246248

249+
/// <summary>
250+
/// Gets the latest pull request review for each user.
251+
/// </summary>
252+
public IReadOnlyList<IPullRequestReviewSummaryViewModel> Reviews
253+
{
254+
get { return reviews; }
255+
private set { this.RaiseAndSetIfChanged(ref reviews, value); }
256+
}
257+
247258
/// <summary>
248259
/// Gets the pull request's changed files.
249260
/// </summary>
@@ -283,6 +294,11 @@ public Uri WebUrl
283294
/// </summary>
284295
public ReactiveCommand<object> OpenOnGitHub { get; }
285296

297+
/// <summary>
298+
/// Gets a command that navigates to a pull request review.
299+
/// </summary>
300+
public ReactiveCommand<object> ShowReview { get; }
301+
286302
/// <summary>
287303
/// Initializes the view model.
288304
/// </summary>
@@ -353,6 +369,8 @@ public async Task Load(IPullRequestModel pullRequest)
353369
TargetBranchDisplayName = GetBranchDisplayName(IsFromFork, pullRequest.Base?.Label);
354370
CommentCount = pullRequest.Comments.Count + pullRequest.ReviewComments.Count;
355371
Body = !string.IsNullOrWhiteSpace(pullRequest.Body) ? pullRequest.Body : Resources.NoDescriptionProvidedMarkdown;
372+
Reviews = PullRequestReviewSummaryViewModel.BuildByUser(pullRequest).ToList();
373+
356374
await Files.InitializeAsync(Session);
357375

358376
var localBranches = await pullRequestsService.GetLocalBranches(LocalRepository, pullRequest).ToList();
@@ -616,6 +634,11 @@ async Task DoSyncSubmodules(object unused)
616634
}
617635
}
618636

637+
void DoShowReview(object item)
638+
{
639+
// TODO
640+
}
641+
619642
class CheckoutCommandState : IPullRequestCheckoutState
620643
{
621644
public CheckoutCommandState(string caption, string disabledMessage)
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using GitHub.App;
5+
using GitHub.Models;
6+
7+
namespace GitHub.ViewModels.GitHubPane
8+
{
9+
/// <summary>
10+
/// Displays a short overview of a pull request review in the <see cref="PullRequestDetailViewModel"/>.
11+
/// </summary>
12+
public class PullRequestReviewSummaryViewModel : IPullRequestReviewSummaryViewModel
13+
{
14+
private static Dictionary<PullRequestReviewState, int> StatePriorities = new Dictionary<PullRequestReviewState, int>
15+
{
16+
{ PullRequestReviewState.Approved, 1 },
17+
{ PullRequestReviewState.ChangesRequested, 1 },
18+
{ PullRequestReviewState.Commented, 0 },
19+
{ PullRequestReviewState.Dismissed, 0 },
20+
{ PullRequestReviewState.Pending, 2 },
21+
};
22+
23+
/// <inheritdoc/>
24+
public long Id { get; set; }
25+
26+
/// <inheritdoc/>
27+
public IAccount User { get; set; }
28+
29+
/// <inheritdoc/>
30+
public PullRequestReviewState State { get; set; }
31+
32+
/// <inheritdoc/>
33+
public string StateDisplay => ToString(State);
34+
35+
/// <inheritdoc/>
36+
public int FileCommentCount { get; set; }
37+
38+
/// <summary>
39+
/// Builds a collection of <see cref="PullRequestReviewSummaryViewModel"/>s by user.
40+
/// </summary>
41+
/// <param name="pullRequest">The pull request model.</param>
42+
/// <remarks>
43+
/// This method builds a list similar to that found in the "Reviewers" section at the top-
44+
/// right of the Pull Request page on GitHub.
45+
/// </remarks>
46+
public static IEnumerable<PullRequestReviewSummaryViewModel> BuildByUser(IPullRequestModel pullRequest)
47+
{
48+
var existing = new Dictionary<string, PullRequestReviewSummaryViewModel>();
49+
50+
foreach (var review in pullRequest.Reviews.OrderBy(x => x.Id))
51+
{
52+
PullRequestReviewSummaryViewModel previous;
53+
existing.TryGetValue(review.User.Login, out previous);
54+
55+
var previousPriority = ToPriority(previous);
56+
var reviewPriority = ToPriority(review.State);
57+
58+
if (reviewPriority >= previousPriority)
59+
{
60+
var count = pullRequest.ReviewComments
61+
.Where(x => x.PullRequestReviewId == review.Id)
62+
.Count();
63+
existing[review.User.Login] = new PullRequestReviewSummaryViewModel
64+
{
65+
Id = review.Id,
66+
User = review.User,
67+
State = review.State,
68+
FileCommentCount = count
69+
};
70+
}
71+
}
72+
73+
var result = existing.Values.OrderBy(x => x.User).AsEnumerable();
74+
75+
if (!result.Any(x => x.State == PullRequestReviewState.Pending))
76+
{
77+
var newReview = new PullRequestReviewSummaryViewModel
78+
{
79+
State = PullRequestReviewState.Pending,
80+
};
81+
result = result.Concat(new[] { newReview });
82+
}
83+
84+
return result;
85+
}
86+
87+
static int ToPriority(PullRequestReviewSummaryViewModel review)
88+
{
89+
return review != null ? ToPriority(review.State) : 0;
90+
}
91+
92+
static int ToPriority(PullRequestReviewState state)
93+
{
94+
switch (state)
95+
{
96+
case PullRequestReviewState.Approved:
97+
case PullRequestReviewState.ChangesRequested:
98+
return 1;
99+
case PullRequestReviewState.Pending:
100+
return 2;
101+
default:
102+
return 0;
103+
}
104+
}
105+
106+
static string ToString(PullRequestReviewState state)
107+
{
108+
switch (state)
109+
{
110+
case PullRequestReviewState.Approved:
111+
return Resources.Approved;
112+
case PullRequestReviewState.ChangesRequested:
113+
return Resources.ChangesRequested;
114+
case PullRequestReviewState.Commented:
115+
case PullRequestReviewState.Dismissed:
116+
return Resources.Commented;
117+
case PullRequestReviewState.Pending:
118+
return Resources.InProgress;
119+
default:
120+
throw new NotSupportedException();
121+
}
122+
}
123+
}
124+
}

src/GitHub.Exports.Reactive/GitHub.Exports.Reactive.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@
197197
<Compile Include="ViewModels\GitHubPane\IPanePageViewModel.cs" />
198198
<Compile Include="ViewModels\GitHubPane\IPullRequestFilesViewModel.cs" />
199199
<Compile Include="ViewModels\GitHubPane\IPullRequestListViewModel.cs" />
200+
<Compile Include="ViewModels\GitHubPane\IPullRequestReviewSummaryViewModel.cs" />
200201
<Compile Include="ViewModels\GitHubPane\ISearchablePageViewModel.cs" />
201202
<Compile Include="ViewModels\GitHubPane\IPullRequestCreationViewModel.cs" />
202203
<Compile Include="ViewModels\GitHubPane\IPullRequestDetailViewModel.cs" />

src/GitHub.Exports.Reactive/ViewModels/GitHubPane/IPullRequestDetailViewModel.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ public interface IPullRequestDetailViewModel : IPanePageViewModel, IOpenInBrowse
125125
/// </summary>
126126
string Body { get; }
127127

128+
/// <summary>
129+
/// Gets the latest pull request review for each user.
130+
/// </summary>
131+
IReadOnlyList<IPullRequestReviewSummaryViewModel> Reviews { get; }
132+
128133
/// <summary>
129134
/// Gets the pull request's changed files.
130135
/// </summary>
@@ -165,6 +170,11 @@ public interface IPullRequestDetailViewModel : IPanePageViewModel, IOpenInBrowse
165170
/// </summary>
166171
ReactiveCommand<object> OpenOnGitHub { get; }
167172

173+
/// <summary>
174+
/// Gets a command that navigates to a pull request review.
175+
/// </summary>
176+
ReactiveCommand<object> ShowReview { get; }
177+
168178
/// <summary>
169179
/// Initializes the view model.
170180
/// </summary>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using GitHub.Models;
2+
3+
namespace GitHub.ViewModels.GitHubPane
4+
{
5+
/// <summary>
6+
/// Displays a short overview of a pull request review in the <see cref="IPullRequestDetailViewModel"/>.
7+
/// </summary>
8+
public interface IPullRequestReviewSummaryViewModel
9+
{
10+
/// <summary>
11+
/// Gets the ID of the pull request review.
12+
/// </summary>
13+
long Id { get; set; }
14+
15+
/// <summary>
16+
/// Gets the user who submitted the review.
17+
/// </summary>
18+
IAccount User { get; set; }
19+
20+
/// <summary>
21+
/// Gets the state of the review.
22+
/// </summary>
23+
PullRequestReviewState State { get; set; }
24+
25+
/// <summary>
26+
/// Gets a string representing the state of the review.
27+
/// </summary>
28+
string StateDisplay { get; }
29+
30+
/// <summary>
31+
/// Gets the number of file comments in the review.
32+
/// </summary>
33+
int FileCommentCount { get; set; }
34+
}
35+
}

0 commit comments

Comments
 (0)