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

Commit d5ac99a

Browse files
committed
Display user reviews.
When the user clicks on a "Reviewer" item in the PR details view, navigate to a new view to show the PR reviews by that user.
1 parent 8d8b7c7 commit d5ac99a

21 files changed

+1016
-1
lines changed

src/GitHub.App/GitHub.App.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@
212212
<Compile Include="Models\PullRequestDetailArgument.cs" />
213213
<Compile Include="Models\PullRequestReviewModel.cs" />
214214
<Compile Include="SampleData\PullRequestFilesViewModelDesigner.cs" />
215+
<Compile Include="SampleData\PullRequestReviewFileCommentViewModelDesigner.cs" />
216+
<Compile Include="SampleData\PullRequestReviewViewModelDesigner.cs" />
217+
<Compile Include="SampleData\PullRequestUserReviewsViewModelDesigner.cs" />
215218
<Compile Include="Services\EnterpriseCapabilitiesService.cs" />
216219
<Compile Include="Services\GlobalConnection.cs" />
217220
<Compile Include="Services\PullRequestEditorService.cs" />
@@ -240,7 +243,10 @@
240243
<Compile Include="ViewModels\GitHubPane\PullRequestCreationViewModel.cs" />
241244
<Compile Include="ViewModels\GitHubPane\NotAGitHubRepositoryViewModel.cs" />
242245
<Compile Include="ViewModels\GitHubPane\NotAGitRepositoryViewModel.cs" />
246+
<Compile Include="ViewModels\GitHubPane\PullRequestReviewFileCommentViewModel.cs" />
243247
<Compile Include="ViewModels\GitHubPane\PullRequestReviewSummaryViewModel.cs" />
248+
<Compile Include="ViewModels\GitHubPane\PullRequestReviewViewModel.cs" />
249+
<Compile Include="ViewModels\GitHubPane\PullRequestUserReviewsViewModel.cs" />
244250
<Compile Include="ViewModels\RepositoryFormViewModel.cs" />
245251
<Compile Include="ViewModels\TeamExplorer\RepositoryPublishViewModel.cs" />
246252
<Compile Include="Caches\CacheIndex.cs" />

