mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Updated view toggle to store date
Also added test for user list order preferences
This commit is contained in:
parent
01be72d5e2
commit
9406b4d4c9
@ -299,7 +299,6 @@ class UserController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function changeSort(string $id, string $type, Request $request)
|
public function changeSort(string $id, string $type, Request $request)
|
||||||
{
|
{
|
||||||
// TODO - Test this endpoint
|
|
||||||
$validSortTypes = ['books', 'bookshelves'];
|
$validSortTypes = ['books', 'bookshelves'];
|
||||||
if (!in_array($type, $validSortTypes)) {
|
if (!in_array($type, $validSortTypes)) {
|
||||||
return redirect()->back(500);
|
return redirect()->back(500);
|
||||||
@ -307,6 +306,28 @@ class UserController extends Controller
|
|||||||
return $this->changeListSort($id, $request, $type);
|
return $this->changeListSort($id, $request, $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the stored section expansion preference for the given user.
|
||||||
|
* @param string $id
|
||||||
|
* @param string $key
|
||||||
|
* @param Request $request
|
||||||
|
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
|
||||||
|
*/
|
||||||
|
public function updateExpansionPreference(string $id, string $key, Request $request)
|
||||||
|
{
|
||||||
|
$this->checkPermissionOrCurrentUser('users-manage', $id);
|
||||||
|
$keyWhitelist = ['home-details'];
|
||||||
|
if (!in_array($key, $keyWhitelist)) {
|
||||||
|
return response("Invalid key", 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
$newState = $request->get('expand', 'false');
|
||||||
|
|
||||||
|
$user = $this->user->findOrFail($id);
|
||||||
|
setting()->putUser($user, 'section_expansion#' . $key, $newState);
|
||||||
|
return response("", 204);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changed the stored preference for a list sort order.
|
* Changed the stored preference for a list sort order.
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
|
@ -67,6 +67,17 @@ class SettingService
|
|||||||
return $this->get($this->userKey($user->id, $key), $default);
|
return $this->get($this->userKey($user->id, $key), $default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a value for the current logged-in user.
|
||||||
|
* @param $key
|
||||||
|
* @param bool $default
|
||||||
|
* @return bool|string
|
||||||
|
*/
|
||||||
|
public function getForCurrentUser($key, $default = false)
|
||||||
|
{
|
||||||
|
return $this->getUser(auth()->user(), $key, $default);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a setting value from the cache or database.
|
* Gets a setting value from the cache or database.
|
||||||
* Looks at the system defaults if not cached or in database.
|
* Looks at the system defaults if not cached or in database.
|
||||||
|
@ -3,8 +3,13 @@ class ExpandToggle {
|
|||||||
|
|
||||||
constructor(elem) {
|
constructor(elem) {
|
||||||
this.elem = elem;
|
this.elem = elem;
|
||||||
this.isOpen = false;
|
|
||||||
|
// Component state
|
||||||
|
this.isOpen = elem.getAttribute('expand-toggle-is-open') === 'yes';
|
||||||
|
this.updateEndpoint = elem.getAttribute('expand-toggle-update-endpoint');
|
||||||
this.selector = elem.getAttribute('expand-toggle');
|
this.selector = elem.getAttribute('expand-toggle');
|
||||||
|
|
||||||
|
// Listener setup
|
||||||
elem.addEventListener('click', this.click.bind(this));
|
elem.addEventListener('click', this.click.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,11 +58,20 @@ class ExpandToggle {
|
|||||||
|
|
||||||
click(event) {
|
click(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let matchingElems = document.querySelectorAll(this.selector);
|
|
||||||
for (let i = 0, len = matchingElems.length; i < len; i++) {
|
const matchingElems = document.querySelectorAll(this.selector);
|
||||||
this.isOpen ? this.close(matchingElems[i]) : this.open(matchingElems[i]);
|
for (let match of matchingElems) {
|
||||||
|
this.isOpen ? this.close(match) : this.open(match);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isOpen = !this.isOpen;
|
this.isOpen = !this.isOpen;
|
||||||
|
this.updateSystemAjax(this.isOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSystemAjax(isOpen) {
|
||||||
|
window.$http.patch(this.updateEndpoint, {
|
||||||
|
expand: isOpen ? 'true' : 'false'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
@include('partials.custom-styles')
|
@include('partials.custom-styles')
|
||||||
@include('partials.custom-head')
|
@include('partials.custom-head')
|
||||||
|
|
||||||
|
@stack('head')
|
||||||
</head>
|
</head>
|
||||||
<body class="@yield('body-class')">
|
<body class="@yield('body-class')">
|
||||||
|
|
||||||
|
@ -9,10 +9,7 @@
|
|||||||
<h5>{{ trans('common.actions') }}</h5>
|
<h5>{{ trans('common.actions') }}</h5>
|
||||||
<div class="icon-list text-primary">
|
<div class="icon-list text-primary">
|
||||||
@include('partials.view-toggle', ['view' => $view, 'type' => 'book'])
|
@include('partials.view-toggle', ['view' => $view, 'type' => 'book'])
|
||||||
<a expand-toggle=".entity-list.compact .entity-item-snippet" class="icon-list-item">
|
@include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
|
||||||
<span>@icon('expand-text')</span>
|
|
||||||
<span>{{ trans('common.toggle_details') }}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -8,10 +8,7 @@
|
|||||||
<div class="actions mb-xl">
|
<div class="actions mb-xl">
|
||||||
<h5>{{ trans('common.actions') }}</h5>
|
<h5>{{ trans('common.actions') }}</h5>
|
||||||
<div class="icon-list text-primary">
|
<div class="icon-list text-primary">
|
||||||
<a expand-toggle=".entity-list.compact .entity-item-snippet" class="icon-list-item">
|
@include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
|
||||||
<span>@icon('expand-text')</span>
|
|
||||||
<span>{{ trans('common.toggle_details') }}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -9,10 +9,7 @@
|
|||||||
<h5>{{ trans('common.actions') }}</h5>
|
<h5>{{ trans('common.actions') }}</h5>
|
||||||
<div class="icon-list text-primary">
|
<div class="icon-list text-primary">
|
||||||
@include('partials.view-toggle', ['view' => $view, 'type' => 'shelf'])
|
@include('partials.view-toggle', ['view' => $view, 'type' => 'shelf'])
|
||||||
<a expand-toggle=".entity-list.compact .entity-item-snippet" class="icon-list-item">
|
@include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
|
||||||
<span>@icon('expand-text')</span>
|
|
||||||
<span>{{ trans('common.toggle_details') }}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
@extends('simple-layout')
|
@extends('simple-layout')
|
||||||
|
|
||||||
|
|
||||||
@section('body')
|
@section('body')
|
||||||
|
|
||||||
<div class="container px-xl py-l">
|
<div class="container px-xl py-s">
|
||||||
<a expand-toggle=".entity-list.compact .entity-item-snippet" class="text-muted">@icon('expand-text'){{ trans('common.toggle_details') }}</a>
|
<div class="icon-list inline block">
|
||||||
|
@include('components.expand-toggle', ['target' => '.entity-list.compact .entity-item-snippet', 'key' => 'home-details'])
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container" id="home-default">
|
<div class="container" id="home-default">
|
||||||
|
19
resources/views/components/expand-toggle.blade.php
Normal file
19
resources/views/components/expand-toggle.blade.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{{--
|
||||||
|
$target - CSS selector of items to expand
|
||||||
|
$key - Unique key for checking existing stored state.
|
||||||
|
--}}
|
||||||
|
<?php $isOpen = setting()->getForCurrentUser('section_expansion#'. $key); ?>
|
||||||
|
<a expand-toggle="{{ $target }}"
|
||||||
|
expand-toggle-update-endpoint="{{ baseUrl('/settings/users/'. auth()->user()->id .'/update-expansion-preference/' . $key) }}"
|
||||||
|
expand-toggle-is-open="{{ $isOpen ? 'yes' : 'no' }}"
|
||||||
|
class="text-muted icon-list-item text-primary">
|
||||||
|
<span>@icon('expand-text')</span>
|
||||||
|
<span>{{ trans('common.toggle_details') }}</span>
|
||||||
|
</a>
|
||||||
|
@if($isOpen)
|
||||||
|
@push('head')
|
||||||
|
<style>
|
||||||
|
{{ $target }} {display: block;}
|
||||||
|
</style>
|
||||||
|
@endpush
|
||||||
|
@endif
|
@ -177,6 +177,7 @@ Route::group(['middleware' => 'auth'], function () {
|
|||||||
Route::patch('/users/{id}/switch-book-view', 'UserController@switchBookView');
|
Route::patch('/users/{id}/switch-book-view', 'UserController@switchBookView');
|
||||||
Route::patch('/users/{id}/switch-shelf-view', 'UserController@switchShelfView');
|
Route::patch('/users/{id}/switch-shelf-view', 'UserController@switchShelfView');
|
||||||
Route::patch('/users/{id}/change-sort/{type}', 'UserController@changeSort');
|
Route::patch('/users/{id}/change-sort/{type}', 'UserController@changeSort');
|
||||||
|
Route::patch('/users/{id}/update-expansion-preference/{key}', 'UserController@updateExpansionPreference');
|
||||||
Route::post('/users/create', 'UserController@store');
|
Route::post('/users/create', 'UserController@store');
|
||||||
Route::get('/users/{id}', 'UserController@edit');
|
Route::get('/users/{id}', 'UserController@edit');
|
||||||
Route::put('/users/{id}', 'UserController@update');
|
Route::put('/users/{id}', 'UserController@update');
|
||||||
|
76
tests/UserPreferencesTest.php
Normal file
76
tests/UserPreferencesTest.php
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<?php namespace Tests;
|
||||||
|
|
||||||
|
class UserPreferencesTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function test_update_sort_preference()
|
||||||
|
{
|
||||||
|
$editor = $this->getEditor();
|
||||||
|
$this->actingAs($editor);
|
||||||
|
|
||||||
|
$updateRequest = $this->patch('/settings/users/' . $editor->id.'/change-sort/books', [
|
||||||
|
'sort' => 'created_at',
|
||||||
|
'order' => 'desc'
|
||||||
|
]);
|
||||||
|
$updateRequest->assertStatus(302);
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('settings', [
|
||||||
|
'setting_key' => 'user:' . $editor->id . ':books_sort',
|
||||||
|
'value' => 'created_at'
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('settings', [
|
||||||
|
'setting_key' => 'user:' . $editor->id . ':books_sort_order',
|
||||||
|
'value' => 'desc'
|
||||||
|
]);
|
||||||
|
$this->assertEquals('created_at', setting()->getForCurrentUser('books_sort'));
|
||||||
|
$this->assertEquals('desc', setting()->getForCurrentUser('books_sort_order'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update_sort_preference_defaults()
|
||||||
|
{
|
||||||
|
$editor = $this->getEditor();
|
||||||
|
$this->actingAs($editor);
|
||||||
|
|
||||||
|
$updateRequest = $this->patch('/settings/users/' . $editor->id.'/change-sort/bookshelves', [
|
||||||
|
'sort' => 'cat',
|
||||||
|
'order' => 'dog'
|
||||||
|
]);
|
||||||
|
$updateRequest->assertStatus(302);
|
||||||
|
|
||||||
|
$this->assertEquals('name', setting()->getForCurrentUser('bookshelves_sort'));
|
||||||
|
$this->assertEquals('asc', setting()->getForCurrentUser('bookshelves_sort_order'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update_sort_bad_entity_type_handled()
|
||||||
|
{
|
||||||
|
$editor = $this->getEditor();
|
||||||
|
$this->actingAs($editor);
|
||||||
|
|
||||||
|
$updateRequest = $this->patch('/settings/users/' . $editor->id.'/change-sort/dogs', [
|
||||||
|
'sort' => 'name',
|
||||||
|
'order' => 'asc'
|
||||||
|
]);
|
||||||
|
$updateRequest->assertStatus(500);
|
||||||
|
|
||||||
|
$this->assertNotEmpty('name', setting()->getForCurrentUser('bookshelves_sort'));
|
||||||
|
$this->assertNotEmpty('asc', setting()->getForCurrentUser('bookshelves_sort_order'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update_expansion_preference()
|
||||||
|
{
|
||||||
|
$editor = $this->getEditor();
|
||||||
|
$this->actingAs($editor);
|
||||||
|
|
||||||
|
$updateRequest = $this->patch('/settings/users/' . $editor->id.'/update-expansion-preference/home-details', ['expand' => 'true']);
|
||||||
|
$updateRequest->assertStatus(204);
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('settings', [
|
||||||
|
'setting_key' => 'user:' . $editor->id . ':section_expansion#home-details',
|
||||||
|
'value' => 'true'
|
||||||
|
]);
|
||||||
|
$this->assertEquals(true, setting()->getForCurrentUser('section_expansion#home-details'));
|
||||||
|
|
||||||
|
$invalidKeyRequest = $this->patch('/settings/users/' . $editor->id.'/update-expansion-preference/my-home-details', ['expand' => 'true']);
|
||||||
|
$invalidKeyRequest->assertStatus(500);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user