Skip to content

Commit

Permalink
Add comment replies to news feed (#623)
Browse files Browse the repository at this point in the history
  • Loading branch information
frankdekker committed Feb 12, 2024
1 parent 7849958 commit ae2930a
Show file tree
Hide file tree
Showing 23 changed files with 195 additions and 70 deletions.
4 changes: 4 additions & 0 deletions assets/styles/comment.scss
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
.comment__reply {
max-width: calc(100vw - var(--review-sidebar-width) - var(--review-sidebar-gap) - 75px);
padding-left: 40px;

&.comment__reply--no-indent {
padding-left: 5px;
}
}

.diff-side-by-side .comment__reply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function __invoke(Request $request, #[MapEntity] Comment $comment): JsonR
$this->replyRepository->save($reply, true);

$this->bus->dispatch(
new CommentReplyAdded((int)$comment->getReview()->getId(), (int)$reply->getId(), $user->getId(), $message)
new CommentReplyAdded((int)$comment->getReview()->getId(), (int)$reply->getId(), $user->getId(), $message, $comment->getFilePath())
);

return $this->json(['success' => true]);
Expand Down
10 changes: 8 additions & 2 deletions src/Controller/App/Review/Comment/AddCommentReplyController.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function __invoke(Request $request, #[MapEntity] ?Comment $comment): Json
/** @var array{message: string} $data */
$data = $form->getData();

$user = $this->getUser();
$user = $this->getUser();
$reply = new CommentReply();
$reply->setUser($user);
$reply->setComment($comment);
Expand All @@ -56,7 +56,13 @@ public function __invoke(Request $request, #[MapEntity] ?Comment $comment): Json
$this->replyRepository->save($reply, true);

$this->bus->dispatch(
new CommentReplyAdded((int)$comment->getReview()->getId(), (int)$reply->getId(), $user->getId(), $data['message'])
new CommentReplyAdded(
(int)$comment->getReview()->getId(),
(int)$reply->getId(),
$user->getId(),
$data['message'],
$comment->getFilePath()
)
);

return $this->json(['success' => true, 'commentId' => $comment->getId()]);
Expand Down
8 changes: 6 additions & 2 deletions src/Entity/Review/Comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,11 @@ public function getFilePath(): string
return $this->filePath;
}

public function setFilePath(string $filePath): void
public function setFilePath(string $filePath): self
{
$this->filePath = $filePath;

return $this;
}

public function getLineReference(): LineReference
Expand Down Expand Up @@ -178,9 +180,11 @@ public function getReview(): CodeReview
return $this->review;
}

public function setReview(CodeReview $review): void
public function setReview(CodeReview $review): self
{
$this->review = $review;

return $this;
}

public function getUser(): User
Expand Down
5 changes: 3 additions & 2 deletions src/Message/Comment/CommentReplyAdded.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public function __construct(
public readonly int $reviewId,
public readonly int $commentReplyId,
public readonly int $byUserId,
public readonly string $message
public readonly string $message,
public readonly string $file
) {
}

Expand Down Expand Up @@ -43,6 +44,6 @@ public function getUserId(): int
*/
public function getPayload(): array
{
return ['commentId' => $this->commentReplyId, 'message' => $this->message];
return ['commentId' => $this->commentReplyId, 'message' => $this->message, 'file' => $this->file];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ private function addCustomParams(CodeReviewActivity $activity, array $params): a

// add message
if ($activity->getEventName() === CommentReplyAdded::NAME) {
$params[] = new Variable('message', (string)$activity->getDataValue('message'));
$params[] = new Variable('file', basename((string)$activity->getDataValue('file')));
}

return $params;
Expand Down
32 changes: 32 additions & 0 deletions src/Service/CodeReview/Comment/ActivityCommentProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);

namespace DR\Review\Service\CodeReview\Comment;

use DR\Review\Entity\Review\CodeReviewActivity;
use DR\Review\Entity\Review\Comment;
use DR\Review\Entity\Review\CommentReply;
use DR\Review\Message\Comment\CommentAdded;
use DR\Review\Message\Comment\CommentReplyAdded;
use DR\Review\Repository\Review\CommentReplyRepository;
use DR\Review\Repository\Review\CommentRepository;

class ActivityCommentProvider
{
public function __construct(private readonly CommentRepository $commentRepository, private readonly CommentReplyRepository $replyRepository)
{
}

public function getCommentFor(CodeReviewActivity $activity): Comment|CommentReply|null
{
if ($activity->getEventName() === CommentAdded::NAME) {
return $this->commentRepository->find((int)$activity->getDataValue('commentId'));
}

if ($activity->getEventName() === CommentReplyAdded::NAME) {
return $this->replyRepository->find((int)$activity->getDataValue('commentId'));
}

return null;
}
}
19 changes: 15 additions & 4 deletions src/ViewModel/App/Review/Timeline/TimelineEntryViewModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@

use DR\Review\Entity\Review\CodeReviewActivity;
use DR\Review\Entity\Review\Comment;
use DR\Review\Entity\Review\CommentReply;
use DR\Review\Entity\Revision\Revision;

class TimelineEntryViewModel
{
private ?Comment $comment = null;
private ?Revision $revision = null;
private ?Comment $comment = null;
private ?CommentReply $reply = null;
private ?Revision $revision = null;

/**
* @param non-empty-array<CodeReviewActivity> $activities
Expand All @@ -24,9 +26,18 @@ public function getComment(): ?Comment
return $this->comment;
}

public function setComment(?Comment $comment): self
public function getReply(): ?CommentReply
{
$this->comment = $comment;
return $this->reply;
}

public function setCommentOrReply(Comment|CommentReply|null $comment): self
{
if ($comment instanceof Comment) {
$this->comment = $comment;
} elseif ($comment instanceof CommentReply) {
$this->reply = $comment;
}

return $this;
}
Expand Down
2 changes: 2 additions & 0 deletions src/ViewModelProvider/ProjectsViewModelProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Doctrine\DBAL\Exception;
use DR\Review\Entity\User\User;
use DR\Review\Message\Comment\CommentAdded;
use DR\Review\Message\Comment\CommentReplyAdded;
use DR\Review\Message\Comment\CommentResolved;
use DR\Review\Message\Review\ReviewAccepted;
use DR\Review\Message\Review\ReviewOpened;
Expand All @@ -22,6 +23,7 @@ class ProjectsViewModelProvider
ReviewOpened::NAME,
CommentAdded::NAME,
CommentResolved::NAME,
CommentReplyAdded::NAME
];

public function __construct(
Expand Down
19 changes: 8 additions & 11 deletions src/ViewModelProvider/ReviewTimelineViewModelProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
use DR\Review\Message\Comment\CommentReplyAdded;
use DR\Review\Message\Revision\ReviewRevisionAdded;
use DR\Review\Repository\Review\CodeReviewActivityRepository;
use DR\Review\Repository\Review\CommentRepository;
use DR\Review\Service\CodeReview\Activity\CodeReviewActivityFormatter;
use DR\Review\Service\CodeReview\Activity\CodeReviewActivityUrlGenerator;
use DR\Review\Service\CodeReview\Comment\ActivityCommentProvider;
use DR\Review\ViewModel\App\Review\Timeline\TimelineEntryViewModel;
use DR\Review\ViewModel\App\Review\Timeline\TimelineViewModel;

Expand All @@ -22,7 +22,7 @@ class ReviewTimelineViewModelProvider
public function __construct(
private readonly CodeReviewActivityRepository $activityRepository,
private readonly CodeReviewActivityFormatter $activityFormatter,
private readonly CommentRepository $commentRepository,
private readonly ActivityCommentProvider $commentProvider,
private readonly CodeReviewActivityUrlGenerator $urlGenerator,
private readonly User $user
) {
Expand All @@ -45,7 +45,7 @@ public function getTimelineViewModel(CodeReview $review, array $revisions): Time

$timelineEntries[] = $entry = new TimelineEntryViewModel([$activity], $message, null);
if ($activity->getEventName() === CommentAdded::NAME) {
$entry->setComment($review->getComments()->get((int)$activity->getDataValue('commentId')));
$entry->setCommentOrReply($review->getComments()->get((int)$activity->getDataValue('commentId')));
} elseif ($activity->getEventName() === ReviewRevisionAdded::NAME) {
$entry->setRevision($revisions[(int)$activity->getDataValue('revisionId')] ?? null);
}
Expand All @@ -68,14 +68,11 @@ public function getTimelineViewModelForFeed(User $user, array $events, ?Reposito
if ($message === null) {
continue;
}
$comment = null;
if ($activity->getEventName() === CommentAdded::NAME) {
$comment = $this->commentRepository->find((int)$activity->getDataValue('commentId'));
if ($comment === null) {
continue;
}
}
$timelineEntries[] = (new TimelineEntryViewModel([$activity], $message, $this->urlGenerator->generate($activity)))->setComment($comment);

$url = $this->urlGenerator->generate($activity);
$entry = (new TimelineEntryViewModel([$activity], $message, $url));
$entry->setCommentOrReply($this->commentProvider->getCommentFor($activity));
$timelineEntries[] = $entry;
}

return new TimelineViewModel($timelineEntries);
Expand Down
2 changes: 2 additions & 0 deletions src/ViewModelProvider/ReviewsViewModelProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use DR\Review\Entity\Review\CodeReview;
use DR\Review\Entity\User\User;
use DR\Review\Message\Comment\CommentAdded;
use DR\Review\Message\Comment\CommentReplyAdded;
use DR\Review\Message\Comment\CommentResolved;
use DR\Review\Message\Review\ReviewAccepted;
use DR\Review\Message\Review\ReviewOpened;
Expand All @@ -25,6 +26,7 @@ class ReviewsViewModelProvider
ReviewOpened::NAME,
CommentAdded::NAME,
CommentResolved::NAME,
CommentReplyAdded::NAME
];

public function __construct(
Expand Down
6 changes: 6 additions & 0 deletions templates/app/project/projects.timeline.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
{% include 'app/review/comment/comment.html.twig' with {comment: entry.comment, detached: false, editCommentForm: null, replyCommentForm: null, visible: true} %}
{% endif %}

{% if entry.reply is not same as (null) %}
<div class="comment__comment-thread">
{% include 'app/review/comment/comment.reply.html.twig' with {reply: entry.reply, indented: false} %}
</div>
{% endif %}

<div class="text-secondary small clearfix">
<span class="pe-1 small">
{{ activity.review.repository.displayName ~ ':' }}
Expand Down
5 changes: 4 additions & 1 deletion templates/app/review/comment/comment.reply.html.twig
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<div class="comment__reply" data-reply-id="{{ reply.id }}">
{# reply: CommentReply #}
{# indented: bool|null #}

<div class="comment__reply {% if indented is defined and not indented %}comment__reply--no-indent{% endif %}" data-reply-id="{{ reply.id }}">
<div class="comment__author_and_time">
<span class="comment__author">{{ reply.user.name }}</span>
<span class="comment__datetime" title="{{ reply.updateTimestamp|format_datetime('full', 'full') }}">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function testInvoke(): void
$request->method('getContent')->willReturn('message');

$user = (new User())->setId(123);
$comment = new Comment();
$comment = (new Comment())->setFilePath('file');
$comment->setReview(new CodeReview());

$this->expectGetUser($user);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,10 @@ public function testInvokeFormNotSubmitted(): void
public function testInvokeFormSubmitted(): void
{
$request = new Request();
$review = new CodeReview();
$review->setId(123);
$comment = new Comment();
$comment->setId(456);
$comment->setReview($review);
$data = ['message' => 'my-comment'];
$user = (new User())->setId(789);
$review = (new CodeReview())->setId(123);
$comment = (new Comment())->setId(456)->setFilePath('file')->setReview($review);
$data = ['message' => 'my-comment'];
$user = (new User())->setId(789);
$this->expectGetUser($user);

$this->expectCreateForm(AddCommentReplyFormType::class, null, ['comment' => $comment])
Expand Down
8 changes: 4 additions & 4 deletions tests/Unit/Message/Comment/CommentReplyAddedTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ class CommentReplyAddedTest extends AbstractMessageEventTestCase
public function testAccessors(): void
{
static::assertCodeReviewEvent(
new CommentReplyAdded(5, 6, 7, 'message'),
new CommentReplyAdded(5, 6, 7, 'message', 'file'),
'comment-reply-added',
5,
['commentId' => 6, 'message' => 'message']
['commentId' => 6, 'message' => 'message', 'file' => 'file']
);
static::assertCommentReplyEvent(new CommentReplyAdded(5, 6, 7, 'message'), 6);
static::assertUserAware(new CommentReplyAdded(5, 6, 7, 'message'), 7);
static::assertCommentReplyEvent(new CommentReplyAdded(5, 6, 7, 'message', 'file'), 6);
static::assertUserAware(new CommentReplyAdded(5, 6, 7, 'message', 'file'), 7);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public function testInvokeSkipIfDisabled(): void
$this->apiProvider,
$this->commentService
);
($handler)(new CommentReplyAdded(111, 222, 333, 'message'));
($handler)(new CommentReplyAdded(111, 222, 333, 'message', 'file'));
}

/**
Expand All @@ -79,7 +79,7 @@ public function testInvokeNoApi(): void
$this->replyRepository->expects(self::once())->method('find')->with(222)->willReturn($reply);
$this->apiProvider->expects(self::once())->method('create')->with($repository, $user)->willReturn(null);

($this->handler)(new CommentReplyAdded(111, 222, 333, 'message'));
($this->handler)(new CommentReplyAdded(111, 222, 333, 'message', 'file'));
}

/**
Expand All @@ -106,7 +106,7 @@ public function testInvokeReplyAdded(): void
$this->apiProvider->expects(self::once())->method('create')->with($repository, $user)->willReturn($api);
$this->commentService->expects(self::once())->method('create')->with($api, $reply);

($this->handler)(new CommentReplyAdded(111, 222, 333, 'message'));
($this->handler)(new CommentReplyAdded(111, 222, 333, 'message', 'file'));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function testAccepts(): void
public function testHandleAbsentCommentShouldReturnEarly(): void
{
$this->replyRepository->expects(self::once())->method('find')->with(123)->willReturn(null);
$this->handler->handle(new CommentReplyAdded(5, 123, 456, 'message'));
$this->handler->handle(new CommentReplyAdded(5, 123, 456, 'message', 'file'));
}

/**
Expand All @@ -54,7 +54,7 @@ public function testHandleCommentStatusAlreadyHandled(): void
$comment->getNotificationStatus()->addStatus(NotificationStatus::STATUS_CREATED);

$this->replyRepository->expects(self::once())->method('find')->with(123)->willReturn($comment);
$this->handler->handle(new CommentReplyAdded(5, 123, 456, 'message'));
$this->handler->handle(new CommentReplyAdded(5, 123, 456, 'message', 'file'));
}

/**
Expand All @@ -72,7 +72,7 @@ public function testHandle(): void
$this->mailService->expects(self::once())->method('sendNewCommentReplyMail')->with($review, $comment, $reply);
$this->replyRepository->expects(self::once())->method('save')->with($reply, true);

$this->handler->handle(new CommentReplyAdded(5, 123, 456, 'message'));
$this->handler->handle(new CommentReplyAdded(5, 123, 456, 'message', 'file'));

static::assertTrue($reply->getNotificationStatus()->hasStatus(NotificationStatus::STATUS_CREATED));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ public function testFormatCommentReplyEvent(): void

$this->translator->expects(self::once())
->method('trans')
->with('timeline.comment.reply.added', ['username' => 'app', 'message' => 'message'])
->with('timeline.comment.reply.added', ['username' => 'app', 'file' => 'filepath'])
->willReturnArgument(0);

$this->formatter->format($activity, $user);
Expand Down
Loading

0 comments on commit ae2930a

Please sign in to comment.