From ab998f7b6dffbe461d830d3696cb46491ad6afb0 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 23 Feb 2018 14:36:16 +0100 Subject: [PATCH] Improve admin tables --- CHANGELOG.md | 1 + client/src/app/+admin/admin.module.ts | 4 +- .../followers-list.component.html | 35 ++++++++---- .../followers-list.component.ts | 8 ++- .../following-list.component.html | 38 ++++++++----- .../following-list.component.ts | 8 ++- .../jobs/jobs-list/jobs-list.component.html | 52 ++++++++++++----- .../jobs/jobs-list/jobs-list.component.ts | 22 +++++++- .../users/user-list/user-list.component.html | 44 +++++++++------ .../users/user-list/user-list.component.ts | 10 +++- .../video-abuse-list.component.html | 37 +++++++----- .../video-abuse-list.component.ts | 8 +-- .../video-blacklist-list.component.html | 56 +++++++++++-------- .../video-blacklist-list.component.ts | 8 +-- .../shared/misc/delete-button.component.html | 2 +- .../shared/misc/delete-button.component.ts | 3 +- client/src/app/shared/rest/rest-table.ts | 20 +++++++ client/src/sass/application.scss | 48 ++++++++-------- 18 files changed, 267 insertions(+), 137 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f2e376cf..9f919fef2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Features * Add ability for admin to inject custom JavaScript/CSS + * Add help tooltip on some fields ### Bug fixes diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index 1d9120490..b389f3d4f 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts @@ -2,7 +2,7 @@ import { NgModule } from '@angular/core' import { ConfigComponent, EditCustomConfigComponent } from '@app/+admin/config' import { ConfigService } from '@app/+admin/config/shared/config.service' import { TabsModule } from 'ngx-bootstrap/tabs' -import { DataTableModule } from 'primeng/components/datatable/datatable' +import { TableModule } from 'primeng/table' import { SharedModule } from '../shared' import { AdminRoutingModule } from './admin-routing.module' import { AdminComponent } from './admin.component' @@ -19,7 +19,7 @@ import { VideoBlacklistComponent, VideoBlacklistListComponent } from './video-bl imports: [ AdminRoutingModule, TabsModule.forRoot(), - DataTableModule, + TableModule, SharedModule ], diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.html b/client/src/app/+admin/follows/followers-list/followers-list.component.html index 74f2c2e36..85d2a2cf6 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.html +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.html @@ -1,11 +1,26 @@ - - - - - - - - + + + ID + Score + Name + Host + State + Created + + + + + + {{ follow.id }} + {{ follow.score }} + {{ follow.follower.name }} + {{ follow.follower.host }} + {{ follow.state }} + {{ follow.createdAt }} + + + diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.ts b/client/src/app/+admin/follows/followers-list/followers-list.component.ts index 649815709..69b3e5e58 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.ts +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core' +import { Component, OnInit } from '@angular/core' import { NotificationsService } from 'angular2-notifications' import { SortMeta } from 'primeng/primeng' @@ -11,7 +11,7 @@ import { FollowService } from '../shared' templateUrl: './followers-list.component.html', styleUrls: [ './followers-list.component.scss' ] }) -export class FollowersListComponent extends RestTable { +export class FollowersListComponent extends RestTable implements OnInit { followers: AccountFollow[] = [] totalRecords = 0 rowsPerPage = 10 @@ -25,6 +25,10 @@ export class FollowersListComponent extends RestTable { super() } + ngOnInit () { + this.loadSort() + } + protected loadData () { this.followService.getFollowers(this.pagination, this.sort) .subscribe( diff --git a/client/src/app/+admin/follows/following-list/following-list.component.html b/client/src/app/+admin/follows/following-list/following-list.component.html index fc1cf0dc4..24981d3e9 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.html +++ b/client/src/app/+admin/follows/following-list/following-list.component.html @@ -1,14 +1,26 @@ - - - - - - - - - - - + + + ID + Host + State + Created + + + + + + + {{ follow.id }} + {{ follow.following.host }} + {{ follow.state }} + {{ follow.createdAt }} + + + + + + diff --git a/client/src/app/+admin/follows/following-list/following-list.component.ts b/client/src/app/+admin/follows/following-list/following-list.component.ts index ad1bd4536..873a5d965 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.ts +++ b/client/src/app/+admin/follows/following-list/following-list.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core' +import { Component, OnInit } from '@angular/core' import { NotificationsService } from 'angular2-notifications' import { SortMeta } from 'primeng/primeng' import { AccountFollow } from '../../../../../../shared/models/actors/follow.model' @@ -10,7 +10,7 @@ import { FollowService } from '../shared' selector: 'my-followers-list', templateUrl: './following-list.component.html' }) -export class FollowingListComponent extends RestTable { +export class FollowingListComponent extends RestTable implements OnInit { following: AccountFollow[] = [] totalRecords = 0 rowsPerPage = 10 @@ -25,6 +25,10 @@ export class FollowingListComponent extends RestTable { super() } + ngOnInit () { + this.loadSort() + } + async removeFollowing (follow: AccountFollow) { const res = await this.confirmService.confirm(`Do you really want to unfollow ${follow.following.host}?`, 'Unfollow') if (res === false) return diff --git a/client/src/app/+admin/jobs/jobs-list/jobs-list.component.html b/client/src/app/+admin/jobs/jobs-list/jobs-list.component.html index f1b14e5e3..87717d3dd 100644 --- a/client/src/app/+admin/jobs/jobs-list/jobs-list.component.html +++ b/client/src/app/+admin/jobs/jobs-list/jobs-list.component.html @@ -8,20 +8,42 @@ + + + + + ID + Type + State + Created + Updated + + + + + + + + + + {{ job.id }} + {{ job.type }} + {{ job.state }} + {{ job.createdAt }} + {{ job.updatedAt }} + + + + + + +
{{ job.data }}
+ + +
+
- - - - - - -
{{ job.data }}
-
-
- - -
diff --git a/client/src/app/+admin/jobs/jobs-list/jobs-list.component.ts b/client/src/app/+admin/jobs/jobs-list/jobs-list.component.ts index 7de6f70d2..80aba9f3a 100644 --- a/client/src/app/+admin/jobs/jobs-list/jobs-list.component.ts +++ b/client/src/app/+admin/jobs/jobs-list/jobs-list.component.ts @@ -14,11 +14,13 @@ import { RestExtractor } from '../../../shared/rest/rest-extractor.service' styleUrls: [ './jobs-list.component.scss' ] }) export class JobsListComponent extends RestTable implements OnInit { + private static JOB_STATE_LOCAL_STORAGE_STATE = 'jobs-list-state' + jobState: JobState = 'inactive' jobStates: JobState[] = [ 'active', 'complete', 'failed', 'inactive', 'delayed' ] jobs: Job[] = [] - totalRecords = 0 - rowsPerPage = 20 + totalRecords: number + rowsPerPage = 10 sort: SortMeta = { field: 'createdAt', order: -1 } pagination: RestPagination = { count: this.rowsPerPage, start: 0 } scrollHeight = '' @@ -32,12 +34,16 @@ export class JobsListComponent extends RestTable implements OnInit { } ngOnInit () { - // 270 -> headers + footer... + // 380 -> headers + footer... this.scrollHeight = (viewportHeight() - 380) + 'px' + + this.loadJobState() + this.loadSort() } onJobStateChanged () { this.loadData() + this.saveJobState() } protected loadData () { @@ -52,4 +58,14 @@ export class JobsListComponent extends RestTable implements OnInit { err => this.notificationsService.error('Error', err.message) ) } + + private loadJobState () { + const result = localStorage.getItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE) + + if (result) this.jobState = result as JobState + } + + private saveJobState () { + localStorage.setItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE, this.jobState) + } } diff --git a/client/src/app/+admin/users/user-list/user-list.component.html b/client/src/app/+admin/users/user-list/user-list.component.html index 08f4caeb9..8dbe9ddc4 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.html +++ b/client/src/app/+admin/users/user-list/user-list.component.html @@ -7,20 +7,32 @@ - - - - - - - - - - - - - - + + + Username + Email + Video quota + Role + Created + + + + + + + {{ user.username }} + {{ user.email }} + {{ user.videoQuota }} + {{ user.roleLabel }} + {{ user.createdAt }} + + + + + + + diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts index 512152808..a52df49c0 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/users/user-list/user-list.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core' +import { Component, OnInit } from '@angular/core' import { NotificationsService } from 'angular2-notifications' import { SortMeta } from 'primeng/components/common/sortmeta' @@ -12,11 +12,11 @@ import { UserService } from '../shared' templateUrl: './user-list.component.html', styleUrls: [ './user-list.component.scss' ] }) -export class UserListComponent extends RestTable { +export class UserListComponent extends RestTable implements OnInit { users: User[] = [] totalRecords = 0 rowsPerPage = 10 - sort: SortMeta = { field: 'id', order: 1 } + sort: SortMeta = { field: 'createdAt', order: 1 } pagination: RestPagination = { count: this.rowsPerPage, start: 0 } constructor ( @@ -27,6 +27,10 @@ export class UserListComponent extends RestTable { super() } + ngOnInit () { + this.loadSort() + } + async removeUser (user: User) { if (user.username === 'root') { this.notificationsService.error('Error', 'You cannot delete root.') diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html index 65d061246..2779db5bc 100644 --- a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html +++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html @@ -2,18 +2,27 @@
Video abuses list
- - - - - - - - - {{ videoAbuse.videoName }} - - - + + + Reason + Reporter + Created + Video + + + + + + {{ videoAbuse.reason }} + {{ videoAbuse.reporterServerHost + '@' + videoAbuse.reporterUsername }} + {{ videoAbuse.createdAt }} + + {{ videoAbuse.videoName }} + + + + diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts index b4d3bbd24..bf9483f34 100644 --- a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts +++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts @@ -15,7 +15,7 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { videoAbuses: VideoAbuse[] = [] totalRecords = 0 rowsPerPage = 10 - sort: SortMeta = { field: 'id', order: 1 } + sort: SortMeta = { field: 'createdAt', order: 1 } pagination: RestPagination = { count: this.rowsPerPage, start: 0 } constructor ( @@ -26,11 +26,11 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { } ngOnInit () { - this.loadData() + this.loadSort() } - getRouterVideoLink (videoId: number) { - return [ '/videos', videoId ] + getRouterVideoLink (videoUUID: string) { + return [ '/videos', videoUUID ] } protected loadData () { diff --git a/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html b/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html index 942f7c9f1..ac30cec39 100644 --- a/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html +++ b/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html @@ -1,23 +1,35 @@ -
-
-

Blacklisted videos

- - - - - - - - - - - - - - - -
+
+
Blacklisted videos
+ + + + + Name + Description + Views + NSFW + UUID + Created + + + + + + + {{ videoBlacklist.name }} + {{ videoBlacklist.description }} + {{ videoBlacklist.views }} + {{ videoBlacklist.nsfw }} + {{ videoBlacklist.uuid }} + {{ videoBlacklist.createdAt }} + + + + + + + diff --git a/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts b/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts index f4cf21259..7210e677c 100644 --- a/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts +++ b/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts @@ -16,7 +16,7 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit { blacklist: BlacklistedVideo[] = [] totalRecords = 0 rowsPerPage = 10 - sort: SortMeta = { field: 'id', order: 1 } + sort: SortMeta = { field: 'createdAt', order: 1 } pagination: RestPagination = { count: this.rowsPerPage, start: 0 } constructor ( @@ -28,13 +28,13 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit { } ngOnInit () { - this.loadData() + this.loadSort() } async removeVideoFromBlacklist (entry: BlacklistedVideo) { - const confirmMessage = 'Do you really want to remove this video from the blacklist ? It will be available again in the video list.' + const confirmMessage = 'Do you really want to remove this video from the blacklist ? It will be available again in the videos list.' - const res = await this.confirmService.confirm(confirmMessage, 'Remove') + const res = await this.confirmService.confirm(confirmMessage, 'Unblacklist') if (res === false) return this.videoBlacklistService.removeVideoFromBlacklist(entry.videoId).subscribe( diff --git a/client/src/app/shared/misc/delete-button.component.html b/client/src/app/shared/misc/delete-button.component.html index 3db483882..d49de294a 100644 --- a/client/src/app/shared/misc/delete-button.component.html +++ b/client/src/app/shared/misc/delete-button.component.html @@ -1,4 +1,4 @@ - Delete + {{ label }} diff --git a/client/src/app/shared/misc/delete-button.component.ts b/client/src/app/shared/misc/delete-button.component.ts index e04039f69..2ffd98212 100644 --- a/client/src/app/shared/misc/delete-button.component.ts +++ b/client/src/app/shared/misc/delete-button.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core' +import { Component, Input } from '@angular/core' @Component({ selector: 'my-delete-button', @@ -7,4 +7,5 @@ import { Component } from '@angular/core' }) export class DeleteButtonComponent { + @Input() label = 'Delete' } diff --git a/client/src/app/shared/rest/rest-table.ts b/client/src/app/shared/rest/rest-table.ts index d04d91c68..165fc4e45 100644 --- a/client/src/app/shared/rest/rest-table.ts +++ b/client/src/app/shared/rest/rest-table.ts @@ -4,13 +4,28 @@ import { SortMeta } from 'primeng/components/common/sortmeta' import { RestPagination } from './rest-pagination' export abstract class RestTable { + abstract totalRecords: number abstract rowsPerPage: number abstract sort: SortMeta abstract pagination: RestPagination + private sortLocalStorageKey = 'rest-table-sort-' + this.constructor.name + protected abstract loadData (): void + loadSort () { + const result = localStorage.getItem(this.sortLocalStorageKey) + + if (result) { + try { + this.sort = JSON.parse(result) + } catch (err) { + console.error('Cannot load sort of local storage key ' + this.sortLocalStorageKey, err) + } + } + } + loadLazy (event: LazyLoadEvent) { this.sort = { order: event.sortOrder, @@ -23,6 +38,11 @@ export abstract class RestTable { } this.loadData() + this.saveSort() + } + + saveSort () { + localStorage.setItem(this.sortLocalStorageKey, JSON.stringify(this.sort)) } } diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss index f998096ae..438990a40 100644 --- a/client/src/sass/application.scss +++ b/client/src/sass/application.scss @@ -131,21 +131,9 @@ label { } // ngprime data table customizations -p-datatable { +p-table { font-size: 15px !important; - .ui-datatable-scrollable-header { - background-color: #fff !important; - } - - .ui-widget-content { - border: none !important; - } - - .ui-datatable-virtual-table { - border-top: none !important; - } - td { border: 1px solid #E5E5E5 !important; padding-left: 15px !important; @@ -157,23 +145,33 @@ p-datatable { tr { background-color: #fff !important; height: 46px; + } - &:hover { - background-color: #f0f0f0 !important; - } + .ui-table-tbody { + tr { + &:hover { + background-color: #f0f0f0 !important; + } - &:not(:hover) { - .action-cell * { - display: none !important; + &:not(:hover) { + .action-cell * { + display: none !important; + } } - } - &:first-child td { - border-top: none !important; + &:first-child td { + border-top: none !important; + } + + &:last-child td { + border-bottom: none !important; + } } - &:last-child td { - border-bottom: none !important; + .expander { + cursor: pointer; + position: relative; + top: 1px; } } @@ -195,7 +193,7 @@ p-datatable { } } - &.ui-state-active { + &.ui-state-highlight { background-color: #fff !important; .fa { -- 2.41.0