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

Commit d3559c6

Browse files
committed
Merge branch 'master' into feature/inline-reviews-tooltip
2 parents 2775886 + d9116de commit d3559c6

22 files changed

+310
-108
lines changed

src/GitHub.App/SampleData/PullRequestDetailViewModelDesigner.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public PullRequestDetailViewModelDesigner()
8686
public IPullRequestCheckoutState CheckoutState { get; set; }
8787
public IPullRequestUpdateState UpdateState { get; set; }
8888
public string OperationError { get; set; }
89+
public string ErrorMessage { get; set; }
8990

9091
public ReactiveCommand<Unit> Checkout { get; }
9192
public ReactiveCommand<Unit> Pull { get; }

src/GitHub.App/ViewModels/PullRequestDetailViewModel.cs

Lines changed: 94 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public class PullRequestDetailViewModel : PanePageViewModelBase, IPullRequestDet
3939
IReadOnlyList<IPullRequestChangeNode> changedFilesTree;
4040
IPullRequestCheckoutState checkoutState;
4141
IPullRequestUpdateState updateState;
42+
string errorMessage;
4243
string operationError;
4344
bool isBusy;
4445
bool isLoading;
@@ -236,6 +237,15 @@ public IPullRequestUpdateState UpdateState
236237
private set { this.RaiseAndSetIfChanged(ref updateState, value); }
237238
}
238239

240+
/// <summary>
241+
/// Gets an error message to display if loading fails.
242+
/// </summary>
243+
public string ErrorMessage
244+
{
245+
get { return errorMessage; }
246+
private set { this.RaiseAndSetIfChanged(ref errorMessage, value); }
247+
}
248+
239249
/// <summary>
240250
/// Gets the error message to be displayed in the action area as a result of an error in a
241251
/// git operation.
@@ -298,10 +308,16 @@ public override void Initialize([AllowNull] ViewWithData data)
298308
else
299309
IsBusy = true;
300310

301-
OperationError = null;
311+
ErrorMessage = OperationError = null;
302312
modelService.GetPullRequest(Repository, prNumber)
303313
.TakeLast(1)
304314
.ObserveOn(RxApp.MainThreadScheduler)
315+
.Catch<IPullRequestModel, Exception>(ex =>
316+
{
317+
ErrorMessage = ex.Message.Trim();
318+
IsLoading = IsBusy = false;
319+
return Observable.Empty<IPullRequestModel>();
320+
})
305321
.Subscribe(x => Load(x).Forget());
306322
}
307323

