allow sorting notifications

pull/3023/head
Rigel Kent 2020-07-15 11:15:50 +02:00 committed by Rigel Kent
parent 292c17b894
commit 654a188f80
8 changed files with 128 additions and 12 deletions

View 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>

View File

@ -3,7 +3,6 @@
.header {
display: flex;
justify-content: space-between;
font-size: 15px;
margin-bottom: 20px;
@ -18,8 +17,13 @@
@include grey-button;
@include button-with-icon(20px, 3px, -1px);
}
.peertube-select-container {
@include peertube-select-container(auto);
}
}
my-user-notifications {
font-size: 15px;
}

View 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 () {}
}

View 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))
}

View 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)
}
}

View File

@ -356,6 +356,17 @@
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/
@ -454,6 +465,49 @@
}
}
@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;
@ -638,6 +692,7 @@
overflow: hidden;
font-size: 0.75rem;
border-radius: 0.25rem;
color: gray;
.progress-bar {
color: pvar(--mainBackgroundColor);
@ -648,11 +703,25 @@
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 {

View File

@ -92,6 +92,11 @@ p-table {
&:last-child td {
border-bottom: none !important;
}
&:focus + tr > td,
&:focus > td {
box-shadow: none !important;
}
}
.expander {

View 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' ],