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

Commit abeb1b8

Browse files
committed
Display an "Add comment" box at the bottom of a PR.
1 parent f976412 commit abeb1b8

File tree

13 files changed

+280
-130
lines changed

13 files changed

+280
-130
lines changed

src/GitHub.App/SampleData/CommentViewModelDesigner.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ public CommentViewModelDesigner()
2424
public CommentEditState EditState { get; set; }
2525
public bool IsReadOnly { get; set; }
2626
public bool IsSubmitting { get; set; }
27+
public bool CanCancel { get; } = true;
2728
public bool CanDelete { get; } = true;
29+
public string CommitCaption { get; set; } = "Comment";
2830
public ICommentThreadViewModel Thread { get; }
2931
public DateTimeOffset CreatedAt => DateTime.Now.Subtract(TimeSpan.FromDays(3));
3032
public IActorViewModel Author { get; set; }

src/GitHub.App/ViewModels/CommentViewModel.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ public class CommentViewModel : ReactiveObject, ICommentViewModel
2222
{
2323
static readonly ILogger log = LogManager.ForContext<CommentViewModel>();
2424
readonly ICommentService commentService;
25+
readonly ObservableAsPropertyHelper<bool> canCancel;
2526
readonly ObservableAsPropertyHelper<bool> canDelete;
27+
ObservableAsPropertyHelper<string> commitCaption;
2628
string id;
2729
IActorViewModel author;
2830
IActorViewModel currentUser;
@@ -74,6 +76,9 @@ public CommentViewModel(ICommentService commentService)
7476
(ro, body) => !ro && !string.IsNullOrWhiteSpace(body)));
7577
AddErrorHandler(CommitEdit);
7678

79+
canCancel = this.WhenAnyValue(x => x.Id)
80+
.Select(id => id != null)
81+
.ToProperty(this, x => x.CanCancel);
7782
CancelEdit = ReactiveCommand.Create(DoCancelEdit, CommitEdit.IsExecuting.Select(x => !x));
7883
AddErrorHandler(CancelEdit);
7984

@@ -144,6 +149,9 @@ public bool IsSubmitting
144149
protected set => this.RaiseAndSetIfChanged(ref isSubmitting, value);
145150
}
146151

152+
/// <inheritdoc/>
153+
public bool CanCancel => canCancel.Value;
154+
147155
/// <inheritdoc/>
148156
public bool CanDelete => canDelete.Value;
149157

@@ -154,6 +162,9 @@ public DateTimeOffset CreatedAt
154162
private set => this.RaiseAndSetIfChanged(ref createdAt, value);
155163
}
156164

165+
/// <inheritdoc/>
166+
public string CommitCaption => commitCaption.Value;
167+
157168
/// <inheritdoc/>
158169
public ICommentThreadViewModel Thread
159170
{
@@ -200,6 +211,8 @@ public Task InitializeAsync(
200211
CreatedAt = comment?.CreatedAt ?? DateTimeOffset.MinValue;
201212
WebUrl = comment?.Url != null ? new Uri(comment.Url) : null;
202213

214+
commitCaption = GetCommitCaptionObservable().ToProperty(this, x => x.CommitCaption);
215+
203216
return Task.CompletedTask;
204217
}
205218

@@ -208,6 +221,12 @@ protected void AddErrorHandler(ReactiveCommand command)
208221
command.ThrownExceptions.Subscribe(x => ErrorMessage = x.Message);
209222
}
210223

