mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-11-23 10:41:16 +08:00
Reduced the memory usage, db queries and cache hits loading revisions
Updated revision listing to only fetch required fields, massively reducing memory usage by not loading content. This also updates user avatar handling to effectively cache the avatar url within request to avoid re-searching from cache, which may improve performance of others areas of the application. This also upates handling of the revisions list view to extract table row to its own view to break things down a bit. For #3633
This commit is contained in:
parent
764489e30b
commit
031c67ba58
|
@ -80,6 +80,11 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||
*/
|
||||
protected ?Collection $permissions;
|
||||
|
||||
/**
|
||||
* This holds the user's avatar URL when loaded to prevent re-calculating within the same request.
|
||||
*/
|
||||
protected string $avatarUrl = '';
|
||||
|
||||
/**
|
||||
* This holds the default user when loaded.
|
||||
*
|
||||
|
@ -233,12 +238,17 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||
return $default;
|
||||
}
|
||||
|
||||
if (!empty($this->avatarUrl)) {
|
||||
return $this->avatarUrl;
|
||||
}
|
||||
|
||||
try {
|
||||
$avatar = $this->avatar ? url($this->avatar->getThumb($size, $size, false)) : $default;
|
||||
} catch (Exception $err) {
|
||||
$avatar = $default;
|
||||
}
|
||||
|
||||
$this->avatarUrl = $avatar;
|
||||
return $avatar;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,11 +11,8 @@ use Ssddanbrown\HtmlDiff\Diff;
|
|||
|
||||
class PageRevisionController extends Controller
|
||||
{
|
||||
protected $pageRepo;
|
||||
protected PageRepo $pageRepo;
|
||||
|
||||
/**
|
||||
* PageRevisionController constructor.
|
||||
*/
|
||||
public function __construct(PageRepo $pageRepo)
|
||||
{
|
||||
$this->pageRepo = $pageRepo;
|
||||
|
@ -29,11 +26,19 @@ class PageRevisionController extends Controller
|
|||
public function index(string $bookSlug, string $pageSlug)
|
||||
{
|
||||
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
|
||||
$this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()]));
|
||||
$revisions = $page->revisions()->select([
|
||||
'id', 'page_id', 'name', 'created_at', 'created_by', 'updated_at',
|
||||
'type', 'revision_number', 'summary',
|
||||
])
|
||||
->selectRaw("IF(markdown = '', false, true) as is_markdown")
|
||||
->with(['page.book', 'createdBy'])
|
||||
->get();
|
||||
|
||||
$this->setPageTitle(trans('entities.pages_revisions_named', ['pageName' => $page->getShortName()]));
|
||||
|
||||
return view('pages.revisions', [
|
||||
'revisions' => $revisions,
|
||||
'page' => $page,
|
||||
'current' => $page,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
69
resources/views/pages/parts/revision-table-row.blade.php
Normal file
69
resources/views/pages/parts/revision-table-row.blade.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<tr>
|
||||
<td>{{ $revision->revision_number == 0 ? '' : $revision->revision_number }}</td>
|
||||
<td>
|
||||
{{ $revision->name }}
|
||||
<br>
|
||||
<small class="text-muted">({{ $revision->is_markdown ? 'Markdown' : 'WYSIWYG' }})</small>
|
||||
</td>
|
||||
<td style="line-height: 0;" width="30">
|
||||
@if($revision->createdBy)
|
||||
<img class="avatar" src="{{ $revision->createdBy->getAvatar(30) }}" alt="{{ $revision->createdBy->name }}">
|
||||
@endif
|
||||
</td>
|
||||
<td width="260">
|
||||
@if($revision->createdBy) {{ $revision->createdBy->name }} @else {{ trans('common.deleted_user') }} @endif
|
||||
<br>
|
||||
<div class="text-muted">
|
||||
<small>{{ $revision->created_at->formatLocalized('%e %B %Y %H:%M:%S') }}</small>
|
||||
<small>({{ $revision->created_at->diffForHumans() }})</small>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{{ $revision->summary }}
|
||||
</td>
|
||||
<td class="actions text-small text-right">
|
||||
<a href="{{ $revision->getUrl('changes') }}" target="_blank" rel="noopener">{{ trans('entities.pages_revisions_changes') }}</a>
|
||||
<span class="text-muted"> | </span>
|
||||
|
||||
|
||||
@if ($index === 0)
|
||||
<a target="_blank" rel="noopener" href="{{ $revision->page->getUrl() }}"><i>{{ trans('entities.pages_revisions_current') }}</i></a>
|
||||
@else
|
||||
<a href="{{ $revision->getUrl() }}" target="_blank" rel="noopener">{{ trans('entities.pages_revisions_preview') }}</a>
|
||||
<span class="text-muted"> | </span>
|
||||
<div component="dropdown" class="dropdown-container">
|
||||
<a refs="dropdown@toggle" href="#" aria-haspopup="true" aria-expanded="false">{{ trans('entities.pages_revisions_restore') }}</a>
|
||||
<ul refs="dropdown@menu" class="dropdown-menu" role="menu">
|
||||
<li class="px-m py-s"><small class="text-muted">{{trans('entities.revision_restore_confirm')}}</small></li>
|
||||
<li>
|
||||
<form action="{{ $revision->getUrl('/restore') }}" method="POST">
|
||||
{!! csrf_field() !!}
|
||||
<input type="hidden" name="_method" value="PUT">
|
||||
<button type="submit" class="text-primary icon-item">
|
||||
@icon('history')
|
||||
<div>{{ trans('entities.pages_revisions_restore') }}</div>
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<span class="text-muted"> | </span>
|
||||
<div component="dropdown" class="dropdown-container">
|
||||
<a refs="dropdown@toggle" href="#" aria-haspopup="true" aria-expanded="false">{{ trans('common.delete') }}</a>
|
||||
<ul refs="dropdown@menu" class="dropdown-menu" role="menu">
|
||||
<li class="px-m py-s"><small class="text-muted">{{trans('entities.revision_delete_confirm')}}</small></li>
|
||||
<li>
|
||||
<form action="{{ $revision->getUrl('/delete/') }}" method="POST">
|
||||
{!! csrf_field() !!}
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
<button type="submit" class="text-neg icon-item">
|
||||
@icon('delete')
|
||||
<div>{{ trans('common.delete') }}</div>
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
|
@ -17,11 +17,11 @@
|
|||
|
||||
<main class="card content-wrap">
|
||||
<h1 class="list-heading">{{ trans('entities.pages_revisions') }}</h1>
|
||||
@if(count($page->revisions) > 0)
|
||||
@if(count($revisions) > 0)
|
||||
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th width="40">{{ trans('entities.pages_revisions_number') }}</th>
|
||||
<th width="56">{{ trans('entities.pages_revisions_number') }}</th>
|
||||
<th>
|
||||
{{ trans('entities.pages_name') }} / {{ trans('entities.pages_revisions_editor') }}
|
||||
</th>
|
||||
|
@ -29,76 +29,8 @@
|
|||
<th>{{ trans('entities.pages_revisions_changelog') }}</th>
|
||||
<th class="text-right">{{ trans('common.actions') }}</th>
|
||||
</tr>
|
||||
@foreach($page->revisions as $index => $revision)
|
||||
<tr>
|
||||
<td>{{ $revision->revision_number == 0 ? '' : $revision->revision_number }}</td>
|
||||
<td>
|
||||
{{ $revision->name }}
|
||||
<br>
|
||||
<small class="text-muted">({{ $revision->markdown ? 'Markdown' : 'WYSIWYG' }})</small>
|
||||
</td>
|
||||
<td style="line-height: 0;" width="30">
|
||||
@if($revision->createdBy)
|
||||
<img class="avatar" src="{{ $revision->createdBy->getAvatar(30) }}" alt="{{ $revision->createdBy->name }}">
|
||||
@endif
|
||||
</td>
|
||||
<td width="260">
|
||||
@if($revision->createdBy) {{ $revision->createdBy->name }} @else {{ trans('common.deleted_user') }} @endif
|
||||
<br>
|
||||
<div class="text-muted">
|
||||
<small>{{ $revision->created_at->formatLocalized('%e %B %Y %H:%M:%S') }}</small>
|
||||
<small>({{ $revision->created_at->diffForHumans() }})</small>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{{ $revision->summary }}
|
||||
</td>
|
||||
<td class="actions text-small text-right">
|
||||
<a href="{{ $revision->getUrl('changes') }}" target="_blank" rel="noopener">{{ trans('entities.pages_revisions_changes') }}</a>
|
||||
<span class="text-muted"> | </span>
|
||||
|
||||
|
||||
@if ($index === 0)
|
||||
<a target="_blank" rel="noopener" href="{{ $page->getUrl() }}"><i>{{ trans('entities.pages_revisions_current') }}</i></a>
|
||||
@else
|
||||
<a href="{{ $revision->getUrl() }}" target="_blank" rel="noopener">{{ trans('entities.pages_revisions_preview') }}</a>
|
||||
<span class="text-muted"> | </span>
|
||||
<div component="dropdown" class="dropdown-container">
|
||||
<a refs="dropdown@toggle" href="#" aria-haspopup="true" aria-expanded="false">{{ trans('entities.pages_revisions_restore') }}</a>
|
||||
<ul refs="dropdown@menu" class="dropdown-menu" role="menu">
|
||||
<li class="px-m py-s"><small class="text-muted">{{trans('entities.revision_restore_confirm')}}</small></li>
|
||||
<li>
|
||||
<form action="{{ $revision->getUrl('/restore') }}" method="POST">
|
||||
{!! csrf_field() !!}
|
||||
<input type="hidden" name="_method" value="PUT">
|
||||
<button type="submit" class="text-primary icon-item">
|
||||
@icon('history')
|
||||
<div>{{ trans('entities.pages_revisions_restore') }}</div>
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<span class="text-muted"> | </span>
|
||||
<div component="dropdown" class="dropdown-container">
|
||||
<a refs="dropdown@toggle" href="#" aria-haspopup="true" aria-expanded="false">{{ trans('common.delete') }}</a>
|
||||
<ul refs="dropdown@menu" class="dropdown-menu" role="menu">
|
||||
<li class="px-m py-s"><small class="text-muted">{{trans('entities.revision_delete_confirm')}}</small></li>
|
||||
<li>
|
||||
<form action="{{ $revision->getUrl('/delete/') }}" method="POST">
|
||||
{!! csrf_field() !!}
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
<button type="submit" class="text-neg icon-item">
|
||||
@icon('delete')
|
||||
<div>{{ trans('common.delete') }}</div>
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@foreach($revisions as $index => $revision)
|
||||
@include('pages.parts.revision-table-row', ['revision' => $revision])
|
||||
@endforeach
|
||||
</table>
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user