]> BookStack Code Mirror - bookstack/commitdiff
Sorting: Finished main sort set CRUD work
authorDan Brown <redacted>
Tue, 4 Feb 2025 20:11:35 +0000 (20:11 +0000)
committerDan Brown <redacted>
Tue, 4 Feb 2025 20:11:35 +0000 (20:11 +0000)
app/Activity/ActivityType.php
app/Sorting/SortSet.php
app/Sorting/SortSetController.php
app/Sorting/SortSetOperation.php
lang/en/activities.php
lang/en/settings.php
resources/views/settings/categories/sorting.blade.php
resources/views/settings/sort-sets/edit.blade.php [new file with mode: 0644]
resources/views/settings/sort-sets/parts/form.blade.php
resources/views/settings/sort-sets/parts/sort-set-list-item.blade.php [new file with mode: 0644]

index 5ec9b9cf0dc7f452040b2ca3278c24d0ed0c9855..4a648da6cfbdb5cb4f173026f5e96cb3f22c7059 100644 (file)
@@ -71,6 +71,10 @@ class ActivityType
     const IMPORT_RUN = 'import_run';
     const IMPORT_DELETE = 'import_delete';
 
+    const SORT_SET_CREATE = 'sort_set_create';
+    const SORT_SET_UPDATE = 'sort_set_update';
+    const SORT_SET_DELETE = 'sort_set_delete';
+
     /**
      * Get all the possible values.
      */
index ee45c211f2dc15b7a68672ab7a5f4abfa8de4c3f..971b3e29aae243dddfe675da74cbe3c7f0addcc4 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace BookStack\Sorting;
 
+use BookStack\Activity\Models\Loggable;
 use Carbon\Carbon;
 use Illuminate\Database\Eloquent\Model;
 
@@ -12,16 +13,14 @@ use Illuminate\Database\Eloquent\Model;
  * @property Carbon $created_at
  * @property Carbon $updated_at
  */
-class SortSet extends Model
+class SortSet extends Model implements Loggable
 {
     /**
      * @return SortSetOperation[]
      */
     public function getOperations(): array
     {
-        $strOptions = explode(',', $this->sequence);
-        $options = array_map(fn ($val) => SortSetOperation::tryFrom($val), $strOptions);
-        return array_filter($options);
+        return SortSetOperation::fromSequence($this->sequence);
     }
 
     /**
@@ -32,4 +31,14 @@ class SortSet extends Model
         $values = array_map(fn (SortSetOperation $opt) => $opt->value, $options);
         $this->sequence = implode(',', $values);
     }
+
+    public function logDescriptor(): string
+    {
+        return "({$this->id}) {$this->name}";
+    }
+
+    public function getUrl(): string
+    {
+        return url("/settings/sorting/sets/{$this->id}");
+    }
 }
index 4ef1482953870592c4b84af2b2ee70f513227943..0d77bd88fcd88048c7087666b238520c00076369 100644 (file)
@@ -2,7 +2,9 @@
 
 namespace BookStack\Sorting;
 
+use BookStack\Activity\ActivityType;
 use BookStack\Http\Controller;
+use BookStack\Http\Request;
 
 class SortSetController extends Controller
 {
@@ -14,6 +16,73 @@ class SortSetController extends Controller
 
     public function create()
     {
+        $this->setPageTitle(trans('settings.sort_set_create'));
+
         return view('settings.sort-sets.create');
     }
+
+    public function store(Request $request)
+    {
+        $this->validate($request, [
+            'name' => ['required', 'string', 'min:1', 'max:200'],
+            'sequence' => ['required', 'string', 'min:1'],
+        ]);
+
+        $operations = SortSetOperation::fromSequence($request->input('sequence'));
+        if (count($operations) === 0) {
+            return redirect()->withInput()->withErrors(['sequence' => 'No operations set.']);
+        }
+
+        $set = new SortSet();
+        $set->name = $request->input('name');
+        $set->setOperations($operations);
+        $set->save();
+
+        $this->logActivity(ActivityType::SORT_SET_CREATE, $set);
+
+        return redirect('/settings/sorting');
+    }
+
+    public function edit(string $id)
+    {
+        $set = SortSet::query()->findOrFail($id);
+
+        $this->setPageTitle(trans('settings.sort_set_edit'));
+
+        return view('settings.sort-sets.edit', ['set' => $set]);
+    }
+
+    public function update(string $id, Request $request)
+    {
+        $this->validate($request, [
+            'name' => ['required', 'string', 'min:1', 'max:200'],
+            'sequence' => ['required', 'string', 'min:1'],
+        ]);
+
+        $set = SortSet::query()->findOrFail($id);
+        $operations = SortSetOperation::fromSequence($request->input('sequence'));
+        if (count($operations) === 0) {
+            return redirect()->withInput()->withErrors(['sequence' => 'No operations set.']);
+        }
+
+        $set->name = $request->input('name');
+        $set->setOperations($operations);
+        $set->save();
+
+        $this->logActivity(ActivityType::SORT_SET_UPDATE, $set);
+
+        return redirect('/settings/sorting');
+    }
+
+    public function destroy(string $id)
+    {
+        $set = SortSet::query()->findOrFail($id);
+
+        // TODO - Check if it's in use
+
+        $set->delete();
+        $this->logActivity(ActivityType::SORT_SET_DELETE, $set);
+
+        return redirect('/settings/sorting');
+    }
 }
index 12fda669fbd036e05bb0dd1ccd5eeed816dcb096..a6dd860f5c756acfda872917f52b5cd828bd0f5d 100644 (file)
@@ -39,6 +39,21 @@ enum SortSetOperation: string
     public static function allExcluding(array $operations): array
     {
         $all = SortSetOperation::cases();
-        return array_diff($all, $operations);
+        $filtered = array_filter($all, function (SortSetOperation $operation) use ($operations) {
+            return !in_array($operation, $operations);
+        });
+        return array_values($filtered);
+    }
+
+    /**
+     * Create a set of operations from a string sequence representation.
+     * (values seperated by commas).
+     * @return SortSetOperation[]
+     */
+    public static function fromSequence(string $sequence): array
+    {
+        $strOptions = explode(',', $sequence);
+        $options = array_map(fn ($val) => SortSetOperation::tryFrom($val), $strOptions);
+        return array_filter($options);
     }
 }
