]> BookStack Code Mirror - bookstack/commitdiff
Redesigned users list to be responsive and aligned
authorDan Brown <redacted>
Sat, 29 Oct 2022 14:23:21 +0000 (15:23 +0100)
committerDan Brown <redacted>
Sat, 29 Oct 2022 14:23:21 +0000 (15:23 +0100)
13 files changed:
app/Auth/Queries/AllUsersPaginatedAndSorted.php
app/Http/Controllers/UserController.php
resources/js/components/entity-permissions.js
resources/lang/en/settings.php
resources/sass/_components.scss
resources/sass/_layout.scss
resources/views/books/parts/list.blade.php
resources/views/common/sort.blade.php [moved from resources/views/entities/sort.blade.php with 100% similarity]
resources/views/form/entity-permissions-row.blade.php
resources/views/form/entity-permissions.blade.php
resources/views/shelves/parts/list.blade.php
resources/views/shelves/show.blade.php
resources/views/users/index.blade.php

index 7b849eaf4c1af9f84036cf8eeb1aa24f89716836..29e58fe096babee0125a4ddc0d5c66c2b64e6c7e 100644 (file)
@@ -19,6 +19,9 @@ class AllUsersPaginatedAndSorted
     public function run(int $count, array $sortData): LengthAwarePaginator
     {
         $sort = $sortData['sort'];
+        if ($sort === 'created_at') {
+            $sort = 'users.created_at';
+        }
 
         $query = User::query()->select(['*'])
             ->scopes(['withLastActivityAt'])
index 895481d02405305c80198541883613941a69a13a..9b089c29a36befa8279836aa0671389f061f36d3 100644 (file)
@@ -37,15 +37,15 @@ class UserController extends Controller
     {
         $this->checkPermission('users-manage');
         $listDetails = [
-            'order'  => $request->get('order', 'asc'),
             'search' => $request->get('search', ''),
-            'sort'   => $request->get('sort', 'name'),
+            'sort'   => setting()->getForCurrentUser('users_sort', 'name'),
+            'order'  => setting()->getForCurrentUser('users_sort_order', 'asc'),
         ];
 
         $users = (new AllUsersPaginatedAndSorted())->run(20, $listDetails);
 
         $this->setPageTitle(trans('settings.users'));
-        $users->appends($listDetails);
+        $users->appends(['search' => $listDetails['search']]);
 
         return view('users.index', [
             'users'       => $users,
@@ -251,7 +251,7 @@ class UserController extends Controller
      */
     public function changeSort(Request $request, string $id, string $type)
     {
-        $validSortTypes = ['books', 'bookshelves', 'shelf_books'];
+        $validSortTypes = ['books', 'bookshelves', 'shelf_books', 'users'];
         if (!in_array($type, $validSortTypes)) {
             return redirect()->back(500);
         }
@@ -318,7 +318,7 @@ class UserController extends Controller
         $this->checkPermissionOrCurrentUser('users-manage', $userId);
 
         $sort = $request->get('sort');
-        if (!in_array($sort, ['name', 'created_at', 'updated_at', 'default'])) {
+        if (!in_array($sort, ['name', 'created_at', 'updated_at', 'default', 'email', 'last_activity_at'])) {
             $sort = 'name';
         }
 
index c67c85f19a699ef43fad99c7d300b6f4b8851b58..0dec5ca0937dda6620122628e5aef22b5ccd8013 100644 (file)
@@ -62,7 +62,7 @@ class EntityPermissions {
     }
 
     removeRowOnButtonClick(button) {
-        const row = button.closest('.content-permissions-row');
+        const row = button.closest('.item-list-row');
         const roleId = button.dataset.roleId;
         const roleName = button.dataset.roleName;
 
index 1ad271e7c9ebd736f1d283bc2884b756294ea56d..d4d6d3bae7cb1013ec885636f3f4c8279e202eb5 100755 (executable)
@@ -172,6 +172,7 @@ return [
 
     // Users
     'users' => 'Users',
+    'users_index_desc' => 'Create & manage individual user accounts within the system. User accounts are used for login and attribution of content & activity. Access permissions are primarily role-based but user content ownership, among other factors, may also affect permissions & access.',
     'user_profile' => 'User Profile',
     'users_add_new' => 'Add New User',
     'users_search' => 'Search Users',
index 9fdd5a6117eb2b650965603bc2fac4159bc717db..667c2638864bd13d09459739af156dd42fd9eeee 100644 (file)
@@ -798,37 +798,6 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
   max-width: 500px;
 }
 
-.content-permissions {
-  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
-}
-.content-permissions-row {
-  border: 1.5px solid;
-  @include lightDark(border-color, #E2E2E2, #444);
-  border-bottom-width: 0;
-  label {
-    padding-bottom: 0;
-  }
-  &:hover {
-    @include lightDark(background-color, #F2F2F2, #333);
-  }
-}
-.content-permissions-row:first-child {
-  border-radius: 4px 4px 0 0;
-}
-.content-permissions-row:last-child {
-  border-radius: 0 0 4px 4px;
-  border-bottom-width: 1.5px;
-}
-.content-permissions-row:first-child:last-child {
-  border-radius: 4px;
-}
-.content-permissions-row-toggle-all {
-  visibility: hidden;
-}
-.content-permissions-row:hover .content-permissions-row-toggle-all {
-  visibility: visible;
-}
-
 .template-item {
   cursor: pointer;
   position: relative;
@@ -969,4 +938,35 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
   .dropdown-search-dropdown .dropdown-search-list {
     max-height: 240px;
   }
+}
+
+.item-list {
+  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
+}
+.item-list-row {
+  border: 1.5px solid;
+  @include lightDark(border-color, #E2E2E2, #444);
+  border-bottom-width: 0;
+  label {
+    padding-bottom: 0;
+  }
+  &:hover {
+    @include lightDark(background-color, #F6F6F6, #333);
+  }
+}
+.item-list-row:first-child {
+  border-radius: 4px 4px 0 0;
+}
+.item-list-row:last-child {
+  border-radius: 0 0 4px 4px;
+  border-bottom-width: 1.5px;
+}
+.item-list-row:first-child:last-child {
+  border-radius: 4px;
+}
+.item-list-row-toggle-all {
+  visibility: hidden;
+}
+.item-list-row:hover .item-list-row-toggle-all {
+  visibility: visible;
 }
\ No newline at end of file
index cfb8397c99207e4ba3a436ed35c556c39caab22f..d4413d32c493cd4694a7401022dd0c855bb0eb4e 100644 (file)
@@ -158,6 +158,18 @@ body.flexbox {
   }
 }
 
+.flex-2 {
+  min-height: 0;
+  flex: 2;
+  max-width: 100%;
+}
+
+.flex-3 {
+  min-height: 0;
+  flex: 3;
+  max-width: 100%;
+}
+
 .flex-none {
   flex: none;
 }
@@ -178,6 +190,27 @@ body.flexbox {
   align-items: center;
 }
 
+/**
+ * Min width utilities
+ */
+.min-width-xs {
+  min-width: 120px;
+}
+.min-width-s {
+  min-width: 160px;
+}
+.min-width-m {
+  min-width: 200px;
+}
+.min-width-l {
+  min-width: 240px;
+}
+.min-width-xl {
+  min-width: 280px;
+}
+.min-width-xxl {
+  min-width: 320px;
+}
 
 /**
  * Display and float utilities
index 30b0766135ccff81c87fb2d3fa7c1a5ba9d2de4a..79d0554c5f77c620fd974dddb23efe2fbeba6321 100644 (file)
@@ -3,7 +3,7 @@
         <h1 class="list-heading">{{ trans('entities.books') }}</h1>
         <div class="text-m-right my-m">
 
-            @include('entities.sort', ['options' => [
+            @include('common.sort', ['options' => [
                 'name' => trans('common.sort_name'),
                 'created_at' => trans('common.sort_created_at'),
                 'updated_at' => trans('common.sort_updated_at'),
                 @endforeach
             </div>
         @else
-             <div class="grid third">
+            <div class="grid third">
                 @foreach($books as $key => $book)
                     @include('entities.grid-item', ['entity' => $book])
                 @endforeach
-             </div>
+            </div>
         @endif
         <div>
             {!! $books->render() !!}
index d2e6a475631ce6a9becada220d9d4c0b8403ccd0..d4c6c4ac12216c4df9c7cb596e50042a7e105dfa 100644 (file)
@@ -5,7 +5,7 @@ $permission - The entity permission containing the permissions.
 $inheriting - Boolean if the current row should be marked as inheriting default permissions. Used for "Everyone Else" role.
 --}}
 
-<div component="permissions-table" class="content-permissions-row flex-container-row justify-space-between wrap">
+<div component="permissions-table" class="item-list-row flex-container-row justify-space-between wrap">
     <div class="gap-x-m flex-container-row items-center px-l py-m flex">
         <div class="text-large" title="{{ $role->id === 0 ? trans('entities.permissions_role_everyone_else') : trans('common.role') }}">
             @icon($role->id === 0 ? 'groups' : 'role')
@@ -16,7 +16,7 @@ $inheriting - Boolean if the current row should be marked as inheriting default
         </span>
         @if($role->id !== 0)
             <button type="button"
-                class="ml-auto flex-none text-small text-primary text-button hover-underline content-permissions-row-toggle-all hide-under-s"
+                class="ml-auto flex-none text-small text-primary text-button hover-underline item-list-row-toggle-all hide-under-s"
                 refs="permissions-table@toggle-all"
                 ><strong>{{ trans('common.toggle_all') }}</strong></button>
         @endif
index 724d0fb393658b4f5152331d8ba3117d4386ca2b..9bf309fb802952f16f9dabee3f076006087cac63 100644 (file)
@@ -35,7 +35,7 @@
 
     <hr>
 
-    <div refs="entity-permissions@role-container" class="content-permissions mt-m mb-m">
+    <div refs="entity-permissions@role-container" class="item-list mt-m mb-m">
         @foreach($data->permissionsWithRoles() as $permission)
             @include('form.entity-permissions-row', [
                 'permission' => $permission,
@@ -58,7 +58,7 @@
         </div>
     </div>
 
-    <div class="content-permissions mt-m mb-xl">
+    <div class="item-list mt-m mb-xl">
         @include('form.entity-permissions-row', [
                 'role' => $data->everyoneElseRole(),
                 'permission' => $data->everyoneElseEntityPermission(),
index d78606ac700e081818d7c183e880116692a6b938..4c841db648827dfe82942f7d4e86e6b6c6f23653 100644 (file)
@@ -1,10 +1,9 @@
-
 <main class="content-wrap mt-m card">
 
     <div class="grid half v-center">
         <h1 class="list-heading">{{ trans('entities.shelves') }}</h1>
         <div class="text-right">
-            @include('entities.sort', ['options' => $sortOptions, 'order' => $order, 'sort' => $sort, 'type' => 'bookshelves'])
+            @include('common.sort', ['options' => $sortOptions, 'order' => $order, 'sort' => $sort, 'type' => 'bookshelves'])
         </div>
     </div>
 
@@ -31,7 +30,8 @@
     @else
         <p class="text-muted">{{ trans('entities.shelves_empty') }}</p>
         @if(userCan('bookshelf-create-all'))
-            <a href="{{ url("/create-shelf") }}" class="button outline">@icon('edit'){{ trans('entities.create_now') }}</a>
+            <a href="{{ url("/create-shelf") }}"
+               class="button outline">@icon('edit'){{ trans('entities.create_now') }}</a>
         @endif
     @endif
 
index 37d2889563063be922a8683d60ee655787bcf7df..fe11ccfced54f6ea0ce4f9b40ef09bc3de50704b 100644 (file)
@@ -23,7 +23,7 @@
             <h1 class="flex fit-content break-text">{{ $shelf->name }}</h1>
             <div class="flex"></div>
             <div class="flex fit-content text-m-right my-m ml-m">
-                @include('entities.sort', ['options' => [
+                @include('common.sort', ['options' => [
                     'default' => trans('common.sort_default'),
                     'name' => trans('common.sort_name'),
                     'created_at' => trans('common.sort_created_at'),
index 03eae2c005a660e3e61edd6d1d236a7b5723df8b..daa41d7d7873634d32524befa0fd162572abc322 100644 (file)
@@ -9,37 +9,37 @@
 
             <div class="flex-container-row wrap justify-space-between items-center">
                 <h1 class="list-heading">{{ trans('settings.users') }}</h1>
+                <div>
+                    <a href="{{ url("/settings/users/create") }}" class="outline button mt-none">{{ trans('settings.users_add_new') }}</a>
+                </div>
+            </div>
+
+            <p class="text-muted">{{ trans('settings.users_index_desc') }}</p>
 
+            <div class="flex-container-row items-center justify-space-between gap-m mt-m mb-l wrap">
                 <div>
                     <div class="block inline mr-xs">
                         <form method="get" action="{{ url("/settings/users") }}">
-                            @foreach(collect($listDetails)->except('search') as $name => $val)
-                                <input type="hidden" name="{{ $name }}" value="{{ $val }}">
-                            @endforeach
                             <input type="text" name="search" placeholder="{{ trans('settings.users_search') }}" @if($listDetails['search']) value="{{$listDetails['search']}}" @endif>
                         </form>
                     </div>
-                    <a href="{{ url("/settings/users/create") }}" class="outline button mt-none">{{ trans('settings.users_add_new') }}</a>
+                </div>
+                <div class="justify-flex-end">
+                    @include('common.sort', ['options' => [
+                        'name' => trans('common.sort_name'),
+                        'email' => trans('auth.email'),
+                        'created_at' => trans('common.sort_created_at'),
+                        'updated_at' => trans('common.sort_updated_at'),
+                        'last_activity_at' => trans('settings.users_latest_activity'),
+                    ], 'order' => $listDetails['order'], 'sort' => $listDetails['sort'], 'type' => 'users'])
                 </div>
             </div>
 
-            <table class="table">
-                <tr>
-                    <th width="9%"></th>
-                    <th width="36%">
-                        <a href="{{ sortUrl('/settings/users', $listDetails, ['sort' => 'name']) }}">{{ trans('auth.name') }}</a>
-                        /
-                        <a href="{{ sortUrl('/settings/users', $listDetails, ['sort' => 'email']) }}">{{ trans('auth.email') }}</a>
-                    </th>
-                    <th width="35%">{{ trans('settings.role_user_roles') }}</th>
-                    <th class="text-right" width="20%">
-                        <a href="{{ sortUrl('/settings/users', $listDetails, ['sort' => 'last_activity_at']) }}">{{ trans('settings.users_latest_activity') }}</a>
-                    </th>
-                </tr>
+            <div class="item-list">
                 @foreach($users as $user)
-                    <tr>
-                        <td class="text-center" style="line-height: 0;"><img class="avatar med" src="{{ $user->getAvatar(40)}}" alt="{{ $user->name }}"></td>
-                        <td>
+                    <div class="flex-container-row item-list-row items-center wrap py-s">
+                        <div class="px-m py-xs flex-container-row items-center flex-2 gap-l min-width-m">
+                            <img class="avatar med" width="40" height="40" src="{{ $user->getAvatar(40)}}" alt="{{ $user->name }}">
                             <a href="{{ url("/settings/users/{$user->id}") }}">
                                 {{ $user->name }}
                                 <br>
                                     <span title="MFA Configured" class="text-pos">@icon('lock')</span>
                                 @endif
                             </a>
-                        </td>
-                        <td>
-                            @foreach($user->roles as $index => $role)
-                                <small><a href="{{ url("/settings/roles/{$role->id}") }}">{{$role->display_name}}</a>@if($index !== count($user->roles) -1),@endif</small>
-                            @endforeach
-                        </td>
-                        <td class="text-right text-muted">
-                            @if($user->last_activity_at)
-                                <small title="{{ $user->last_activity_at->format('Y-m-d H:i:s') }}">{{ $user->last_activity_at->diffForHumans() }}</small>
-                            @endif
-                        </td>
-                    </tr>
+                        </div>
+                        <div class="flex-container-row items-center flex-3 min-width-m">
+                            <div class="px-m py-xs flex">
+                                @foreach($user->roles as $index => $role)
+                                    <small><a href="{{ url("/settings/roles/{$role->id}") }}">{{$role->display_name}}</a>@if($index !== count($user->roles) -1),@endif</small>
+                                @endforeach
+                            </div>
+                            <div class="px-m py-xs flex text-right text-muted">
+                                @if($user->last_activity_at)
+                                    <small>{{ trans('settings.users_latest_activity') }}</small>
+                                    <br>
+                                    <small title="{{ $user->last_activity_at->format('Y-m-d H:i:s') }}">{{ $user->last_activity_at->diffForHumans() }}</small>
+                                @endif
+                            </div>
+                        </div>
+                    </div>
                 @endforeach
-            </table>
+            </div>
 
             <div>
                 {{ $users->links() }}