src/GitHub.App/Models/PullRequestReviewModel.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ public class PullRequestReviewModel : IPullRequestReviewModel
1010
public string Body { get; set; }
1111
public PullRequestReviewState State { get; set; }
1212
public string CommitId { get; set; }
13+
public DateTimeOffset? SubmittedAt { get; set; }
1314
}
1415
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.Reactive;
2+
using GitHub.ViewModels.GitHubPane;
3+
using ReactiveUI;
4+
5+
namespace GitHub.SampleData
6+
{
7+
public class PullRequestReviewFileCommentViewModelDesigner : IPullRequestReviewFileCommentViewModel
8+
{
9+
public string Body { get; set; }
10+
public string RelativePath { get; set; }
11+
public ReactiveCommand<Unit> Open { get; }
12+
}
13+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading.Tasks;
4+
using GitHub.Models;
5+
using GitHub.ViewModels.GitHubPane;
6+
using ReactiveUI;
7+
8+
namespace GitHub.SampleData
9+
{
10+
public class PullRequestReviewViewModelDesigner : PanePageViewModelBase, IPullRequestReviewViewModel
11+
{
12+
public PullRequestReviewViewModelDesigner()
13+
{
14+
PullRequestModel = new PullRequestModel(
15+
419,
16+
"Fix a ton of potential crashers, odd code and redundant calls in ModelService",
17+
new AccountDesigner { Login = "Haacked", IsUser = true },
18+
DateTimeOffset.Now - TimeSpan.FromDays(2));
19+
20+
Model = new PullRequestReviewModel
21+
{
22+
23+
SubmittedAt = DateTimeOffset.Now - TimeSpan.FromDays(1),
24+
User = new AccountDesigner { Login = "Haacked", IsUser = true },
25+
};
26+
27+
Body = @"Just a few comments. I don't feel too strongly about them though.
28+
29+
Otherwise, very nice work here! ✨";
30+
31+
StateDisplay = "approved";
32+
33+
FileComments = new[]
34+
{
35+
new PullRequestReviewFileCommentViewModelDesigner
36+
{
37+
Body = @"These should probably be properties. Most likely they should be readonly properties. I know that makes creating instances of these not look as nice as using property initializers when constructing an instance, but if these properties should never be mutated after construction, then it guides future consumers to the right behavior.
38+
39+
However, if you're two-way binding these properties to a UI, then ignore the readonly part and make them properties. But in that case they should probably be reactive properties (or implement INPC).",
40+
RelativePath = "src/GitHub.Exports.Reactive/ViewModels/IPullRequestListViewModel.cs",
41+
},
42+
new PullRequestReviewFileCommentViewModelDesigner
43+
{
44+
Body = "While I have no problems with naming a variable ass I think we should probably avoid swear words in case Microsoft runs their Policheck tool against this code.",
45+
RelativePath = "src/GitHub.App/ViewModels/PullRequestListViewModel.cs",
46+
},
47+
};
48+
49+
OutdatedFileComments = new[]
50+
{
51+
new PullRequestReviewFileCommentViewModelDesigner
52+
{
53+
Body = @"So this is just casting a mutable list to an IReadOnlyList which can be cast back to List. I know we probably won't do that, but I'm thinking of the next person to come along. The safe thing to do is to wrap List with a ReadOnlyList. We have an extension method ToReadOnlyList for observables. Wouldn't be hard to write one for IEnumerable.",
54+
RelativePath = "src/GitHub.Exports.Reactive/ViewModels/IPullRequestListViewModel.cs",
55+
},
56+
};
57+
}
58+
59+
public string Body { get; }
60+
public IReadOnlyList<IPullRequestReviewFileCommentViewModel> FileComments { get; set; }
61+
public bool IsExpanded { get; set; }
62+
public bool HasDetails { get; set; }
63+
public ILocalRepositoryModel LocalRepository { get; set; }
64+
public IPullRequestReviewModel Model { get; set; }
65+
public ReactiveCommand<object> NavigateToPullRequest { get; }
66+
public IReadOnlyList<IPullRequestReviewFileCommentViewModel> OutdatedFileComments { get; set; }
67+
public IPullRequestModel PullRequestModel { get; set; }
68+
public string RemoteRepositoryOwner { get; set; }
69+
public string StateDisplay { get; set; }
70+
71+
public Task InitializeAsync(
72+
ILocalRepositoryModel localRepository,
73+
string owner,
74+
IPullRequestModel pullRequest,
75+
long pullRequestReviewId)
76+
{
77+
throw new NotImplementedException();
78+
}
79+
80+
public Task Load(IPullRequestModel pullRequest)
81+
{
82+
throw new NotImplementedException();
83+
}
84+
}
85+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading.Tasks;
4+
using GitHub.Models;
5+
using GitHub.ViewModels.GitHubPane;
6+
using ReactiveUI;
7+
8+
namespace GitHub.SampleData
9+
{
10+
public class PullRequestUserReviewsViewModelDesigner : PanePageViewModelBase, IPullRequestUserReviewsViewModel
11+
{
12+
public PullRequestUserReviewsViewModelDesigner()
13+
{
14+
User = new AccountDesigner { Login = "Haacked", IsUser = true };
15+
PullRequestNumber = 123;
16+
PullRequestTitle = "Error handling/bubbling from viewmodels to views to viewhosts";
17+
Reviews = new[]
18+
{
19+
new PullRequestReviewViewModelDesigner()
20+
{
21+
IsExpanded = true,
22+
HasDetails = true,
23+
FileComments = new PullRequestReviewFileCommentViewModel[0],
24+
StateDisplay = "approved",
25+
Model = new PullRequestReviewModel
26+
{
27+
State = PullRequestReviewState.Approved,
28+
SubmittedAt = DateTimeOffset.Now - TimeSpan.FromDays(1),
29+
User = User,
30+
},
31+
},
32+
new PullRequestReviewViewModelDesigner()
33+
{
34+
IsExpanded = true,
35+
HasDetails = true,
36+
StateDisplay = "requested changes",
37+
Model = new PullRequestReviewModel
38+
{
39+
State = PullRequestReviewState.ChangesRequested,
40+
SubmittedAt = DateTimeOffset.Now - TimeSpan.FromDays(2),
41+
User = User,
42+
},
43+
},
44+
new PullRequestReviewViewModelDesigner()
45+
{
46+
IsExpanded = false,
47+
HasDetails = false,
48+
StateDisplay = "commented",
49+
Model = new PullRequestReviewModel
50+
{
51+
State = PullRequestReviewState.Commented,
52+
SubmittedAt = DateTimeOffset.Now - TimeSpan.FromDays(2),
53+
User = User,
54+
},
55+
}
56+
};
57+
}
58+
59+
public ILocalRepositoryModel LocalRepository { get; set; }
60+
public string RemoteRepositoryOwner { get; set; }
61+
public int PullRequestNumber { get; set; }
62+
public IAccount User { get; set; }
63+
public IReadOnlyList<IPullRequestReviewViewModel> Reviews { get; set; }
64+
public string PullRequestTitle { get; set; }
65+
public ReactiveCommand<object> NavigateToPullRequest { get; }
66+
67+
public Task InitializeAsync(ILocalRepositoryModel localRepository, IConnection connection, string owner, string repo, int pullRequestNumber, string login)
68+
{
69+
return Task.CompletedTask;
70+
}
71+
72+
public Task Load(IAccount user, IPullRequestModel pullRequest)
73+
{
74+
return Task.CompletedTask;
75+
}
76+
}
77+
}

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public sealed class GitHubPaneViewModel : ViewModelBase, IGitHubPaneViewModel, I
3333
{
3434
static readonly ILogger log = LogManager.ForContext<GitHubPaneViewModel>();
3535
static readonly Regex pullUri = CreateRoute("/:owner/:repo/pull/:number");
36+
static readonly Regex pullUserReviewsUri = CreateRoute("/:owner/:repo/pull/:number/reviews/:login");
3637

3738
readonly IViewViewModelFactory viewModelFactory;
3839
readonly ISimpleApiClientFactory apiClientFactory;
@@ -243,6 +244,14 @@ public async Task NavigateTo(Uri uri)
243244
var number = int.Parse(match.Groups["number"].Value);
244245
await ShowPullRequest(owner, repo, number);
245246
}
247+
else if ((match = pullUserReviewsUri.Match(uri.AbsolutePath))?.Success == true)
248+
{
249+
var owner = match.Groups["owner"].Value;
250+
var repo = match.Groups["repo"].Value;
251+
var number = int.Parse(match.Groups["number"].Value);
252+
var login = match.Groups["login"].Value;
253+
await ShowPullRequestReviews(owner, repo, number, login);
254+
}
246255
else
247256
{
248257
throw new NotSupportedException("Unrecognised GitHub pane URL: " + uri.AbsolutePath);
@@ -282,6 +291,20 @@ public Task ShowPullRequest(string owner, string repo, int number)
282291
x => x.RemoteRepositoryOwner == owner && x.LocalRepository.Name == repo && x.Number == number);
283292
}
284293

294+
/// <inheritdoc/>
295+
public Task ShowPullRequestReviews(string owner, string repo, int number, string login)
296+
{
297+
Guard.ArgumentNotNull(owner, nameof(owner));
298+
Guard.ArgumentNotNull(repo, nameof(repo));
299+
300+
return NavigateTo<IPullRequestUserReviewsViewModel>(
301+
x => x.InitializeAsync(LocalRepository, Connection, owner, repo, number, login),
302+
x => x.RemoteRepositoryOwner == owner &&
303+
x.LocalRepository.Name == repo &&
304+
x.PullRequestNumber == number &&
305+
x.User.Login == login);
306+
}
307+
285308
async Task CreateInitializeTask(IServiceProvider paneServiceProvider)
286309
{
287310
await UpdateContent(teamExplorerContext.ActiveRepository);

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using LibGit2Sharp;
1919
using ReactiveUI;
2020
using Serilog;
21+
using static System.FormattableString;
2122

2223
namespace GitHub.ViewModels.GitHubPane
2324
{
@@ -636,7 +637,16 @@ async Task DoSyncSubmodules(object unused)
636637

637638
void DoShowReview(object item)
638639
{
639-
// TODO
640+
var review = (PullRequestReviewSummaryViewModel)item;
641+
642+
if (review.State == PullRequestReviewState.Pending)
643+
{
644+
throw new NotImplementedException();
645+
}
646+
else
647+
{
648+
NavigateTo(Invariant($"{RemoteRepositoryOwner}/{LocalRepository.Name}/pull/{Number}/reviews/{review.User.Login}"));
649+
}
640650
}
641651

642652
class CheckoutCommandState : IPullRequestCheckoutState
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Reactive;
3+
using GitHub.Extensions;
4+
using GitHub.Models;
5+
using GitHub.Services;
6+
using ReactiveUI;
7+
8+
namespace GitHub.ViewModels.GitHubPane
9+
{
10+
/// <summary>
11+
/// A view model for a file comment in a <see cref="PullRequestReviewViewModel"/>.
12+
/// </summary>
13+
public class PullRequestReviewFileCommentViewModel : IPullRequestReviewFileCommentViewModel
14+
{
15+
readonly IPullRequestEditorService editorService;
16+
readonly IPullRequestSession session;
17+
readonly IPullRequestReviewCommentModel model;
18+
19+
public PullRequestReviewFileCommentViewModel(
20+
IPullRequestEditorService editorService,
21+
IPullRequestSession session,
22+
IPullRequestReviewCommentModel model)
23+
{
24+
Guard.ArgumentNotNull(editorService, nameof(editorService));
25+
Guard.ArgumentNotNull(session, nameof(session));
26+
Guard.ArgumentNotNull(model, nameof(model));
27+
28+
this.editorService = editorService;
29+
this.session = session;
30+
this.model = model;
31+
}
32+
33+
/// <inheritdoc/>
34+
public string Body => model.Body;
35+
36+
/// <inheritdoc/>
37+
public string RelativePath => model.Path;
38+
39+
/// <inheritdoc/>
40+
public ReactiveCommand<Unit> Open { get; }
41+
}
42+
}

0 commit comments

Comments
 (0)