index 7c3454d41ca287406316a6eb3f528250c5361c3d..7db872c0ca80c3877820eb9c6fbb9d0729ee5d4d 100644 (file)
@@ -127,6 +127,14 @@ return [
     'comment_update'              => 'updated comment',
     'comment_delete'              => 'deleted comment',
 
+    // Sort Sets
+    'sort_set_create' => 'created sort set',
+    'sort_set_create_notification' => 'Sort set successfully created',
+    'sort_set_update' => 'updated sort set',
+    'sort_set_update_notification' => 'Sort set successfully update',
+    'sort_set_delete' => 'deleted sort set',
+    'sort_set_delete_notification' => 'Sort set successfully deleted',
+
     // Other
     'permissions_update'          => 'updated permissions',
 ];
index 8bb2f6ef481725eee56e46730c97d3ad5e4908dd..cda097590a02f7aa51bedfdc4d49314a8311e44f 100644 (file)
@@ -82,6 +82,8 @@ return [
     'sorting_sets_desc' => 'These are predefined sorting operations which can be applied to content in the system.',
     'sort_set_create' => 'Create Sort Set',
     'sort_set_edit' => 'Edit Sort Set',
+    'sort_set_delete' => 'Delete Sort Set',
+    'sort_set_delete_desc' => 'Remove this sort set from the system. Deletion will only go ahead if the sort is not in active use.',
     'sort_set_details' => 'Sort Set Details',
     'sort_set_details_desc' => 'Set a name for this sort set, which will appear in lists when users are selecting a sort.',
     'sort_set_operations' => 'Sort Operations',
index 9de11bb6f2b69173d57c8094d3e2e0e2a8fb5f12..b5d6138400321afda5bf58bc9baab06142b95924 100644 (file)
             </div>
         </div>
 
-{{--        TODO--}}
+        @php
+            $sortSets = \BookStack\Sorting\SortSet::query()->orderBy('name', 'asc')->get();
+        @endphp
+        @if(empty($sortSets))
+            <p class="italic text-muted">{{ trans('common.no_items') }}</p>
+        @else
+            <div class="item-list">
+                @foreach($sortSets as $set)
+                    @include('settings.sort-sets.parts.sort-set-list-item', ['set' => $set])
+                @endforeach
+            </div>
+        @endif
     </div>
 @endsection
\ No newline at end of file
diff --git a/resources/views/settings/sort-sets/edit.blade.php b/resources/views/settings/sort-sets/edit.blade.php
new file mode 100644 (file)
index 0000000..3b88c12
--- /dev/null
@@ -0,0 +1,44 @@
+@extends('layouts.simple')
+
+@section('body')
+
+    <div class="container small">
+
+        @include('settings.parts.navbar', ['selected' => 'settings'])
+
+        <div class="card content-wrap auto-height">
+            <h1 class="list-heading">{{ trans('settings.sort_set_edit') }}</h1>
+
+            <form action="{{ $set->getUrl() }}" method="POST">
+                {{ method_field('PUT') }}
+                {{ csrf_field() }}
+
+                @include('settings.sort-sets.parts.form', ['model' => $set])
+
+                <div class="form-group text-right">
+                    <a href="{{ url("/settings/sorting") }}" class="button outline">{{ trans('common.cancel') }}</a>
+                    <button type="submit" class="button">{{ trans('common.save') }}</button>
+                </div>
+            </form>
+        </div>
+
+        <div class="card content-wrap auto-height">
+            <div class="flex-container-row items-center gap-l">
+                <div>
+                    <h2 class="list-heading">{{ trans('settings.sort_set_delete') }}</h2>
+                    <p class="text-muted">{{ trans('settings.sort_set_delete_desc') }}</p>
+                </div>
+                <div class="flex">
+                    <form action="{{ $set->getUrl() }}" method="POST">
+                        {{ method_field('DELETE') }}
+                        {{ csrf_field() }}
+                        <div class="text-right">
+                            <button type="submit" class="button outline">{{ trans('common.delete') }}</button>
+                        </div>
+                    </form>
+                </div>
+            </div>
+        </div>
+    </div>
+
+@stop
index 3f22209471fee9576667d3ad84ade7491bbb4a81..38db840ac57646c5783c4581bea12e96ad7834ef 100644 (file)
     <div component="sort-set-manager">
         <label class="setting-list-label">{{ trans('settings.sort_set_operations') }}</label>
         <p class="text-muted text-small">{{ trans('settings.sort_set_operations_desc') }}</p>
+        @include('form.errors', ['name' => 'sequence'])
 
-        <input refs="sort-set-manager@input" type="hidden" name="books"
-               value="{{ $model?->sequence ?? '' }}">
+        <input refs="sort-set-manager@input" type="hidden" name="sequence"
+               value="{{ old('sequence') ?? $model?->sequence ?? '' }}">
+
+        @php
+            $configuredOps = old('sequence') ? \BookStack\Sorting\SortSetOperation::fromSequence(old('sequence')) : ($model?->getOperations() ?? []);
+        @endphp
 
         <div class="grid half">
             <div class="form-group">
@@ -27,8 +32,9 @@
                     aria-labelledby="sort-set-configured-operations"
                     class="scroll-box configured-option-list">
                     <li class="text-muted empty-state px-m py-s italic text-small">{{ trans('settings.sort_set_configured_operations_empty') }}</li>
-                    @foreach(($model?->getOperations() ?? []) as $option)
-                        @include('settings.sort-sets.parts.operation')
+
+                    @foreach($configuredOps as $operation)
+                        @include('settings.sort-sets.parts.operation', ['operation' => $operation])
                     @endforeach
                 </ul>
             </div>
@@ -40,7 +46,7 @@
                     aria-labelledby="sort-set-available-operations"
                     class="scroll-box available-option-list">
                     <li class="text-muted empty-state px-m py-s italic text-small">{{ trans('settings.sort_set_available_operations_empty') }}</li>
-                    @foreach(\BookStack\Sorting\SortSetOperation::allExcluding($model?->getOperations() ?? []) as $operation)
+                    @foreach(\BookStack\Sorting\SortSetOperation::allExcluding($configuredOps) as $operation)
                         @include('settings.sort-sets.parts.operation', ['operation' => $operation])
                     @endforeach
                 </ul>
diff --git a/resources/views/settings/sort-sets/parts/sort-set-list-item.blade.php b/resources/views/settings/sort-sets/parts/sort-set-list-item.blade.php
new file mode 100644 (file)
index 0000000..e5ee1fb
--- /dev/null
@@ -0,0 +1,8 @@
+<div class="item-list-row flex-container-row py-xs items-center">
+    <div class="py-xs px-m flex-2">
+        <a href="{{ $set->getUrl() }}">{{ $set->name }}</a>
+    </div>
+    <div class="px-m text-small text-muted">
+        {{ implode(', ', array_map(fn ($op) => $op->getLabel(), $set->getOperations())) }}
+    </div>
+</div>
\ No newline at end of file