224+
protected virtual IObservable<string> GetCommitCaptionObservable()
225+
{
226+
return this.WhenAnyValue(x => x.Id)
227+
.Select(x => x == null ? Resources.Comment : Resources.UpdateComment);
228+
}
229+
211230
async Task DoDelete()
212231
{
213232
if (commentService.ConfirmCommentDelete())
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.Reactive;
2+
using System.Threading.Tasks;
3+
using GitHub.Models;
4+
using ReactiveUI;
5+
6+
namespace GitHub.ViewModels.Documents
7+
{
8+
/// <summary>
9+
/// View model for comments on an issue or pull request.
10+
/// </summary>
11+
public interface IIssueishCommentViewModel : ICommentViewModel
12+
{
13+
/// <summary>
14+
/// Gets a value indicating whether the comment will show a
15+
/// a button for <see cref="CloseIssueish"/>.
16+
/// </summary>
17+
bool CanCloseIssueish { get; }
18+
19+
/// <summary>
20+
/// Gets a a caption for the <see cref="CloseIssueish"/> command.
21+
/// </summary>
22+
string CloseIssueishCaption { get; }
23+
24+
/// <summary>
25+
/// Gets a command which when executed will close the issue or pull request.
26+
/// </summary>
27+
ReactiveCommand<Unit, Unit> CloseIssueish { get; }
28+
29+
/// <summary>
30+
/// Initializes the view model with data.
31+
/// </summary>
32+
/// <param name="thread">The thread that the comment is a part of.</param>
33+
/// <param name="currentUser">The current user.</param>
34+
/// <param name="comment">The comment model. May be null.</param>
35+
/// <param name="closeCaption">
36+
/// The caption for the <see cref="CloseIssueish"/> command, or null if the user cannot
37+
/// close the issue/pr from this comment.
38+
/// </param>
39+
Task InitializeAsync(
40+
ICommentThreadViewModel thread,
41+
ActorModel currentUser,
42+
CommentModel comment,
43+
string closeCaption);
44+
}
45+
}

src/GitHub.App/ViewModels/Documents/IssueishCommentThreadViewModel.cs

Lines changed: 0 additions & 86 deletions
This file was deleted.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System;
2+
using System.ComponentModel.Composition;
3+
using System.Reactive;
4+
using System.Threading.Tasks;
5+
using GitHub.Models;
6+
using GitHub.Services;
7+
using ReactiveUI;
8+
9+
namespace GitHub.ViewModels.Documents
10+
{
11+
/// <summary>
12+
/// View model for comments on an issue or pull request.
13+
/// </summary>
14+
[Export(typeof(IIssueishCommentViewModel))]
15+
[PartCreationPolicy(CreationPolicy.NonShared)]
16+
public class IssueishCommentViewModel : CommentViewModel, IIssueishCommentViewModel
17+
{
18+
/// <summary>
19+
/// Initializes a new instance of the <see cref="CommentViewModel"/> class.
20+
/// </summary>
21+
/// <param name="commentService">The comment service.</param>
22+
[ImportingConstructor]
23+
public IssueishCommentViewModel(ICommentService commentService)
24+
: base(commentService)
25+
{
26+
}
27+
28+
/// <inheritdoc/>
29+
public bool CanCloseIssueish { get; private set; }
30+
31+
/// <inheritdoc/>
32+
public string CloseIssueishCaption { get; private set; }
33+
34+
/// <inheritdoc/>
35+
public ReactiveCommand<Unit, Unit> CloseIssueish { get; }
36+
37+
/// <inheritdoc/>
38+
public async Task InitializeAsync(
39+
ICommentThreadViewModel thread,
40+
ActorModel currentUser,
41+
CommentModel comment,
42+
string closeCaption)
43+
{
44+
await base.InitializeAsync(
45+
thread,
46+
currentUser,
47+
comment,
48+
comment == null ? CommentEditState.Editing : CommentEditState.None)
49+
.ConfigureAwait(true);
50+
51+
CanCloseIssueish = closeCaption != null;
52+
CloseIssueishCaption = closeCaption;
53+
}
54+
}
55+
}

src/GitHub.App/ViewModels/Documents/PullRequestPageViewModel.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ public async Task InitializeAsync(
8989
break;
9090
case CommentModel comment:
9191
{
92-
var vm = factory.CreateViewModel<ICommentViewModel>();
93-
await vm.InitializeAsync(this, currentUser, comment, CommentEditState.None).ConfigureAwait(true);
92+
var vm = factory.CreateViewModel<IIssueishCommentViewModel>();
93+
await vm.InitializeAsync(this, currentUser, comment, null).ConfigureAwait(true);
9494
timeline.Add(vm);
9595
}
9696
break;
@@ -102,6 +102,14 @@ public async Task InitializeAsync(
102102
timeline.Add(new CommitSummariesViewModel(commits));
103103
}
104104

105+
var placeholder = factory.CreateViewModel<IIssueishCommentViewModel>();
106+
await placeholder.InitializeAsync(
107+
this,
108+
currentUser,
109+
null,
110+
Resources.ClosePullRequest).ConfigureAwait(true);
111+
timeline.Add(placeholder);
112+
105113
Timeline = timeline;
106114
}
107115

src/GitHub.App/ViewModels/PullRequestReviewCommentViewModel.cs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ namespace GitHub.ViewModels
1919
public class PullRequestReviewCommentViewModel : CommentViewModel, IPullRequestReviewCommentViewModel
2020
{
2121
readonly ObservableAsPropertyHelper<bool> canStartReview;
22-
readonly ObservableAsPropertyHelper<string> commitCaption;
2322
IPullRequestSession session;
2423
bool isPending;
2524

@@ -31,19 +30,12 @@ public class PullRequestReviewCommentViewModel : CommentViewModel, IPullRequestR
3130
public PullRequestReviewCommentViewModel(ICommentService commentService)
3231
: base(commentService)
3332
{
34-
var pendingAndIsNew = this.WhenAnyValue(
33+
canStartReview = this.WhenAnyValue(
3534
x => x.IsPending,
3635
x => x.Id,
37-
(isPending, id) => (isPending, isNewComment: id == null));
38-
39-
canStartReview = pendingAndIsNew
40-
.Select(arg => !arg.isPending && arg.isNewComment)
36+
(isPending, id) => !isPending && id == null)
4137
.ToProperty(this, x => x.CanStartReview);
4238

43-
commitCaption = pendingAndIsNew
44-
.Select(arg => !arg.isNewComment ? Resources.UpdateComment : arg.isPending ? Resources.AddReviewComment : Resources.AddSingleComment)
45-
.ToProperty(this, x => x.CommitCaption);
46-
4739
StartReview = ReactiveCommand.CreateFromTask(DoStartReview, CommitEdit.CanExecute);
4840
AddErrorHandler(StartReview);
4941
}
@@ -82,9 +74,6 @@ await InitializeAsync(
8274
/// <inheritdoc/>
8375
public bool CanStartReview => canStartReview.Value;
8476

85-
/// <inheritdoc/>
86-
public string CommitCaption => commitCaption.Value;
87-
8877
/// <inheritdoc/>
8978
public bool IsPending
9079
{
@@ -95,6 +84,16 @@ public bool IsPending
9584
/// <inheritdoc/>
9685
public ReactiveCommand<Unit, Unit> StartReview { get; }
9786

87+
protected override IObservable<string> GetCommitCaptionObservable()
88+
{
89+
return this.WhenAnyValue(
90+
x => x.IsPending,
91+
x => x.Id,
92+
(pending, id) => id != null ?
93+
Resources.UpdateComment :
94+
pending ? Resources.AddReviewComment : Resources.AddSingleComment);
95+
}
96+
9897
async Task DoStartReview()
9998
{
10099
IsSubmitting = true;

0 commit comments

Comments
 (0)