0
0
Fork 0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-04-16 17:47:52 +00:00

Sorting: Added auto sort option to book sort UI

Includes indicator on books added to sort operation.
This commit is contained in:
Dan Brown 2025-02-09 15:16:18 +00:00
parent ccd94684eb
commit ec79517493
No known key found for this signature in database
GPG key ID: 46D9F943C24A2EF9
8 changed files with 74 additions and 18 deletions

View file

@ -44,24 +44,40 @@ class BookSortController extends Controller
}
/**
* Sorts a book using a given mapping array.
* Update the sort options of a book, setting the auto-sort and/or updating
* child order via mapping.
*/
public function update(Request $request, BookSorter $sorter, string $bookSlug)
{
$book = $this->queries->findVisibleBySlugOrFail($bookSlug);
$this->checkOwnablePermission('book-update', $book);
$loggedActivityForBook = false;
// Return if no map sent
if (!$request->filled('sort-tree')) {
return redirect($book->getUrl());
// Sort via map
if ($request->filled('sort-tree')) {
$sortMap = BookSortMap::fromJson($request->get('sort-tree'));
$booksInvolved = $sorter->sortUsingMap($sortMap);
// Rebuild permissions and add activity for involved books.
foreach ($booksInvolved as $bookInvolved) {
Activity::add(ActivityType::BOOK_SORT, $bookInvolved);
if ($bookInvolved->id === $book->id) {
$loggedActivityForBook = true;
}
}
}
$sortMap = BookSortMap::fromJson($request->get('sort-tree'));
$booksInvolved = $sorter->sortUsingMap($sortMap);
// Rebuild permissions and add activity for involved books.
foreach ($booksInvolved as $bookInvolved) {
Activity::add(ActivityType::BOOK_SORT, $bookInvolved);
if ($request->filled('auto-sort')) {
$sortSetId = intval($request->get('auto-sort')) ?: null;
if ($sortSetId && SortSet::query()->find($sortSetId) === null) {
$sortSetId = null;
}
$book->sort_set_id = $sortSetId;
$book->save();
$sorter->runBookAutoSort($book);
if (!$loggedActivityForBook) {
Activity::add(ActivityType::BOOK_SORT, $book);
}
}
return redirect($book->getUrl());

View file

@ -5,6 +5,7 @@ namespace BookStack\Sorting;
use BookStack\Activity\Models\Loggable;
use BookStack\Entities\Models\Book;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
@ -48,4 +49,12 @@ class SortSet extends Model implements Loggable
{
return $this->hasMany(Book::class);
}
public static function allByName(): Collection
{
return static::query()
->withCount('books')
->orderBy('name', 'asc')
->get();
}
}

View file

@ -166,7 +166,9 @@ return [
'books_search_this' => 'Search this book',
'books_navigation' => 'Book Navigation',
'books_sort' => 'Sort Book Contents',
'books_sort_desc' => 'Move chapters and pages within a book to reorganise its contents. Other books can be added which allows easy moving of chapters and pages between books.',
'books_sort_desc' => 'Move chapters and pages within a book to reorganise its contents. Other books can be added which allows easy moving of chapters and pages between books. Optionally an auto sort option can be set to automatically sort this book\'s contents upon changes.',
'books_sort_auto_sort' => 'Auto Sort Option',
'books_sort_auto_sort_active' => 'Auto Sort Active: :sortName',
'books_sort_named' => 'Sort Book :bookName',
'books_sort_name' => 'Sort by Name',
'books_sort_created' => 'Sort by Created Date',

View file

@ -0,0 +1 @@
<svg version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m3 18h6v-2h-6zm0-12v2h18v-2zm0 7h11v-2h-11z"/><g transform="matrix(.024132 0 0 .024132 3.6253 26.687)"><path d="m602.72-360v-146.6h-58.639l117.28-205.24v146.6h58.639z" stroke-width=".73298"/></g></svg>

After

(image error) Size: 285 B

View file

@ -242,6 +242,10 @@
margin-bottom: vars.$m;
padding: vars.$m vars.$xl;
position: relative;
summary:focus {
outline: 1px dashed var(--color-primary);
outline-offset: 5px;
}
&::before {
pointer-events: none;
content: '';

View file

@ -8,6 +8,11 @@
<span>@icon('book')</span>
<span>{{ $book->name }}</span>
</div>
<div class="flex-container-row items-center text-book">
@if($book->sortSet)
<span title="{{ trans('entities.books_sort_auto_sort_active', ['sortName' => $book->sortSet->name]) }}">@icon('auto-sort')</span>
@endif
</div>
</h5>
</summary>
<div class="sort-box-options pb-sm">

View file

@ -18,14 +18,36 @@
<div>
<div component="book-sort" class="card content-wrap auto-height">
<h1 class="list-heading">{{ trans('entities.books_sort') }}</h1>
<p class="text-muted">{{ trans('entities.books_sort_desc') }}</p>
<div class="flex-container-row gap-m wrap mb-m">
<p class="text-muted flex min-width-s mb-none">{{ trans('entities.books_sort_desc') }}</p>
<div class="min-width-s">
@php
$autoSortVal = intval(old('auto-sort') ?? $book->sort_set_id ?? 0);
@endphp
<label for="auto-sort">{{ trans('entities.books_sort_auto_sort') }}</label>
<select id="auto-sort"
name="auto-sort"
form="sort-form"
class="{{ $errors->has('auto-sort') ? 'neg' : '' }}">
<option value="0" @if($autoSortVal === 0) selected @endif>-- {{ trans('common.none') }} --</option>
@foreach(\BookStack\Sorting\SortSet::allByName() as $set)
<option value="{{$set->id}}"
@if($autoSortVal === $set->id) selected @endif
>
{{ $set->name }}
</option>
@endforeach
</select>
</div>
</div>
<div refs="book-sort@sortContainer">
@include('books.parts.sort-box', ['book' => $book, 'bookChildren' => $bookChildren])
</div>
<form action="{{ $book->getUrl('/sort') }}" method="POST">
{!! csrf_field() !!}
<form id="sort-form" action="{{ $book->getUrl('/sort') }}" method="POST">
{{ csrf_field() }}
<input type="hidden" name="_method" value="PUT">
<input refs="book-sort@input" type="hidden" name="sort-tree">
<div class="list text-right">

View file

@ -1,10 +1,7 @@
@extends('settings.layout')
@php
$sortSets = \BookStack\Sorting\SortSet::query()
->withCount('books')
->orderBy('name', 'asc')
->get();
$sortSets = \BookStack\Sorting\SortSet::allByName();
@endphp
@section('card')