@@ -312,94 +328,103 @@ public override void Initialize([AllowNull] ViewWithData data)
312328
/// <param name="files">The pull request's changed files.</param>
313329
public async Task Load(IPullRequestModel pullRequest)
314330
{
315-
var firstLoad = (Model == null);
316-
Model = pullRequest;
317-
Session = await sessionManager.GetSession(pullRequest);
318-
Title = Resources.PullRequestNavigationItemText + " #" + pullRequest.Number;
319-
320-
IsFromFork = pullRequestsService.IsPullRequestFromFork(Repository, Model);
321-
SourceBranchDisplayName = GetBranchDisplayName(IsFromFork, pullRequest.Head?.Label);
322-
TargetBranchDisplayName = GetBranchDisplayName(IsFromFork, pullRequest.Base.Label);
323-
CommentCount = pullRequest.Comments.Count + pullRequest.ReviewComments.Count;
324-
Body = !string.IsNullOrWhiteSpace(pullRequest.Body) ? pullRequest.Body : Resources.NoDescriptionProvidedMarkdown;
331+
try
332+
{
333+
var firstLoad = (Model == null);
334+
Model = pullRequest;
335+
Session = await sessionManager.GetSession(pullRequest);
336+
Title = Resources.PullRequestNavigationItemText + " #" + pullRequest.Number;
325337

326-
var changes = await pullRequestsService.GetTreeChanges(Repository, pullRequest);
327-
ChangedFilesTree = (await CreateChangedFilesTree(pullRequest, changes)).Children.ToList();
338+
IsFromFork = pullRequestsService.IsPullRequestFromFork(Repository, Model);
339+
SourceBranchDisplayName = GetBranchDisplayName(IsFromFork, pullRequest.Head?.Label);
340+
TargetBranchDisplayName = GetBranchDisplayName(IsFromFork, pullRequest.Base.Label);
341+
CommentCount = pullRequest.Comments.Count + pullRequest.ReviewComments.Count;
342+
Body = !string.IsNullOrWhiteSpace(pullRequest.Body) ? pullRequest.Body : Resources.NoDescriptionProvidedMarkdown;
328343

329-
var localBranches = await pullRequestsService.GetLocalBranches(Repository, pullRequest).ToList();
344+
var changes = await pullRequestsService.GetTreeChanges(Repository, pullRequest);
345+
ChangedFilesTree = (await CreateChangedFilesTree(pullRequest, changes)).Children.ToList();
330346

331-
IsCheckedOut = localBranches.Contains(Repository.CurrentBranch);
347+
var localBranches = await pullRequestsService.GetLocalBranches(Repository, pullRequest).ToList();
332348

333-
if (IsCheckedOut)
334-
{
335-
var divergence = await pullRequestsService.CalculateHistoryDivergence(Repository, Model.Number);
336-
var pullEnabled = divergence.BehindBy > 0;
337-
var pushEnabled = divergence.AheadBy > 0 && !pullEnabled;
338-
string pullToolTip;
339-
string pushToolTip;
349+
IsCheckedOut = localBranches.Contains(Repository.CurrentBranch);
340350

341-
if (pullEnabled)
342-
{
343-
pullToolTip = string.Format(
344-
Resources.PullRequestDetailsPullToolTip,
345-
IsFromFork ? Resources.Fork : Resources.Remote,
346-
SourceBranchDisplayName);
347-
}
348-
else
351+
if (IsCheckedOut)
349352
{
350-
pullToolTip = Resources.NoCommitsToPull;
351-
}
353+
var divergence = await pullRequestsService.CalculateHistoryDivergence(Repository, Model.Number);
354+
var pullEnabled = divergence.BehindBy > 0;
355+
var pushEnabled = divergence.AheadBy > 0 && !pullEnabled;
356+
string pullToolTip;
357+
string pushToolTip;
352358

353-
if (pushEnabled)
354-
{
355-
pushToolTip = string.Format(
356-
Resources.PullRequestDetailsPushToolTip,
357-
IsFromFork ? Resources.Fork : Resources.Remote,
358-
SourceBranchDisplayName);
359-
}
360-
else if (divergence.AheadBy == 0)
361-
{
362-
pushToolTip = Resources.NoCommitsToPush;
359+
if (pullEnabled)
360+
{
361+
pullToolTip = string.Format(
362+
Resources.PullRequestDetailsPullToolTip,
363+
IsFromFork ? Resources.Fork : Resources.Remote,
364+
SourceBranchDisplayName);
365+
}
366+
else
367+
{
368+
pullToolTip = Resources.NoCommitsToPull;
369+
}
370+
371+
if (pushEnabled)
372+
{
373+
pushToolTip = string.Format(
374+
Resources.PullRequestDetailsPushToolTip,
375+
IsFromFork ? Resources.Fork : Resources.Remote,
376+
SourceBranchDisplayName);
377+
}
378+
else if (divergence.AheadBy == 0)
379+
{
380+
pushToolTip = Resources.NoCommitsToPush;
381+
}
382+
else
383+
{
384+
pushToolTip = Resources.MustPullBeforePush;
385+
}
386+
387+
UpdateState = new UpdateCommandState(divergence, pullEnabled, pushEnabled, pullToolTip, pushToolTip);
388+
CheckoutState = null;
363389
}
364390
else
365391
{
366-
pushToolTip = Resources.MustPullBeforePush;
367-
}
392+
var caption = localBranches.Count > 0 ?
393+
string.Format(Resources.PullRequestDetailsCheckout, localBranches.First().DisplayName) :
394+
string.Format(Resources.PullRequestDetailsCheckoutTo, await pullRequestsService.GetDefaultLocalBranchName(Repository, Model.Number, Model.Title));
395+
var clean = await pullRequestsService.IsWorkingDirectoryClean(Repository);
396+
string disabled = null;
368397

369-
UpdateState = new UpdateCommandState(divergence, pullEnabled, pushEnabled, pullToolTip, pushToolTip);
370-
CheckoutState = null;
371-
}
372-
else
373-
{
374-
var caption = localBranches.Count > 0 ?
375-
string.Format(Resources.PullRequestDetailsCheckout, localBranches.First().DisplayName) :
376-
string.Format(Resources.PullRequestDetailsCheckoutTo, await pullRequestsService.GetDefaultLocalBranchName(Repository, Model.Number, Model.Title));
377-
var clean = await pullRequestsService.IsWorkingDirectoryClean(Repository);
378-
string disabled = null;
398+
if (pullRequest.Head == null || !pullRequest.Head.RepositoryCloneUrl.IsValidUri)
399+
{
400+
disabled = Resources.SourceRepositoryNoLongerAvailable;
401+
}
402+
else if (!clean)
403+
{
404+
disabled = Resources.WorkingDirectoryHasUncommittedCHanges;
405+
}
379406

380-
if (pullRequest.Head == null || !pullRequest.Head.RepositoryCloneUrl.IsValidUri)
381-
{
382-
disabled = Resources.SourceRepositoryNoLongerAvailable;
407+
CheckoutState = new CheckoutCommandState(caption, disabled);
408+
UpdateState = null;
383409
}
384-
else if (!clean)
410+
411+
if (firstLoad)
385412
{
386-
disabled = Resources.WorkingDirectoryHasUncommittedCHanges;
413+
usageTracker.IncrementPullRequestOpened().Forget();
387414
}
388415

389-
CheckoutState = new CheckoutCommandState(caption, disabled);
390-
UpdateState = null;
416+
if (!isInCheckout)
417+
{
418+
pullRequestsService.RemoveUnusedRemotes(Repository).Subscribe(_ => { });
419+
}
391420
}
392-
393-
IsLoading = IsBusy = false;
394-
395-
if (firstLoad)
421+
catch (Exception ex)
396422
{
397-
usageTracker.IncrementPullRequestOpened().Forget();
423+
ErrorMessage = ex.Message.Trim();
398424
}
399-
400-
if (!isInCheckout)
425+
finally
401426
{
402-
pullRequestsService.RemoveUnusedRemotes(Repository).Subscribe(_ => { });
427+
IsLoading = IsBusy = false;
403428
}
404429
}
405430

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public interface IPullRequestUpdateState
6464
/// <summary>
6565
/// Represents a view model for displaying details of a pull request.
6666
/// </summary>
67-
public interface IPullRequestDetailViewModel : IViewModel, IHasLoading, IHasBusy
67+
public interface IPullRequestDetailViewModel : IViewModel, IHasLoading, IHasBusy, IHasErrorState
6868
{
6969
/// <summary>
7070
/// Gets the underlying pull request model.

src/GitHub.Exports/GitHub.Exports.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@
137137
<Compile Include="Models\ICommentModel.cs" />
138138
<Compile Include="Models\IInlineCommentModel.cs" />
139139
<Compile Include="Models\IPullRequestReviewCommentModel.cs" />
140+
<Compile Include="ViewModels\IHasErrorState.cs" />
140141
<Compile Include="ViewModels\IHasLoading.cs" />
141142
<Compile Include="ViewModels\IPanePageViewModel.cs" />
142143
<Compile Include="ViewModels\IViewModel.cs" />
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace GitHub.ViewModels
4+
{
5+
/// <summary>
6+
/// Interface for view models that have an error state.
7+
/// </summary>
8+
public interface IHasErrorState
9+
{
10+
/// <summary>
11+
/// Gets the view model's error message or null if the view model is not in an error state.
12+
/// </summary>
13+
string ErrorMessage { get; }
14+
}
15+
}

src/GitHub.InlineReviews/SampleData/CommentThreadViewModelDesigner.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,10 @@ class CommentThreadViewModelDesigner : ICommentThreadViewModel
1616
= new AccountDesigner { Login = "shana", IsUser = true };
1717

1818
public ReactiveCommand<ICommentModel> PostComment { get; }
19+
20+
public Uri GetCommentUrl(int id)
21+
{
22+
throw new NotImplementedException();
23+
}
1924
}
2025
}

