diff options
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 @@ | |||
5 | ### Features | 5 | ### Features |
6 | 6 | ||
7 | * Add ability for admin to inject custom JavaScript/CSS | 7 | * Add ability for admin to inject custom JavaScript/CSS |
8 | * Add help tooltip on some fields | ||
8 | 9 | ||
9 | ### Bug fixes | 10 | ### Bug fixes |
10 | 11 | ||
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' | |||
2 | import { ConfigComponent, EditCustomConfigComponent } from '@app/+admin/config' | 2 | import { ConfigComponent, EditCustomConfigComponent } from '@app/+admin/config' |
3 | import { ConfigService } from '@app/+admin/config/shared/config.service' | 3 | import { ConfigService } from '@app/+admin/config/shared/config.service' |
4 | import { TabsModule } from 'ngx-bootstrap/tabs' | 4 | import { TabsModule } from 'ngx-bootstrap/tabs' |
5 | import { DataTableModule } from 'primeng/components/datatable/datatable' | 5 | import { TableModule } from 'primeng/table' |
6 | import { SharedModule } from '../shared' | 6 | import { SharedModule } from '../shared' |
7 | import { AdminRoutingModule } from './admin-routing.module' | 7 | import { AdminRoutingModule } from './admin-routing.module' |
8 | import { AdminComponent } from './admin.component' | 8 | import { AdminComponent } from './admin.component' |
@@ -19,7 +19,7 @@ import { VideoBlacklistComponent, VideoBlacklistListComponent } from './video-bl | |||
19 | imports: [ | 19 | imports: [ |
20 | AdminRoutingModule, | 20 | AdminRoutingModule, |
21 | TabsModule.forRoot(), | 21 | TabsModule.forRoot(), |
22 | DataTableModule, | 22 | TableModule, |
23 | SharedModule | 23 | SharedModule |
24 | ], | 24 | ], |
25 | 25 | ||
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 @@ | |||
1 | <p-dataTable | 1 | <p-table |
2 | [value]="followers" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | 2 | [value]="followers" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" |
3 | sortField="createdAt" (onLazyLoad)="loadLazy($event)" | 3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" |
4 | > | 4 | > |
5 | <p-column field="id" header="ID" [style]="{ width: '60px' }"></p-column> | 5 | <ng-template pTemplate="header"> |
6 | <p-column field="score" header="Score"></p-column> | 6 | <tr> |
7 | <p-column field="follower.name" header="Name"></p-column> | 7 | <th style="width: 60px">ID</th> |
8 | <p-column field="follower.host" header="Host"></p-column> | 8 | <th>Score</th> |
9 | <p-column field="state" header="State"></p-column> | 9 | <th>Name</th> |
10 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> | 10 | <th>Host</th> |
11 | </p-dataTable> | 11 | <th>State</th> |
12 | <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
13 | </tr> | ||
14 | </ng-template> | ||
15 | |||
16 | <ng-template pTemplate="body" let-follow> | ||
17 | <tr> | ||
18 | <td>{{ follow.id }}</td> | ||
19 | <td>{{ follow.score }}</td> | ||
20 | <td>{{ follow.follower.name }}</td> | ||
21 | <td>{{ follow.follower.host }}</td> | ||
22 | <td>{{ follow.state }}</td> | ||
23 | <td>{{ follow.createdAt }}</td> | ||
24 | </tr> | ||
25 | </ng-template> | ||
26 | </p-table> | ||
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 @@ | |||
1 | import { Component } from '@angular/core' | 1 | import { Component, OnInit } from '@angular/core' |
2 | 2 | ||
3 | import { NotificationsService } from 'angular2-notifications' | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | import { SortMeta } from 'primeng/primeng' | 4 | import { SortMeta } from 'primeng/primeng' |
@@ -11,7 +11,7 @@ import { FollowService } from '../shared' | |||
11 | templateUrl: './followers-list.component.html', | 11 | templateUrl: './followers-list.component.html', |
12 | styleUrls: [ './followers-list.component.scss' ] | 12 | styleUrls: [ './followers-list.component.scss' ] |
13 | }) | 13 | }) |
14 | export class FollowersListComponent extends RestTable { | 14 | export class FollowersListComponent extends RestTable implements OnInit { |
15 | followers: AccountFollow[] = [] | 15 | followers: AccountFollow[] = [] |
16 | totalRecords = 0 | 16 | totalRecords = 0 |
17 | rowsPerPage = 10 | 17 | rowsPerPage = 10 |
@@ -25,6 +25,10 @@ export class FollowersListComponent extends RestTable { | |||
25 | super() | 25 | super() |
26 | } | 26 | } |
27 | 27 | ||
28 | ngOnInit () { | ||
29 | this.loadSort() | ||
30 | } | ||
31 | |||
28 | protected loadData () { | 32 | protected loadData () { |
29 | this.followService.getFollowers(this.pagination, this.sort) | 33 | this.followService.getFollowers(this.pagination, this.sort) |
30 | .subscribe( | 34 | .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 @@ | |||
1 | <p-dataTable | 1 | <p-table |
2 | [value]="following" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | 2 | [value]="following" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" |
3 | sortField="createdAt" (onLazyLoad)="loadLazy($event)" | 3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" |
4 | > | 4 | > |
5 | <p-column field="id" header="ID" [style]="{ width: '60px' }"></p-column> | 5 | <ng-template pTemplate="header"> |
6 | <p-column field="following.host" header="Host"></p-column> | 6 | <tr> |
7 | <p-column field="state" header="State"></p-column> | 7 | <th style="width: 60px">ID</th> |
8 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> | 8 | <th>Host</th> |
9 | <p-column styleClass="action-cell"> | 9 | <th>State</th> |
10 | <ng-template pTemplate="body" let-following="rowData"> | 10 | <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> |
11 | <my-delete-button (click)="removeFollowing(following)"></my-delete-button> | 11 | <th></th> |
12 | </ng-template> | 12 | </tr> |
13 | </p-column> | 13 | </ng-template> |
14 | </p-dataTable> | 14 | |
15 | <ng-template pTemplate="body" let-follow> | ||
16 | <tr> | ||
17 | <td>{{ follow.id }}</td> | ||
18 | <td>{{ follow.following.host }}</td> | ||
19 | <td>{{ follow.state }}</td> | ||
20 | <td>{{ follow.createdAt }}</td> | ||
21 | <td class="action-cell"> | ||
22 | <my-delete-button (click)="removeFollowing(follow)"></my-delete-button> | ||
23 | </td> | ||
24 | </tr> | ||
25 | </ng-template> | ||
26 | </p-table> | ||
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 @@ | |||
1 | import { Component } from '@angular/core' | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { NotificationsService } from 'angular2-notifications' | 2 | import { NotificationsService } from 'angular2-notifications' |
3 | import { SortMeta } from 'primeng/primeng' | 3 | import { SortMeta } from 'primeng/primeng' |
4 | import { AccountFollow } from '../../../../../../shared/models/actors/follow.model' | 4 | import { AccountFollow } from '../../../../../../shared/models/actors/follow.model' |
@@ -10,7 +10,7 @@ import { FollowService } from '../shared' | |||
10 | selector: 'my-followers-list', | 10 | selector: 'my-followers-list', |
11 | templateUrl: './following-list.component.html' | 11 | templateUrl: './following-list.component.html' |
12 | }) | 12 | }) |
13 | export class FollowingListComponent extends RestTable { | 13 | export class FollowingListComponent extends RestTable implements OnInit { |
14 | following: AccountFollow[] = [] | 14 | following: AccountFollow[] = [] |
15 | totalRecords = 0 | 15 | totalRecords = 0 |
16 | rowsPerPage = 10 | 16 | rowsPerPage = 10 |
@@ -25,6 +25,10 @@ export class FollowingListComponent extends RestTable { | |||
25 | super() | 25 | super() |
26 | } | 26 | } |
27 | 27 | ||
28 | ngOnInit () { | ||
29 | this.loadSort() | ||
30 | } | ||
31 | |||
28 | async removeFollowing (follow: AccountFollow) { | 32 | async removeFollowing (follow: AccountFollow) { |
29 | const res = await this.confirmService.confirm(`Do you really want to unfollow ${follow.following.host}?`, 'Unfollow') | 33 | const res = await this.confirmService.confirm(`Do you really want to unfollow ${follow.following.host}?`, 'Unfollow') |
30 | if (res === false) return | 34 | 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 @@ | |||
8 | </div> | 8 | </div> |
9 | </div> | 9 | </div> |
10 | 10 | ||
11 | <p-table | ||
12 | [value]="jobs" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" dataKey="id" | ||
13 | sortField="createdAt" (onLazyLoad)="loadLazy($event)" | ||
14 | > | ||
15 | <ng-template pTemplate="header"> | ||
16 | <tr> | ||
17 | <th style="width: 27px"></th> | ||
18 | <th style="width: 60px">ID</th> | ||
19 | <th style="width: 210px">Type</th> | ||
20 | <th style="width: 130px">State</th> | ||
21 | <th style="width: 250px" pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
22 | <th style="width: 250px">Updated</th> | ||
23 | </tr> | ||
24 | </ng-template> | ||
11 | 25 | ||
26 | <ng-template pTemplate="body" let-expanded="expanded" let-job> | ||
27 | <tr> | ||
28 | <td> | ||
29 | <span class="expander" [pRowToggler]="job"> | ||
30 | <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i> | ||
31 | </span> | ||
32 | </td> | ||
33 | <td>{{ job.id }}</td> | ||
34 | <td>{{ job.type }}</td> | ||
35 | <td>{{ job.state }}</td> | ||
36 | <td>{{ job.createdAt }}</td> | ||
37 | <td>{{ job.updatedAt }}</td> | ||
38 | </tr> | ||
39 | </ng-template> | ||
40 | |||
41 | <ng-template pTemplate="rowexpansion" let-job> | ||
42 | <tr> | ||
43 | <td colspan="6"> | ||
44 | <pre>{{ job.data }}</pre> | ||
45 | </td> | ||
46 | </tr> | ||
47 | </ng-template> | ||
48 | </p-table> | ||
12 | 49 | ||
13 | <p-dataTable | ||
14 | [value]="jobs" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | ||
15 | sortField="createdAt" (onLazyLoad)="loadLazy($event)" [scrollable]="true" [virtualScroll]="true" [scrollHeight]="scrollHeight" | ||
16 | > | ||
17 | <p-column field="id" header="ID" [style]="{ width: '60px' }"></p-column> | ||
18 | <p-column field="type" header="Type" [style]="{ width: '210px' }"></p-column> | ||
19 | <p-column field="state" header="State" [style]="{ width: '130px' }"></p-column> | ||
20 | <p-column header="Payload"> | ||
21 | <ng-template pTemplate="body" let-job="rowData"> | ||
22 | <pre>{{ job.data }}</pre> | ||
23 | </ng-template> | ||
24 | </p-column> | ||
25 | <p-column field="createdAt" header="Created date" [sortable]="true" [style]="{ width: '250px' }"></p-column> | ||
26 | <p-column field="updatedAt" header="Updated date" [style]="{ width: '250px' }"></p-column> | ||
27 | </p-dataTable> | ||
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' | |||
14 | styleUrls: [ './jobs-list.component.scss' ] | 14 | styleUrls: [ './jobs-list.component.scss' ] |
15 | }) | 15 | }) |
16 | export class JobsListComponent extends RestTable implements OnInit { | 16 | export class JobsListComponent extends RestTable implements OnInit { |
17 | private static JOB_STATE_LOCAL_STORAGE_STATE = 'jobs-list-state' | ||
18 | |||
17 | jobState: JobState = 'inactive' | 19 | jobState: JobState = 'inactive' |
18 | jobStates: JobState[] = [ 'active', 'complete', 'failed', 'inactive', 'delayed' ] | 20 | jobStates: JobState[] = [ 'active', 'complete', 'failed', 'inactive', 'delayed' ] |
19 | jobs: Job[] = [] | 21 | jobs: Job[] = [] |
20 | totalRecords = 0 | 22 | totalRecords: number |
21 | rowsPerPage = 20 | 23 | rowsPerPage = 10 |
22 | sort: SortMeta = { field: 'createdAt', order: -1 } | 24 | sort: SortMeta = { field: 'createdAt', order: -1 } |
23 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 25 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
24 | scrollHeight = '' | 26 | scrollHeight = '' |
@@ -32,12 +34,16 @@ export class JobsListComponent extends RestTable implements OnInit { | |||
32 | } | 34 | } |
33 | 35 | ||
34 | ngOnInit () { | 36 | ngOnInit () { |
35 | // 270 -> headers + footer... | 37 | // 380 -> headers + footer... |
36 | this.scrollHeight = (viewportHeight() - 380) + 'px' | 38 | this.scrollHeight = (viewportHeight() - 380) + 'px' |
39 | |||
40 | this.loadJobState() | ||
41 | this.loadSort() | ||
37 | } | 42 | } |
38 | 43 | ||
39 | onJobStateChanged () { | 44 | onJobStateChanged () { |
40 | this.loadData() | 45 | this.loadData() |
46 | this.saveJobState() | ||
41 | } | 47 | } |
42 | 48 | ||
43 | protected loadData () { | 49 | protected loadData () { |
@@ -52,4 +58,14 @@ export class JobsListComponent extends RestTable implements OnInit { | |||
52 | err => this.notificationsService.error('Error', err.message) | 58 | err => this.notificationsService.error('Error', err.message) |
53 | ) | 59 | ) |
54 | } | 60 | } |
61 | |||
62 | private loadJobState () { | ||
63 | const result = localStorage.getItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE) | ||
64 | |||
65 | if (result) this.jobState = result as JobState | ||
66 | } | ||
67 | |||
68 | private saveJobState () { | ||
69 | localStorage.setItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE, this.jobState) | ||
70 | } | ||
55 | } | 71 | } |
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 @@ | |||
7 | </a> | 7 | </a> |
8 | </div> | 8 | </div> |
9 | 9 | ||
10 | <p-dataTable | 10 | <p-table |
11 | [value]="users" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | 11 | [value]="users" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" |
12 | sortField="id" (onLazyLoad)="loadLazy($event)" | 12 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" |
13 | > | 13 | > |
14 | <p-column field="id" header="ID" [sortable]="true" [style]="{ width: '60px' }"></p-column> | 14 | <ng-template pTemplate="header"> |
15 | <p-column field="username" header="Username" [sortable]="true"></p-column> | 15 | <tr> |
16 | <p-column field="email" header="Email"></p-column> | 16 | <th pSortableColumn="username">Username <p-sortIcon field="username"></p-sortIcon></th> |
17 | <p-column field="videoQuota" header="Video quota"></p-column> | 17 | <th>Email</th> |
18 | <p-column field="roleLabel" header="Role"></p-column> | 18 | <th>Video quota</th> |
19 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> | 19 | <th>Role</th> |
20 | <p-column styleClass="action-cell"> | 20 | <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> |
21 | <ng-template pTemplate="body" let-user="rowData"> | 21 | <th></th> |
22 | <my-edit-button [routerLink]="getRouterUserEditLink(user)"></my-edit-button> | 22 | </tr> |
23 | <my-delete-button (click)="removeUser(user)"></my-delete-button> | 23 | </ng-template> |
24 | </ng-template> | 24 | |
25 | </p-column> | 25 | <ng-template pTemplate="body" let-user> |
26 | </p-dataTable> | 26 | <tr> |
27 | <td>{{ user.username }}</td> | ||
28 | <td>{{ user.email }}</td> | ||
29 | <td>{{ user.videoQuota }}</td> | ||
30 | <td>{{ user.roleLabel }}</td> | ||
31 | <td>{{ user.createdAt }}</td> | ||
32 | <td class="action-cell"> | ||
33 | <my-edit-button [routerLink]="getRouterUserEditLink(user)"></my-edit-button> | ||
34 | <my-delete-button (click)="removeUser(user)"></my-delete-button> | ||
35 | </td> | ||
36 | </tr> | ||
37 | </ng-template> | ||
38 | </p-table> | ||
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 @@ | |||
1 | import { Component } from '@angular/core' | 1 | import { Component, OnInit } from '@angular/core' |
2 | 2 | ||
3 | import { NotificationsService } from 'angular2-notifications' | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | import { SortMeta } from 'primeng/components/common/sortmeta' | 4 | import { SortMeta } from 'primeng/components/common/sortmeta' |
@@ -12,11 +12,11 @@ import { UserService } from '../shared' | |||
12 | templateUrl: './user-list.component.html', | 12 | templateUrl: './user-list.component.html', |
13 | styleUrls: [ './user-list.component.scss' ] | 13 | styleUrls: [ './user-list.component.scss' ] |
14 | }) | 14 | }) |
15 | export class UserListComponent extends RestTable { | 15 | export class UserListComponent extends RestTable implements OnInit { |
16 | users: User[] = [] | 16 | users: User[] = [] |
17 | totalRecords = 0 | 17 | totalRecords = 0 |
18 | rowsPerPage = 10 | 18 | rowsPerPage = 10 |
19 | sort: SortMeta = { field: 'id', order: 1 } | 19 | sort: SortMeta = { field: 'createdAt', order: 1 } |
20 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 20 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
21 | 21 | ||
22 | constructor ( | 22 | constructor ( |
@@ -27,6 +27,10 @@ export class UserListComponent extends RestTable { | |||
27 | super() | 27 | super() |
28 | } | 28 | } |
29 | 29 | ||
30 | ngOnInit () { | ||
31 | this.loadSort() | ||
32 | } | ||
33 | |||
30 | async removeUser (user: User) { | 34 | async removeUser (user: User) { |
31 | if (user.username === 'root') { | 35 | if (user.username === 'root') { |
32 | this.notificationsService.error('Error', 'You cannot delete root.') | 36 | 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 @@ | |||
2 | <div class="admin-sub-title">Video abuses list</div> | 2 | <div class="admin-sub-title">Video abuses list</div> |
3 | </div> | 3 | </div> |
4 | 4 | ||
5 | <p-dataTable | 5 | <p-table |
6 | [value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | 6 | [value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" |
7 | sortField="id" (onLazyLoad)="loadLazy($event)" | 7 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" |
8 | > | 8 | > |
9 | <p-column field="id" header="ID" [sortable]="true" [style]="{ width: '60px' }"></p-column> | 9 | <ng-template pTemplate="header"> |
10 | <p-column field="reason" header="Reason"></p-column> | 10 | <tr> |
11 | <p-column field="reporterServerHost" header="Reporter server host"></p-column> | 11 | <th>Reason</th> |
12 | <p-column field="reporterUsername" header="Reporter username"></p-column> | 12 | <th>Reporter</th> |
13 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> | 13 | <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> |
14 | <p-column header="Video"> | 14 | <th>Video</th> |
15 | <ng-template pTemplate="body" let-videoAbuse="rowData"> | 15 | </tr> |
16 | <a [routerLink]="getRouterVideoLink(videoAbuse.videoId)" title="Go to the video">{{ videoAbuse.videoName }}</a> | 16 | </ng-template> |
17 | </ng-template> | 17 | |
18 | </p-column> | 18 | <ng-template pTemplate="body" let-videoAbuse> |
19 | </p-dataTable> | 19 | <tr> |
20 | <td>{{ videoAbuse.reason }}</td> | ||
21 | <td>{{ videoAbuse.reporterServerHost + '@' + videoAbuse.reporterUsername }}</td> | ||
22 | <td>{{ videoAbuse.createdAt }}</td> | ||
23 | <td> | ||
24 | <a [routerLink]="getRouterVideoLink(videoAbuse.videoUUID)" title="Go to the video">{{ videoAbuse.videoName }}</a> | ||
25 | </td> | ||
26 | </tr> | ||
27 | </ng-template> | ||
28 | </p-table> | ||
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 { | |||
15 | videoAbuses: VideoAbuse[] = [] | 15 | videoAbuses: VideoAbuse[] = [] |
16 | totalRecords = 0 | 16 | totalRecords = 0 |
17 | rowsPerPage = 10 | 17 | rowsPerPage = 10 |
18 | sort: SortMeta = { field: 'id', order: 1 } | 18 | sort: SortMeta = { field: 'createdAt', order: 1 } |
19 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 19 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
20 | 20 | ||
21 | constructor ( | 21 | constructor ( |
@@ -26,11 +26,11 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { | |||
26 | } | 26 | } |
27 | 27 | ||
28 | ngOnInit () { | 28 | ngOnInit () { |
29 | this.loadData() | 29 | this.loadSort() |
30 | } | 30 | } |
31 | 31 | ||
32 | getRouterVideoLink (videoId: number) { | 32 | getRouterVideoLink (videoUUID: string) { |
33 | return [ '/videos', videoId ] | 33 | return [ '/videos', videoUUID ] |
34 | } | 34 | } |
35 | 35 | ||
36 | protected loadData () { | 36 | 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 @@ | |||
1 | <div class="row"> | 1 | <div class="admin-sub-header"> |
2 | <div class="content-padding"> | 2 | <div class="admin-sub-title">Blacklisted videos</div> |
3 | <h3>Blacklisted videos</h3> | ||
4 | |||
5 | <p-dataTable | ||
6 | [value]="blacklist" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | ||
7 | sortField="id" (onLazyLoad)="loadLazy($event)" | ||
8 | > | ||
9 | <p-column field="id" header="ID" [sortable]="true"></p-column> | ||
10 | <p-column field="name" header="Name" [sortable]="true"></p-column> | ||
11 | <p-column field="description" header="Description"></p-column> | ||
12 | <p-column field="views" header="Views" [sortable]="true"></p-column> | ||
13 | <p-column field="nsfw" header="NSFW"></p-column> | ||
14 | <p-column field="uuid" header="UUID" [sortable]="true"></p-column> | ||
15 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> | ||
16 | <p-column header="Delete" styleClass="action-cell"> | ||
17 | <ng-template pTemplate="body" let-entry="rowData"> | ||
18 | <my-delete-button (click)="removeVideoFromBlacklist(entry)"></my-delete-button> | ||
19 | </ng-template> | ||
20 | </p-column> | ||
21 | </p-dataTable> | ||
22 | </div> | ||
23 | </div> | 3 | </div> |
4 | |||
5 | <p-table | ||
6 | [value]="blacklist" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | ||
7 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" | ||
8 | > | ||
9 | <ng-template pTemplate="header"> | ||
10 | <tr> | ||
11 | <th pSortableColumn="name">Name <p-sortIcon field="name"></p-sortIcon></th> | ||
12 | <th>Description</th> | ||
13 | <th pSortableColumn="views">Views <p-sortIcon field="views"></p-sortIcon></th> | ||
14 | <th>NSFW</th> | ||
15 | <th>UUID</th> | ||
16 | <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
17 | <th></th> | ||
18 | </tr> | ||
19 | </ng-template> | ||
20 | |||
21 | <ng-template pTemplate="body" let-videoBlacklist> | ||
22 | <tr> | ||
23 | <td>{{ videoBlacklist.name }}</td> | ||
24 | <td>{{ videoBlacklist.description }}</td> | ||
25 | <td>{{ videoBlacklist.views }}</td> | ||
26 | <td>{{ videoBlacklist.nsfw }}</td> | ||
27 | <td>{{ videoBlacklist.uuid }}</td> | ||
28 | <td>{{ videoBlacklist.createdAt }}</td> | ||
29 | <td class="action-cell"> | ||
30 | <my-delete-button label="Unblacklist" (click)="removeVideoFromBlacklist(videoBlacklist)"></my-delete-button> | ||
31 | </td> | ||
32 | </tr> | ||
33 | </ng-template> | ||
34 | </p-table> | ||
35 | |||
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 { | |||
16 | blacklist: BlacklistedVideo[] = [] | 16 | blacklist: BlacklistedVideo[] = [] |
17 | totalRecords = 0 | 17 | totalRecords = 0 |
18 | rowsPerPage = 10 | 18 | rowsPerPage = 10 |
19 | sort: SortMeta = { field: 'id', order: 1 } | 19 | sort: SortMeta = { field: 'createdAt', order: 1 } |
20 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 20 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
21 | 21 | ||
22 | constructor ( | 22 | constructor ( |
@@ -28,13 +28,13 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit { | |||
28 | } | 28 | } |
29 | 29 | ||
30 | ngOnInit () { | 30 | ngOnInit () { |
31 | this.loadData() | 31 | this.loadSort() |
32 | } | 32 | } |
33 | 33 | ||
34 | async removeVideoFromBlacklist (entry: BlacklistedVideo) { | 34 | async removeVideoFromBlacklist (entry: BlacklistedVideo) { |
35 | const confirmMessage = 'Do you really want to remove this video from the blacklist ? It will be available again in the video list.' | 35 | const confirmMessage = 'Do you really want to remove this video from the blacklist ? It will be available again in the videos list.' |
36 | 36 | ||
37 | const res = await this.confirmService.confirm(confirmMessage, 'Remove') | 37 | const res = await this.confirmService.confirm(confirmMessage, 'Unblacklist') |
38 | if (res === false) return | 38 | if (res === false) return |
39 | 39 | ||
40 | this.videoBlacklistService.removeVideoFromBlacklist(entry.videoId).subscribe( | 40 | 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 @@ | |||
1 | <span class="action-button action-button-delete" > | 1 | <span class="action-button action-button-delete" > |
2 | <span class="icon icon-delete-grey"></span> | 2 | <span class="icon icon-delete-grey"></span> |
3 | Delete | 3 | {{ label }} |
4 | </span> | 4 | </span> |
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 @@ | |||
1 | import { Component } from '@angular/core' | 1 | import { Component, Input } from '@angular/core' |
2 | 2 | ||
3 | @Component({ | 3 | @Component({ |
4 | selector: 'my-delete-button', | 4 | selector: 'my-delete-button', |
@@ -7,4 +7,5 @@ import { Component } from '@angular/core' | |||
7 | }) | 7 | }) |
8 | 8 | ||
9 | export class DeleteButtonComponent { | 9 | export class DeleteButtonComponent { |
10 | @Input() label = 'Delete' | ||
10 | } | 11 | } |
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' | |||
4 | import { RestPagination } from './rest-pagination' | 4 | import { RestPagination } from './rest-pagination' |
5 | 5 | ||
6 | export abstract class RestTable { | 6 | export abstract class RestTable { |
7 | |||
7 | abstract totalRecords: number | 8 | abstract totalRecords: number |
8 | abstract rowsPerPage: number | 9 | abstract rowsPerPage: number |
9 | abstract sort: SortMeta | 10 | abstract sort: SortMeta |
10 | abstract pagination: RestPagination | 11 | abstract pagination: RestPagination |
11 | 12 | ||
13 | private sortLocalStorageKey = 'rest-table-sort-' + this.constructor.name | ||
14 | |||
12 | protected abstract loadData (): void | 15 | protected abstract loadData (): void |
13 | 16 | ||
17 | loadSort () { | ||
18 | const result = localStorage.getItem(this.sortLocalStorageKey) | ||
19 | |||
20 | if (result) { | ||
21 | try { | ||
22 | this.sort = JSON.parse(result) | ||
23 | } catch (err) { | ||
24 | console.error('Cannot load sort of local storage key ' + this.sortLocalStorageKey, err) | ||
25 | } | ||
26 | } | ||
27 | } | ||
28 | |||
14 | loadLazy (event: LazyLoadEvent) { | 29 | loadLazy (event: LazyLoadEvent) { |
15 | this.sort = { | 30 | this.sort = { |
16 | order: event.sortOrder, | 31 | order: event.sortOrder, |
@@ -23,6 +38,11 @@ export abstract class RestTable { | |||
23 | } | 38 | } |
24 | 39 | ||
25 | this.loadData() | 40 | this.loadData() |
41 | this.saveSort() | ||
42 | } | ||
43 | |||
44 | saveSort () { | ||
45 | localStorage.setItem(this.sortLocalStorageKey, JSON.stringify(this.sort)) | ||
26 | } | 46 | } |
27 | 47 | ||
28 | } | 48 | } |
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 { | |||
131 | } | 131 | } |
132 | 132 | ||
133 | // ngprime data table customizations | 133 | // ngprime data table customizations |
134 | p-datatable { | 134 | p-table { |
135 | font-size: 15px !important; | 135 | font-size: 15px !important; |
136 | 136 | ||
137 | .ui-datatable-scrollable-header { | ||
138 | background-color: #fff !important; | ||
139 | } | ||
140 | |||
141 | .ui-widget-content { | ||
142 | border: none !important; | ||
143 | } | ||
144 | |||
145 | .ui-datatable-virtual-table { | ||
146 | border-top: none !important; | ||
147 | } | ||
148 | |||
149 | td { | 137 | td { |
150 | border: 1px solid #E5E5E5 !important; | 138 | border: 1px solid #E5E5E5 !important; |
151 | padding-left: 15px !important; | 139 | padding-left: 15px !important; |
@@ -157,23 +145,33 @@ p-datatable { | |||
157 | tr { | 145 | tr { |
158 | background-color: #fff !important; | 146 | background-color: #fff !important; |
159 | height: 46px; | 147 | height: 46px; |
148 | } | ||
160 | 149 | ||
161 | &:hover { | 150 | .ui-table-tbody { |
162 | background-color: #f0f0f0 !important; | 151 | tr { |
163 | } | 152 | &:hover { |
153 | background-color: #f0f0f0 !important; | ||
154 | } | ||
164 | 155 | ||
165 | &:not(:hover) { | 156 | &:not(:hover) { |
166 | .action-cell * { | 157 | .action-cell * { |
167 | display: none !important; | 158 | display: none !important; |
159 | } | ||
168 | } | 160 | } |
169 | } | ||
170 | 161 | ||
171 | &:first-child td { | 162 | &:first-child td { |
172 | border-top: none !important; | 163 | border-top: none !important; |
164 | } | ||
165 | |||
166 | &:last-child td { | ||
167 | border-bottom: none !important; | ||
168 | } | ||
173 | } | 169 | } |
174 | 170 | ||
175 | &:last-child td { | 171 | .expander { |
176 | border-bottom: none !important; | 172 | cursor: pointer; |
173 | position: relative; | ||
174 | top: 1px; | ||
177 | } | 175 | } |
178 | } | 176 | } |
179 | 177 | ||
@@ -195,7 +193,7 @@ p-datatable { | |||
195 | } | 193 | } |
196 | } | 194 | } |
197 | 195 | ||
198 | &.ui-state-active { | 196 | &.ui-state-highlight { |
199 | background-color: #fff !important; | 197 | background-color: #fff !important; |
200 | 198 | ||
201 | .fa { | 199 | .fa { |