Skip to content

Commit 099f610

Browse files
committed
Comments: Started archive display, created mode for tree node
1 parent 8bdf948 commit 099f610

File tree

10 files changed

+110
-28
lines changed

10 files changed

+110
-28
lines changed

app/Activity/CommentRepo.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
use BookStack\Activity\Models\Comment;
66
use BookStack\Entities\Models\Entity;
7+
use BookStack\Exceptions\NotifyException;
8+
use BookStack\Exceptions\PrettyException;
79
use BookStack\Facades\Activity as ActivityService;
810
use BookStack\Util\HtmlDescriptionFilter;
911

@@ -59,6 +61,10 @@ public function update(Comment $comment, string $html): Comment
5961
*/
6062
public function archive(Comment $comment): Comment
6163
{
64+
if ($comment->parent_id) {
65+
throw new NotifyException('Only top-level comments can be archived.');
66+
}
67+
6268
$comment->archived = true;
6369
$comment->save();
6470

@@ -72,6 +78,10 @@ public function archive(Comment $comment): Comment
7278
*/
7379
public function unarchive(Comment $comment): Comment
7480
{
81+
if ($comment->parent_id) {
82+
throw new NotifyException('Only top-level comments can be un-archived.');
83+
}
84+
7585
$comment->archived = false;
7686
$comment->save();
7787

app/Activity/Controllers/CommentController.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace BookStack\Activity\Controllers;
44

55
use BookStack\Activity\CommentRepo;
6+
use BookStack\Activity\Tools\CommentTree;
7+
use BookStack\Activity\Tools\CommentTreeNode;
68
use BookStack\Entities\Queries\PageQueries;
79
use BookStack\Http\Controller;
810
use Illuminate\Http\Request;
@@ -45,10 +47,7 @@ public function savePageComment(Request $request, int $pageId)
4547

4648
return view('comments.comment-branch', [
4749
'readOnly' => false,
48-
'branch' => [
49-
'comment' => $comment,
50-
'children' => [],
51-
]
50+
'branch' => new CommentTreeNode($comment, 0, []),
5251
]);
5352
}
5453

@@ -81,15 +80,17 @@ public function update(Request $request, int $commentId)
8180
public function archive(int $id)
8281
{
8382
$comment = $this->commentRepo->getById($id);
83+
$this->checkOwnablePermission('page-view', $comment->entity);
8484
if (!userCan('comment-update', $comment) && !userCan('comment-delete', $comment)) {
8585
$this->showPermissionError();
8686
}
8787

8888
$this->commentRepo->archive($comment);
8989

90-
return view('comments.comment', [
91-
'comment' => $comment,
90+
$tree = new CommentTree($comment->entity);
91+
return view('comments.comment-branch', [
9292
'readOnly' => false,
93+
'branch' => $tree->getCommentNodeForId($id),
9394
]);
9495
}
9596

@@ -99,15 +100,17 @@ public function archive(int $id)
99100
public function unarchive(int $id)
100101
{
101102
$comment = $this->commentRepo->getById($id);
103+
$this->checkOwnablePermission('page-view', $comment->entity);
102104
if (!userCan('comment-update', $comment) && !userCan('comment-delete', $comment)) {
103105
$this->showPermissionError();
104106
}
105107

106108
$this->commentRepo->unarchive($comment);
107109

108-
return view('comments.comment', [
109-
'comment' => $comment,
110+
$tree = new CommentTree($comment->entity);
111+
return view('comments.comment-branch', [
110112
'readOnly' => false,
113+
'branch' => $tree->getCommentNodeForId($id),
111114
]);
112115
}
113116

app/Activity/Tools/CommentTree.php

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class CommentTree
99
{
1010
/**
1111
* The built nested tree structure array.
12-
* @var array{comment: Comment, depth: int, children: array}[]
12+
* @var CommentTreeNode[]
1313
*/
1414
protected array $tree;
1515
protected array $comments;
@@ -36,9 +36,25 @@ public function count(): int
3636
return count($this->comments);
3737
}
3838

39-
public function get(): array
39+
public function getActive(): array
4040
{
41-
return $this->tree;
41+
return array_filter($this->tree, fn (CommentTreeNode $node) => !$node->comment->archived);
42+
}
43+
44+
public function getArchived(): array
45+
{
46+
return array_filter($this->tree, fn (CommentTreeNode $node) => $node->comment->archived);
47+
}
48+
49+
public function getCommentNodeForId(int $commentId): ?CommentTreeNode
50+
{
51+
foreach ($this->tree as $node) {
52+
if ($node->comment->id === $commentId) {
53+
return $node;
54+
}
55+
}
56+
57+
return null;
4258
}
4359

4460
public function canUpdateAny(): bool
@@ -54,6 +70,7 @@ public function canUpdateAny(): bool
5470

5571
/**
5672
* @param Comment[] $comments
73+
* @return CommentTreeNode[]
5774
*/
5875
protected function createTree(array $comments): array
5976
{
@@ -77,26 +94,22 @@ protected function createTree(array $comments): array
7794

7895
$tree = [];
7996
foreach ($childMap[0] ?? [] as $childId) {
80-
$tree[] = $this->createTreeForId($childId, 0, $byId, $childMap);
97+
$tree[] = $this->createTreeNodeForId($childId, 0, $byId, $childMap);
8198
}
8299

83100
return $tree;
84101
}
85102

86-
protected function createTreeForId(int $id, int $depth, array &$byId, array &$childMap): array
103+
protected function createTreeNodeForId(int $id, int $depth, array &$byId, array &$childMap): CommentTreeNode
87104
{
88105
$childIds = $childMap[$id] ?? [];
89106
$children = [];
90107

91108
foreach ($childIds as $childId) {
92-
$children[] = $this->createTreeForId($childId, $depth + 1, $byId, $childMap);
109+
$children[] = $this->createTreeNodeForId($childId, $depth + 1, $byId, $childMap);
93110
}
94111

95-
return [
96-
'comment' => $byId[$id],
97-
'depth' => $depth,
98-
'children' => $children,
99-
];
112+
return new CommentTreeNode($byId[$id], $depth, $children);
100113
}
101114

102115
protected function loadComments(): array
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace BookStack\Activity\Tools;
4+
5+
use BookStack\Activity\Models\Comment;
6+
7+
class CommentTreeNode
8+
{
9+
public Comment $comment;
10+
public int $depth;
11+
12+
/**
13+
* @var CommentTreeNode[]
14+
*/
15+
public array $children;
16+
17+
public function __construct(Comment $comment, int $depth, array $children)
18+
{
19+
$this->comment = $comment;
20+
$this->depth = $depth;
21+
$this->children = $children;
22+
}
23+
}

lang/en/entities.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@
392392
'comment' => 'Comment',
393393
'comments' => 'Comments',
394394
'comment_add' => 'Add Comment',
395+
'comment_archived' => ':count Archived Comment|:count Archived Comments',
395396
'comment_placeholder' => 'Leave a comment here',
396397
'comment_count' => '{0} No Comments|{1} 1 Comment|[2,*] :count Comments',
397398
'comment_save' => 'Save Comment',

resources/js/components/page-comment.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,12 @@ export class PageComment extends Component {
137137
protected async archive(): Promise<void> {
138138
this.showLoading();
139139
const isArchived = this.archiveButton.dataset.isArchived === 'true';
140+
const action = isArchived ? 'unarchive' : 'archive';
140141

141-
await window.$http.put(`/comment/${this.commentId}/${isArchived ? 'unarchive' : 'archive'}`);
142-
this.$emit('archive');
142+
const response = await window.$http.put(`/comment/${this.commentId}/${action}`);
143+
this.$emit(action, {new_thread_dom: htmlToDom(response.data as string)});
143144
window.$events.success(this.archiveText);
145+
this.container.closest('.comment-branch')?.remove();
144146
}
145147

146148
protected showLoading(): HTMLElement {

resources/js/components/page-comments.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ export interface CommentReplyEvent extends Event {
99
}
1010
}
1111

12+
export interface ArchiveEvent extends Event {
13+
detail: {
14+
new_thread_dom: HTMLElement;
15+
}
16+
}
17+
1218
export class PageComments extends Component {
1319

1420
private elem: HTMLElement;
@@ -17,6 +23,7 @@ export class PageComments extends Component {
1723
private commentCountBar: HTMLElement;
1824
private commentsTitle: HTMLElement;
1925
private addButtonContainer: HTMLElement;
26+
private archiveContainer: HTMLElement;
2027
private replyToRow: HTMLElement;
2128
private formContainer: HTMLElement;
2229
private form: HTMLFormElement;
@@ -43,6 +50,7 @@ export class PageComments extends Component {
4350
this.commentCountBar = this.$refs.commentCountBar;
4451
this.commentsTitle = this.$refs.commentsTitle;
4552
this.addButtonContainer = this.$refs.addButtonContainer;
53+
this.archiveContainer = this.$refs.archiveContainer;
4654
this.replyToRow = this.$refs.replyToRow;
4755
this.formContainer = this.$refs.formContainer;
4856
this.form = this.$refs.form as HTMLFormElement;
@@ -75,6 +83,14 @@ export class PageComments extends Component {
7583
this.setReply(event.detail.id, event.detail.element);
7684
});
7785

86+
this.elem.addEventListener('page-comment-archive', (event: ArchiveEvent) => {
87+
this.archiveContainer.append(event.detail.new_thread_dom);
88+
});
89+
90+
this.elem.addEventListener('page-comment-unarchive', (event: ArchiveEvent) => {
91+
this.container.append(event.detail.new_thread_dom)
92+
});
93+
7894
if (this.form) {
7995
this.removeReplyToButton.addEventListener('click', this.removeReplyTo.bind(this));
8096
this.hideFormButton.addEventListener('click', this.hideForm.bind(this));

resources/views/comments/comment-branch.blade.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1+
{{--
2+
$branch CommentTreeNode
3+
--}}
14
<div class="comment-branch">
25
<div>
3-
@include('comments.comment', ['comment' => $branch['comment']])
6+
@include('comments.comment', ['comment' => $branch->comment])
47
</div>
58
<div class="flex-container-row">
69
<div class="comment-thread-indicator-parent">
710
<div class="comment-thread-indicator"></div>
811
</div>
912
<div class="comment-branch-children flex">
10-
@foreach($branch['children'] as $childBranch)
13+
@foreach($branch->children as $childBranch)
1114
@include('comments.comment-branch', ['branch' => $childBranch])
1215
@endforeach
1316
</div>

resources/views/comments/comment.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class="comment-box">
3838
@if(userCan('comment-create-all'))
3939
<button refs="page-comment@reply-button" type="button" class="text-button text-muted hover-underline text-small p-xs">@icon('reply') {{ trans('common.reply') }}</button>
4040
@endif
41-
@if(userCan('comment-update', $comment) || userCan('comment-delete', $comment))
41+
@if(!$comment->parent_id && (userCan('comment-update', $comment) || userCan('comment-delete', $comment)))
4242
<button refs="page-comment@archive-button"
4343
type="button"
4444
data-is-archived="{{ $comment->archived ? 'true' : 'false' }}"

resources/views/comments/comments.blade.php

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,34 @@ class="button outline">{{ trans('entities.comment_add') }}</button>
1818
@endif
1919
</div>
2020

21-
<div refs="page-comments@commentContainer" class="comment-container">
22-
@foreach($commentTree->get() as $branch)
21+
<div refs="page-comments@comment-container" class="comment-container">
22+
@foreach($commentTree->getActive() as $branch)
2323
@include('comments.comment-branch', ['branch' => $branch, 'readOnly' => false])
2424
@endforeach
2525
</div>
2626

2727
@if(userCan('comment-create-all'))
2828
@include('comments.create')
2929
@if (!$commentTree->empty())
30-
<div refs="page-comments@addButtonContainer" class="text-right">
30+
<div refs="page-comments@addButtonContainer" class="flex-container-row">
31+
32+
<button type="button"
33+
refs="page-comments@show-archived-button"
34+
class="text-button hover-underline">{{ trans_choice('entities.comment_archived', count($commentTree->getArchived())) }}</button>
35+
3136
<button type="button"
3237
refs="page-comments@add-comment-button"
33-
class="button outline">{{ trans('entities.comment_add') }}</button>
38+
class="button outline ml-auto">{{ trans('entities.comment_add') }}</button>
3439
</div>
3540
@endif
3641
@endif
3742

43+
<div refs="page-comments@archive-container" class="comment-container">
44+
@foreach($commentTree->getArchived() as $branch)
45+
@include('comments.comment-branch', ['branch' => $branch, 'readOnly' => false])
46+
@endforeach
47+
</div>
48+
3849
@if(userCan('comment-create-all') || $commentTree->canUpdateAny())
3950
@push('body-end')
4051
<script src="{{ versioned_asset('libs/tinymce/tinymce.min.js') }}" nonce="{{ $cspNonce }}" defer></script>

0 commit comments

Comments
 (0)