src/GitHub.InlineReviews/SampleData/CommentViewModelDesigner.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,33 @@
44
using GitHub.InlineReviews.ViewModels;
55
using GitHub.Models;
66
using GitHub.SampleData;
7-
using GitHub.ViewModels;
7+
using GitHub.UI;
88

99
namespace GitHub.InlineReviews.SampleData
1010
{
11-
class CommentViewModelDesigner : ViewModelBase, ICommentViewModel
11+
class CommentViewModelDesigner : ReactiveObject, ICommentViewModel
1212
{
1313
public CommentViewModelDesigner()
1414
{
1515
User = new AccountDesigner { Login = "shana", IsUser = true };
1616
}
1717

18+
public void Initialize(ViewWithData data)
19+
{
20+
}
21+
1822
public int Id { get; set; }
1923
public string Body { get; set; }
2024
public string ErrorMessage { get; set; }
2125
public CommentEditState EditState { get; set; }
2226
public bool IsReadOnly { get; set; }
27+
public ICommentThreadViewModel Thread { get; }
2328
public DateTimeOffset UpdatedAt => DateTime.Now.Subtract(TimeSpan.FromDays(3));
2429
public IAccount User { get; set; }
2530

2631
public ReactiveCommand<object> BeginEdit { get; }
2732
public ReactiveCommand<object> CancelEdit { get; }
2833
public ReactiveCommand<Unit> CommitEdit { get; }
34+
public ReactiveCommand<object> OpenOnGitHub { get; }
2935
}
3036
}

