]> BookStack Code Mirror - bookstack/commitdiff
Sorting: Added auto sort option to book sort UI
authorDan Brown <redacted>
Sun, 9 Feb 2025 15:16:18 +0000 (15:16 +0000)
committerDan Brown <redacted>
Sun, 9 Feb 2025 15:16:18 +0000 (15:16 +0000)
Includes indicator on books added to sort operation.

app/Sorting/BookSortController.php
app/Sorting/SortSet.php
lang/en/entities.php
resources/icons/auto-sort.svg [new file with mode: 0644]
resources/sass/_lists.scss
resources/views/books/parts/sort-box.blade.php
resources/views/books/sort.blade.php
resources/views/settings/categories/sorting.blade.php

index feed5db4fde0694086d7c2a90b6ae61e21c96aa3..98d79d0fd1299d23349bb80c8f86cde3a3534e26 100644 (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);
 
-        $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;
+                }
+            }
+        }
 
-        // 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());
index a73407bfa08e58e8c695701a34b98e12be034849..8cdee1df49c4e24b276616328a94a1dfae7fda05 100644 (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();
+    }
 }
index 26a563a7eb534388afd1e89fce92ea91e1a8a5c7..28a209fa21a2b41f5c30909a5df732bcdf383747 100644 (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',
diff --git a/resources/icons/auto-sort.svg b/resources/icons/auto-sort.svg
new file mode 100644 (file)
index 0000000..c3cb2f5
--- /dev/null
@@ -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>
index fd76f498ed186bf6a23be71151d15dbd2f726e48..1e503dd0ffe50a54eb428c2ca19e63ece3737afe 100644 (file)
   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: '';
index 03998e261781bd7db46d9ba427963c93bd721a54..232616168f92e9af637b57161c93770bf022e972 100644 (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">
index c82ad4e3b1e7f7cec7f2ffdbcecd9e7b6b49ea23..3c59ac1e0928e1a2acde9e3c6afdae958d3ad119 100644 (file)
             <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">
index 60fb329b6aa53a99b2ae65777477faae63ada4cb..6a52873e6abd9c6f2912bc585123137e89a9b8b7 100644 (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')
Morty Proxy This is a proxified and sanitized view of the page, visit original site.