]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
allow sorting notifications
authorRigel Kent <sendmemail@rigelk.eu>
Wed, 15 Jul 2020 09:15:50 +0000 (11:15 +0200)
committerRigel Kent <par@rigelk.eu>
Wed, 29 Jul 2020 16:15:53 +0000 (18:15 +0200)
client/src/app/+my-account/my-account-notifications/my-account-notifications.component.html
client/src/app/+my-account/my-account-notifications/my-account-notifications.component.scss
client/src/app/+my-account/my-account-notifications/my-account-notifications.component.ts
client/src/app/shared/shared-main/users/user-notification.service.ts
client/src/app/shared/shared-main/users/user-notifications.component.ts
client/src/sass/include/_mixins.scss
client/src/sass/primeng-custom.scss
server/initializers/constants.ts

index 8e4480ca66b95d41322d1ca13c0a908a0f447d28..0727f90e88d926171c7e30cfa5240fd54ea69b12 100644 (file)
@@ -5,7 +5,15 @@
     Notification preferences
   </a>
 
-  <button class="btn" [disabled]="!hasUnreadNotifications()" (click)="markAllAsRead()">
+  <div class="peertube-select-container peertube-select-button ml-2">
+    <select [(ngModel)]="notificationSortType" (ngModelChange)="onNotificationSortTypeChanged()" class="form-control">
+      <option value="undefined" disabled>Sort by</option>
+      <option value="created" i18n>Newest first</option>
+      <option value="unread-created" i18n>Unread first</option>
+    </select>
+  </div>
+
+  <button class="btn ml-auto" [disabled]="!hasUnreadNotifications()" (click)="markAllAsRead()">
     <ng-container *ngIf="hasUnreadNotifications()">
       <my-global-icon iconName="inbox-full" aria-hidden="true"></my-global-icon>
 
index 73f7c7b247967dd2141cfa9c5b5d89a70fa0a1be..d586eeb0d724bb4721c6e3930dc9e13580242ab7 100644 (file)
@@ -3,7 +3,6 @@
 
 .header {
   display: flex;
-  justify-content: space-between;
   font-size: 15px;
   margin-bottom: 20px;
 
     @include grey-button;
     @include button-with-icon(20px, 3px, -1px);
   }
+
+  .peertube-select-container {
+    @include peertube-select-container(auto);
+  }
 }
 
+
 my-user-notifications {
   font-size: 15px;
 }