src/GitHub.InlineReviews/ViewModels/CommentThreadViewModel.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ public void Dispose()
5252
GC.SuppressFinalize(this);
5353
}
5454

55+
/// <inheritdoc/>
56+
public abstract Uri GetCommentUrl(int id);
57+
5558
protected virtual void Dispose(bool disposing)
5659
{
5760
if (disposing)

src/GitHub.InlineReviews/ViewModels/CommentViewModel.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Threading.Tasks;
66
using GitHub.Extensions;
77
using GitHub.Models;
8+
using GitHub.UI;
89
using ReactiveUI;
910

1011
namespace GitHub.InlineReviews.ViewModels
@@ -72,6 +73,8 @@ public CommentViewModel(
7273
CancelEdit = ReactiveCommand.Create(CommitEdit.IsExecuting.Select(x => !x));
7374
CancelEdit.Subscribe(DoCancelEdit);
7475
AddErrorHandler(CancelEdit);
76+
77+
OpenOnGitHub = ReactiveCommand.Create(this.WhenAnyValue(x => x.Id, x => x != 0));
7578
}
7679

7780
/// <summary>
@@ -88,6 +91,11 @@ public CommentViewModel(
8891
{
8992
}
9093

94+
public void Initialize(ViewWithData data)
95+
{
96+
// Nothing to do here: initialized in constructor.
97+
}
98+
9199
/// <summary>
92100
/// Creates a placeholder comment which can be used to add a new comment to a thread.
93101
/// </summary>
@@ -207,5 +215,8 @@ public DateTimeOffset UpdatedAt
207215

208216
/// <inheritdoc/>
209217
public ReactiveCommand<Unit> CommitEdit { get; }
218+
219+
/// <inheritdoc/>
220+
public ReactiveCommand<object> OpenOnGitHub { get; }
210221
}
211222
}

src/GitHub.InlineReviews/ViewModels/ICommentThreadViewModel.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ namespace GitHub.InlineReviews.ViewModels
1010
/// </summary>
1111
public interface ICommentThreadViewModel
1212
{
13+
/// <summary>
14+
/// Gets the browser URI for a comment in the thread.
15+
/// </summary>
16+
/// <param name="id">The ID of the comment.</param>
17+
/// <returns>The URI.</returns>
18+
Uri GetCommentUrl(int id);
19+
1320
/// <summary>
1421
/// Gets the comments in the thread.
1522
/// </summary>

0 commit comments

Comments
 (0)