Comments: Added read-only listing into page editor

This commit is contained in:
Dan Brown 2023-06-16 13:08:04 +01:00
parent ec775aec02
commit 9a2ef7ef44
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
9 changed files with 81 additions and 30 deletions

View File

@ -24,16 +24,10 @@ use Throwable;
class PageController extends Controller class PageController extends Controller
{ {
protected PageRepo $pageRepo; public function __construct(
protected ReferenceFetcher $referenceFetcher; protected PageRepo $pageRepo,
protected ReferenceFetcher $referenceFetcher
/** ) {
* PageController constructor.
*/
public function __construct(PageRepo $pageRepo, ReferenceFetcher $referenceFetcher)
{
$this->pageRepo = $pageRepo;
$this->referenceFetcher = $referenceFetcher;
} }
/** /**

View File

@ -2,6 +2,7 @@
namespace BookStack\Entities\Tools; namespace BookStack\Entities\Tools;
use BookStack\Activity\Tools\CommentTree;
use BookStack\Entities\Models\Page; use BookStack\Entities\Models\Page;
use BookStack\Entities\Repos\PageRepo; use BookStack\Entities\Repos\PageRepo;
use BookStack\Entities\Tools\Markdown\HtmlToMarkdown; use BookStack\Entities\Tools\Markdown\HtmlToMarkdown;
@ -9,19 +10,14 @@ use BookStack\Entities\Tools\Markdown\MarkdownToHtml;
class PageEditorData class PageEditorData
{ {
protected Page $page;
protected PageRepo $pageRepo;
protected string $requestedEditor;
protected array $viewData; protected array $viewData;
protected array $warnings; protected array $warnings;
public function __construct(Page $page, PageRepo $pageRepo, string $requestedEditor) public function __construct(
{ protected Page $page,
$this->page = $page; protected PageRepo $pageRepo,
$this->pageRepo = $pageRepo; protected string $requestedEditor
$this->requestedEditor = $requestedEditor; ) {
$this->viewData = $this->build(); $this->viewData = $this->build();
} }
@ -69,6 +65,7 @@ class PageEditorData
'draftsEnabled' => $draftsEnabled, 'draftsEnabled' => $draftsEnabled,
'templates' => $templates, 'templates' => $templates,
'editor' => $editorType, 'editor' => $editorType,
'comments' => new CommentTree($page),
]; ];
} }

View File

@ -371,6 +371,7 @@ return [
'comment_updated_success' => 'Comment updated', 'comment_updated_success' => 'Comment updated',
'comment_delete_confirm' => 'Are you sure you want to delete this comment?', 'comment_delete_confirm' => 'Are you sure you want to delete this comment?',
'comment_in_reply_to' => 'In reply to :commentId', 'comment_in_reply_to' => 'In reply to :commentId',
'comment_editor_explain' => 'Here are the comments that have been left on this page. Comments can be added & managed when viewing the saved page.',
// Revision // Revision
'revision_delete_confirm' => 'Are you sure you want to delete this revision?', 'revision_delete_confirm' => 'Are you sure you want to delete this revision?',

View File

@ -676,6 +676,7 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
@include lightDark(background-color, #FFF, #222); @include lightDark(background-color, #FFF, #222);
.content { .content {
font-size: 0.666em; font-size: 0.666em;
padding: $-m $-s;
p, ul, ol { p, ul, ol {
font-size: $fs-m; font-size: $fs-m;
margin: .5em 0; margin: .5em 0;
@ -700,6 +701,7 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
.comment-box .header { .comment-box .header {
border-bottom: 1px solid #DDD; border-bottom: 1px solid #DDD;
padding: $-s;
@include lightDark(border-color, #DDD, #000); @include lightDark(border-color, #DDD, #000);
button { button {
font-size: .8rem; font-size: .8rem;
@ -710,6 +712,9 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
.text-muted { .text-muted {
color: #999; color: #999;
} }
.meta a, .meta span {
white-space: nowrap;
}
.right-meta .text-muted { .right-meta .text-muted {
opacity: .8; opacity: .8;
} }
@ -735,6 +740,24 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
display: block; display: block;
} }
.comment-container-compact .comment-box {
.meta {
font-size: 0.8rem;
}
.header {
padding: $-xs;
}
.right-meta {
display: none;
}
.content {
padding: $-xs $-s;
}
}
.comment-container-compact .comment-thread-indicator {
width: $-m;
}
#tag-manager .drag-card { #tag-manager .drag-card {
max-width: 500px; max-width: 500px;
} }

View File

@ -1,4 +1,4 @@
<div component="page-comment" <div component="{{ $readOnly ? '' : 'page-comment' }}"
option:page-comment:comment-id="{{ $comment->id }}" option:page-comment:comment-id="{{ $comment->id }}"
option:page-comment:comment-local-id="{{ $comment->local_id }}" option:page-comment:comment-local-id="{{ $comment->local_id }}"
option:page-comment:comment-parent-id="{{ $comment->parent_id }}" option:page-comment:comment-parent-id="{{ $comment->parent_id }}"
@ -6,12 +6,15 @@
option:page-comment:deleted-text="{{ trans('entities.comment_deleted_success') }}" option:page-comment:deleted-text="{{ trans('entities.comment_deleted_success') }}"
id="comment{{$comment->local_id}}" id="comment{{$comment->local_id}}"
class="comment-box"> class="comment-box">
<div class="header p-s"> <div class="header">
<div class="flex-container-row justify-space-between wrap"> <div class="flex-container-row wrap items-center gap-x-xs">
<div class="meta text-muted flex-container-row items-center"> @if ($comment->createdBy)
<div>
<img width="50" src="{{ $comment->createdBy->getAvatar(50) }}" class="avatar block mx-xs" alt="{{ $comment->createdBy->name }}">
</div>
@endif
<div class="meta text-muted flex-container-row wrap items-center flex">
@if ($comment->createdBy) @if ($comment->createdBy)
<img width="50" src="{{ $comment->createdBy->getAvatar(50) }}" class="avatar mx-xs" alt="{{ $comment->createdBy->name }}">
&nbsp;
<a href="{{ $comment->createdBy->getProfileUrl() }}">{{ $comment->createdBy->getShortName(16) }}</a> <a href="{{ $comment->createdBy->getProfileUrl() }}">{{ $comment->createdBy->getShortName(16) }}</a>
@else @else
{{ trans('common.deleted_user') }} {{ trans('common.deleted_user') }}
@ -25,6 +28,7 @@
@endif @endif
</div> </div>
<div class="right-meta flex-container-row justify-flex-end items-center px-s"> <div class="right-meta flex-container-row justify-flex-end items-center px-s">
@if(!$readOnly && (userCan('comment-create-all') || userCan('comment-update', $comment) || userCan('comment-delete', $comment)))
<div class="actions mr-s"> <div class="actions mr-s">
@if(userCan('comment-create-all')) @if(userCan('comment-create-all'))
<button refs="page-comment@reply-button" type="button" class="text-button text-muted hover-underline p-xs">@icon('reply') {{ trans('common.reply') }}</button> <button refs="page-comment@reply-button" type="button" class="text-button text-muted hover-underline p-xs">@icon('reply') {{ trans('common.reply') }}</button>
@ -50,6 +54,7 @@
&nbsp;&bull;&nbsp; &nbsp;&bull;&nbsp;
</span> </span>
</div> </div>
@endif
<div> <div>
<a class="bold text-muted" href="#comment{{$comment->local_id}}">#{{$comment->local_id}}</a> <a class="bold text-muted" href="#comment{{$comment->local_id}}">#{{$comment->local_id}}</a>
</div> </div>
@ -58,7 +63,7 @@
</div> </div>
<div refs="page-comment@content-container" class="content px-m py-s"> <div refs="page-comment@content-container" class="content">
@if ($comment->parent_id) @if ($comment->parent_id)
<p class="comment-reply mb-xxs"> <p class="comment-reply mb-xxs">
<a class="text-muted text-small" href="#comment{{ $comment->parent_id }}">@icon('reply'){{ trans('entities.comment_in_reply_to', ['commentId' => '#' . $comment->parent_id]) }}</a> <a class="text-muted text-small" href="#comment{{ $comment->parent_id }}">@icon('reply'){{ trans('entities.comment_in_reply_to', ['commentId' => '#' . $comment->parent_id]) }}</a>
@ -67,7 +72,7 @@
{!! $comment->html !!} {!! $comment->html !!}
</div> </div>
@if(userCan('comment-update', $comment)) @if(!$readOnly && userCan('comment-update', $comment))
<form novalidate refs="page-comment@form" hidden class="content pt-s px-s block"> <form novalidate refs="page-comment@form" hidden class="content pt-s px-s block">
<div class="form-group description-input"> <div class="form-group description-input">
<textarea refs="page-comment@input" name="markdown" rows="3" placeholder="{{ trans('entities.comment_placeholder') }}">{{ $comment->text }}</textarea> <textarea refs="page-comment@input" name="markdown" rows="3" placeholder="{{ trans('entities.comment_placeholder') }}">{{ $comment->text }}</textarea>

View File

@ -18,7 +18,7 @@
<div refs="page-comments@commentContainer" class="comment-container"> <div refs="page-comments@commentContainer" class="comment-container">
@foreach($commentTree->get() as $branch) @foreach($commentTree->get() as $branch)
@include('comments.comment-branch', ['branch' => $branch]) @include('comments.comment-branch', ['branch' => $branch, 'readOnly' => false])
@endforeach @endforeach
</div> </div>

View File

@ -7,6 +7,9 @@
<button type="button" refs="editor-toolbox@tab-button" data-tab="files" title="{{ trans('entities.attachments') }}">@icon('attach')</button> <button type="button" refs="editor-toolbox@tab-button" data-tab="files" title="{{ trans('entities.attachments') }}">@icon('attach')</button>
@endif @endif
<button type="button" refs="editor-toolbox@tab-button" data-tab="templates" title="{{ trans('entities.templates') }}">@icon('template')</button> <button type="button" refs="editor-toolbox@tab-button" data-tab="templates" title="{{ trans('entities.templates') }}">@icon('template')</button>
@if($comments->enabled())
<button type="button" refs="editor-toolbox@tab-button" data-tab="comments" title="{{ trans('entities.comments') }}">@icon('comment')</button>
@endif
</div> </div>
<div refs="editor-toolbox@tab-content" data-tab-content="tags" class="toolbox-tab-content"> <div refs="editor-toolbox@tab-content" data-tab-content="tags" class="toolbox-tab-content">
@ -26,7 +29,10 @@
<div class="px-l"> <div class="px-l">
@include('pages.parts.template-manager', ['page' => $page, 'templates' => $templates]) @include('pages.parts.template-manager', ['page' => $page, 'templates' => $templates])
</div> </div>
</div> </div>
@if($comments->enabled())
@include('pages.parts.toolbox-comments')
@endif
</div> </div>

View File

@ -0,0 +1,15 @@
<div refs="editor-toolbox@tab-content" data-tab-content="comments" class="toolbox-tab-content">
<h4>{{ trans('entities.comments') }}</h4>
<div class="comment-container-compact px-l">
<p class="text-muted small mb-m">
{{ trans('entities.comment_editor_explain') }}
</p>
@foreach($comments->get() as $branch)
@include('comments.comment-branch', ['branch' => $branch, 'readOnly' => true])
@endforeach
@if($comments->empty())
<p class="italic text-muted">{{ trans('common.no_items') }}</p>
@endif
</div>
</div>

View File

@ -135,4 +135,14 @@ class CommentTest extends TestCase
$respHtml->assertElementCount('.comment-branch', 4); $respHtml->assertElementCount('.comment-branch', 4);
$respHtml->assertElementContains('.comment-branch .comment-branch', 'My nested comment'); $respHtml->assertElementContains('.comment-branch .comment-branch', 'My nested comment');
} }
public function test_comments_are_visible_in_the_page_editor()
{
$page = $this->entities->page();
$this->asAdmin()->postJson("/comment/$page->id", ['text' => 'My great comment to see in the editor']);
$respHtml = $this->withHtml($this->get($page->getUrl('/edit')));
$respHtml->assertElementContains('.comment-box .content', 'My great comment to see in the editor');
}
} }