index 0c1427d962e5dc919850650efef31183d2f5aba9..03b91e0504ce20905083dda967ce8467c1dab172 100644 (file)
@@ -8,6 +8,8 @@ import { UserNotificationsComponent } from '@app/shared/shared-main'
 export class MyAccountNotificationsComponent {
   @ViewChild('userNotification', { static: true }) userNotification: UserNotificationsComponent
 
+  notificationSortType = 'created'
+
   markAllAsRead () {
     this.userNotification.markAllAsRead()
   }
@@ -15,4 +17,6 @@ export class MyAccountNotificationsComponent {
   hasUnreadNotifications () {
     return this.userNotification.notifications.filter(n => n.read === false).length !== 0
   }
+
+  onNotificationSortTypeChanged () {}
 }
index 8dd9472fe07a1567622f7f36a4d30ca800e24848..ecc66ecdbb8221c3db89f513640ff5c1a6b23bbe 100644 (file)
@@ -5,6 +5,7 @@ import { ComponentPaginationLight, RestExtractor, RestService, User, UserNotific
 import { ResultList, UserNotification as UserNotificationServer, UserNotificationSetting } from '@shared/models'
 import { environment } from '../../../../environments/environment'
 import { UserNotification } from './user-notification.model'
+import { SortMeta } from 'primeng/api'
 
 @Injectable()
 export class UserNotificationService {
@@ -18,9 +19,16 @@ export class UserNotificationService {
     private userNotificationSocket: UserNotificationSocket
   ) {}
 
-  listMyNotifications (pagination: ComponentPaginationLight, unread?: boolean, ignoreLoadingBar = false) {
+  listMyNotifications (parameters: {
+    pagination: ComponentPaginationLight
+    ignoreLoadingBar?: boolean
+    unread?: boolean,
+    sort?: SortMeta
+  }) {
+    const { pagination, ignoreLoadingBar, unread, sort } = parameters
+
     let params = new HttpParams()
-    params = this.restService.addRestGetParams(params, this.restService.componentPaginationToRestPagination(pagination))
+    params = this.restService.addRestGetParams(params, this.restService.componentPaginationToRestPagination(pagination), sort)
 
     if (unread) params = params.append('unread', `${unread}`)
 
@@ -35,7 +43,7 @@ export class UserNotificationService {
   }
 
   countUnreadNotifications () {
-    return this.listMyNotifications({ currentPage: 1, itemsPerPage: 0 }, true)
+    return this.listMyNotifications({ pagination: { currentPage: 1, itemsPerPage: 0 }, ignoreLoadingBar: true, unread: true })
       .pipe(map(n => n.total))
   }
 
index 6abd8b7d841c1ebd70105dec1a4487fca6a896e0..48be80e3f37f4934f76e8bb18f7ece64339f7c34 100644 (file)
@@ -19,6 +19,7 @@ export class UserNotificationsComponent implements OnInit {
   @Output() notificationsLoaded = new EventEmitter()
 
   notifications: UserNotification[] = []
+  sortField = 'createdAt'
 
   // So we can access it in the template
   UserNotificationType = UserNotificationType
@@ -39,18 +40,25 @@ export class UserNotificationsComponent implements OnInit {
       totalItems: null
     }
 
-    this.loadMoreNotifications()
+    this.loadNotifications()
 
     if (this.markAllAsReadSubject) {
       this.markAllAsReadSubject.subscribe(() => this.markAllAsRead())
     }
   }
 
-  loadMoreNotifications () {
-    this.userNotificationService.listMyNotifications(this.componentPagination, undefined, this.ignoreLoadingBar)
+  loadNotifications (reset?: boolean) {
+    this.userNotificationService.listMyNotifications({
+      pagination: this.componentPagination,
+      ignoreLoadingBar: this.ignoreLoadingBar,
+      sort: {
+        field: this.sortField,
+        order: this.sortField === 'createdAt' ? -1 : 1
+      }
+    })
         .subscribe(
           result => {
-            this.notifications = this.notifications.concat(result.data)
+            this.notifications = reset ? result.data : this.notifications.concat(result.data)
             this.componentPagination.totalItems = result.total
 
             this.notificationsLoaded.emit()
@@ -68,7 +76,7 @@ export class UserNotificationsComponent implements OnInit {
     this.componentPagination.currentPage++
 
     if (hasMoreItems(this.componentPagination)) {
-      this.loadMoreNotifications()
+      this.loadNotifications()
     }
   }
 
@@ -97,4 +105,14 @@ export class UserNotificationsComponent implements OnInit {
           err => this.notifier.error(err.message)
         )
   }
+
+  changeSortColumn (column: string) {
+    this.componentPagination = {
+      currentPage: 1,
+      itemsPerPage: this.itemsPerPage,
+      totalItems: null
+    }
+    this.sortField = column
+    this.loadNotifications(true)
+  }
 }
index 3471d694ca17a3c2041e5631dfcde055ffc0a861..2de5ce7f159993cd6635a9ca353dab72aa9d0416 100644 (file)
       color: #000;
     }
   }
+
+  &.peertube-select-button {
+    @include grey-button;
+
+    select,
+    option {
+      font-weight: $font-semibold;
+      color: pvar(--greyForegroundColor);
+      border: none;
+    }
+  }
 }
 
 // Thanks: https://codepen.io/triss90/pen/XNEdRe/
   }
 }
 
+@mixin table-badge {
+  border-radius: 2px;
+  padding: 1/4em 1/2em;
+  text-transform: uppercase;
+  font-weight: $font-bold;
+  font-size: 12px;
+  letter-spacing: 1/3px;
+
+  &.badge-banned,
+  &.badge-red {
+    background-color: #ffcdd2;
+    color: #c63737;
+  }
+
+  &.badge-banned {
+    text-decoration: line-through;
+  }
+
+  &.badge-yellow {
+    background-color: #feedaf;
+    color: #8a5340;
+  }
+
+  &.badge-brown {
+    background-color: #ffd8b2;
+    color: #805b36;
+  }
+
+  &.badge-green {
+    background-color: #c8e6c9;
+    color: #256029;
+  }
+
+  &.badge-blue {
+    background-color: #b3e5fc;
+    color: #23547b;
+  }
+
+  &.badge-purple {
+    background-color: #eccfff;
+    color: #694382;
+  }
+}
 
 @mixin avatar ($size) {
   object-fit: cover;
   overflow: hidden;
   font-size: 0.75rem;
   border-radius: 0.25rem;
+  color: gray;
 
   .progress-bar {
     color: pvar(--mainBackgroundColor);
     text-align: center;
     white-space: nowrap;
     transition: width 0.6s ease;
+    isolation: isolate;
+
+    &:after {
+      content: attr(valuenow-formatted);
+      position: absolute;
+      margin-left: .2rem;
+      mix-blend-mode: screen;
+      color: gray;
+    }
 
     &.secondary {
       background-color: pvar(--secondaryColor);
     }
   }
+
+  .progress-bar + span {
+    position: relative;
+    top: -1px;
+  }
 }
 
 @mixin breadcrumb {
index 2388c0469beda6174da3d3e4b7c22557181b0257..bf49639f56dc9ff98064acbc393ac9b808e680fa 100644 (file)
@@ -92,6 +92,11 @@ p-table {
       &:last-child td {
         border-bottom: none !important;
       }
+
+      &:focus + tr > td,
+      &:focus > td {
+        box-shadow: none !important;
+      }
     }
 
     .expander {
index 2e9d3956ea52e88c4cefe2ce8806d004bb397eb6..fd5bf58685e1cf82d3973b5e92dcf1b40358c356 100644 (file)
@@ -55,7 +55,7 @@ const WEBSERVER = {
 
 // Sortable columns per schema
 const SORTABLE_COLUMNS = {
-  USERS: [ 'id', 'username', 'videoQuotaUsed', 'createdAt' ],
+  USERS: [ 'id', 'username', 'videoQuotaUsed', 'createdAt', 'lastLoginDate', 'role' ],
   USER_SUBSCRIPTIONS: [ 'id', 'createdAt' ],
   ACCOUNTS: [ 'createdAt' ],
   JOBS: [ 'createdAt' ],
@@ -78,7 +78,7 @@ const SORTABLE_COLUMNS = {
   ACCOUNTS_BLOCKLIST: [ 'createdAt' ],
   SERVERS_BLOCKLIST: [ 'createdAt' ],
 
-  USER_NOTIFICATIONS: [ 'createdAt' ],
+  USER_NOTIFICATIONS: [ 'createdAt', 'read' ],
 
   VIDEO_PLAYLISTS: [ 'displayName', 'createdAt', 'updatedAt' ],