aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+admin
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/+admin')
-rw-r--r--client/src/app/+admin/admin.component.html27
-rw-r--r--client/src/app/+admin/admin.component.scss0
-rw-r--r--client/src/app/+admin/admin.component.ts26
-rw-r--r--client/src/app/+admin/follows/followers-list/followers-list.component.html26
-rw-r--r--client/src/app/+admin/follows/followers-list/followers-list.component.scss3
-rw-r--r--client/src/app/+admin/follows/following-add/following-add.component.html47
-rw-r--r--client/src/app/+admin/follows/following-add/following-add.component.scss10
-rw-r--r--client/src/app/+admin/follows/following-add/following-add.component.ts94
-rw-r--r--client/src/app/+admin/follows/following-list/following-list.component.html34
-rw-r--r--client/src/app/+admin/follows/follows.component.html6
-rw-r--r--client/src/app/+admin/follows/follows.component.scss23
-rw-r--r--client/src/app/+admin/follows/follows.component.ts2
-rw-r--r--client/src/app/+admin/jobs/jobs-list/jobs-list.component.html36
-rw-r--r--client/src/app/+admin/jobs/jobs-list/jobs-list.component.scss3
-rw-r--r--client/src/app/+admin/jobs/jobs-list/jobs-list.component.ts24
-rw-r--r--client/src/app/+admin/jobs/shared/job.service.ts7
-rw-r--r--client/src/app/+admin/users/shared/user.service.ts14
-rw-r--r--client/src/app/+admin/users/user-edit/user-edit.component.html123
-rw-r--r--client/src/app/+admin/users/user-edit/user-edit.component.scss18
-rw-r--r--client/src/app/+admin/users/user-list/user-list.component.html57
-rw-r--r--client/src/app/+admin/users/user-list/user-list.component.scss14
-rw-r--r--client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html41
-rw-r--r--client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.scss6
-rw-r--r--client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts3
-rw-r--r--client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html2
25 files changed, 324 insertions, 322 deletions
diff --git a/client/src/app/+admin/admin.component.html b/client/src/app/+admin/admin.component.html
new file mode 100644
index 000000000..0bf4c8aac
--- /dev/null
+++ b/client/src/app/+admin/admin.component.html
@@ -0,0 +1,27 @@
1<div class="row">
2 <div class="sub-menu">
3 <a *ngIf="hasUsersRight()" routerLink="/admin/users" routerLinkActive="active" class="title-page">
4 Users
5 </a>
6
7 <a *ngIf="hasServerFollowRight()" routerLink="/admin/follows" routerLinkActive="active" class="title-page">
8 Manage follows
9 </a>
10
11 <a *ngIf="hasVideoAbusesRight()" routerLink="/admin/video-abuses" routerLinkActive="active" class="title-page">
12 Video abuses
13 </a>
14
15 <a *ngIf="hasVideoBlacklistRight()" routerLink="/admin/video-blacklist" routerLinkActive="active" class="title-page">
16 Video blacklist
17 </a>
18
19 <a *ngIf="hasJobsRight()" routerLink="/admin/jobs" routerLinkActive="active" class="title-page">
20 Jobs
21 </a>
22 </div>
23
24 <div class="margin-content">
25 <router-outlet></router-outlet>
26 </div>
27</div>
diff --git a/client/src/app/+admin/admin.component.scss b/client/src/app/+admin/admin.component.scss
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/client/src/app/+admin/admin.component.scss
diff --git a/client/src/app/+admin/admin.component.ts b/client/src/app/+admin/admin.component.ts
index ecd62ee61..75cd50cc7 100644
--- a/client/src/app/+admin/admin.component.ts
+++ b/client/src/app/+admin/admin.component.ts
@@ -1,7 +1,31 @@
1import { Component } from '@angular/core' 1import { Component } from '@angular/core'
2import { UserRight } from '../../../../shared'
3import { AuthService } from '../core/auth/auth.service'
2 4
3@Component({ 5@Component({
4 template: '<router-outlet></router-outlet>' 6 templateUrl: './admin.component.html',
7 styleUrls: [ './admin.component.scss' ]
5}) 8})
6export class AdminComponent { 9export class AdminComponent {
10 constructor (private auth: AuthService) {}
11
12 hasUsersRight () {
13 return this.auth.getUser().hasRight(UserRight.MANAGE_USERS)
14 }
15
16 hasServerFollowRight () {
17 return this.auth.getUser().hasRight(UserRight.MANAGE_SERVER_FOLLOW)
18 }
19
20 hasVideoAbusesRight () {
21 return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_ABUSES)
22 }
23
24 hasVideoBlacklistRight () {
25 return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)
26 }
27
28 hasJobsRight () {
29 return this.auth.getUser().hasRight(UserRight.MANAGE_JOBS)
30 }
7} 31}
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 473801822..a24039fc6 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,16 +1,10 @@
1<div class="row"> 1<p-dataTable
2 <div class="content-padding"> 2 [value]="followers" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
3 <h3>Followers list</h3> 3 sortField="createdAt" (onLazyLoad)="loadLazy($event)"
4 4>
5 <p-dataTable 5 <p-column field="id" header="ID"></p-column>
6 [value]="followers" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" 6 <p-column field="follower.host" header="Host"></p-column>
7 sortField="createdAt" (onLazyLoad)="loadLazy($event)" 7 <p-column field="follower.score" header="Score"></p-column>
8 > 8 <p-column field="state" header="State"></p-column>
9 <p-column field="id" header="ID"></p-column> 9 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
10 <p-column field="follower.host" header="Host"></p-column> 10</p-dataTable>
11 <p-column field="follower.score" header="Score"></p-column>
12 <p-column field="state" header="State"></p-column>
13 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
14 </p-dataTable>
15 </div>
16</div>
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.scss b/client/src/app/+admin/follows/followers-list/followers-list.component.scss
index 0a0f621c6..e69de29bb 100644
--- a/client/src/app/+admin/follows/followers-list/followers-list.component.scss
+++ b/client/src/app/+admin/follows/followers-list/followers-list.component.scss
@@ -1,3 +0,0 @@
1.btn {
2 margin-top: 10px;
3}
diff --git a/client/src/app/+admin/follows/following-add/following-add.component.html b/client/src/app/+admin/follows/following-add/following-add.component.html
index 8e7dddc11..25bab9d0d 100644
--- a/client/src/app/+admin/follows/following-add/following-add.component.html
+++ b/client/src/app/+admin/follows/following-add/following-add.component.html
@@ -1,35 +1,22 @@
1<div class="row"> 1<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
2 <div class="content-padding">
3 2
4 <h3>Add following</h3> 3<form (ngSubmit)="addFollowing()">
4 <div class="form-group">
5 <label for="hosts">1 host (without "http://") per line</label>
5 6
6 <div *ngIf="error" class="alert alert-danger">{{ error }}</div> 7 <textarea
8 type="text" class="form-control" placeholder="example.com" id="hosts" name="hosts"
9 [(ngModel)]="hostsString" (ngModelChange)="onHostsChanged()" [ngClass]="{ 'input-error': hostsError }"
10 ></textarea>
7 11
8 <form (ngSubmit)="addFollowing()" [formGroup]="form"> 12 <div *ngIf="hostsError" class="form-error">
9 <div class="form-group" *ngFor="let host of hosts; let id = index; trackBy:customTrackBy"> 13 {{ hostsError }}
10 <label [for]="'host-' + id">Host (so without "http://")</label> 14 </div>
11 15 </div>
12 <div class="input-group">
13 <input
14 type="text" class="form-control" placeholder="example.com"
15 [id]="'host-' + id" [formControlName]="'host-' + id"
16 />
17 <span class="input-group-btn">
18 <button *ngIf="displayAddField(id)" (click)="addField()" class="btn btn-default" type="button">+</button>
19 <button *ngIf="displayRemoveField(id)" (click)="removeField(id)" class="btn btn-default" type="button">-</button>
20 </span>
21 </div>
22
23 <div [hidden]="form.controls['host-' + id].valid || form.controls['host-' + id].pristine" class="alert alert-warning">
24 It should be a valid host.
25 </div>
26 </div>
27
28 <div *ngIf="canMakeFriends() === false" class="alert alert-warning">
29 It seems that you are not on a HTTPS server. Your webserver need to have TLS activated in order to follow servers.
30 </div>
31 16
32 <input type="submit" value="Add following" class="btn btn-default" [disabled]="!isFormValid()"> 17 <div *ngIf="httpEnabled() === false" class="alert alert-warning">
33 </form> 18 It seems that you are not on a HTTPS server. Your webserver needs to have TLS activated in order to follow servers.
34 </div> 19 </div>
35</div> 20
21 <input type="submit" value="Add following" [disabled]="hostsError || !hostsString" class="btn btn-default">
22</form>
diff --git a/client/src/app/+admin/follows/following-add/following-add.component.scss b/client/src/app/+admin/follows/following-add/following-add.component.scss
index 5fde51636..2cb3efe28 100644
--- a/client/src/app/+admin/follows/following-add/following-add.component.scss
+++ b/client/src/app/+admin/follows/following-add/following-add.component.scss
@@ -1,7 +1,9 @@
1table { 1textarea {
2 margin-bottom: 40px; 2 height: 250px;
3} 3}
4 4
5.input-group-btn button { 5input[type=submit] {
6 width: 35px; 6 @include peertube-button;
7 @include orange-button;
7} 8}
9
diff --git a/client/src/app/+admin/follows/following-add/following-add.component.ts b/client/src/app/+admin/follows/following-add/following-add.component.ts
index 814c6f1a1..bf842129d 100644
--- a/client/src/app/+admin/follows/following-add/following-add.component.ts
+++ b/client/src/app/+admin/follows/following-add/following-add.component.ts
@@ -1,9 +1,6 @@
1import { Component, OnInit } from '@angular/core' 1import { Component } from '@angular/core'
2import { FormControl, FormGroup } from '@angular/forms'
3import { Router } from '@angular/router' 2import { Router } from '@angular/router'
4
5import { NotificationsService } from 'angular2-notifications' 3import { NotificationsService } from 'angular2-notifications'
6
7import { ConfirmService } from '../../../core' 4import { ConfirmService } from '../../../core'
8import { validateHost } from '../../../shared' 5import { validateHost } from '../../../shared'
9import { FollowService } from '../shared' 6import { FollowService } from '../shared'
@@ -13,9 +10,9 @@ import { FollowService } from '../shared'
13 templateUrl: './following-add.component.html', 10 templateUrl: './following-add.component.html',
14 styleUrls: [ './following-add.component.scss' ] 11 styleUrls: [ './following-add.component.scss' ]
15}) 12})
16export class FollowingAddComponent implements OnInit { 13export class FollowingAddComponent {
17 form: FormGroup 14 hostsString = ''
18 hosts: string[] = [ ] 15 hostsError: string = null
19 error: string = null 16 error: string = null
20 17
21 constructor ( 18 constructor (
@@ -25,76 +22,50 @@ export class FollowingAddComponent implements OnInit {
25 private followService: FollowService 22 private followService: FollowService
26 ) {} 23 ) {}
27 24
28 ngOnInit () { 25 httpEnabled () {
29 this.form = new FormGroup({})
30 this.addField()
31 }
32
33 addField () {
34 this.form.addControl(`host-${this.hosts.length}`, new FormControl('', [ validateHost ]))
35 this.hosts.push('')
36 }
37
38 canMakeFriends () {
39 return window.location.protocol === 'https:' 26 return window.location.protocol === 'https:'
40 } 27 }
41 28
42 customTrackBy (index: number, obj: any): any { 29 onHostsChanged () {
43 return index 30 this.hostsError = null
44 }
45
46 displayAddField (index: number) {
47 return index === (this.hosts.length - 1)
48 }
49 31
50 displayRemoveField (index: number) { 32 const newHostsErrors = []
51 return (index !== 0 || this.hosts.length > 1) && index !== (this.hosts.length - 1) 33 const hosts = this.getNotEmptyHosts()
52 }
53 34
54 isFormValid () { 35 for (const host of hosts) {
55 // Do not check the last input 36 if (validateHost(host) === false) {
56 for (let i = 0; i < this.hosts.length - 1; i++) { 37 newHostsErrors.push(`${host} is not valid`)
57 if (!this.form.controls[`host-${i}`].valid) return false 38 }
58 } 39 }
59 40
60 const lastIndex = this.hosts.length - 1 41 if (newHostsErrors.length !== 0) {
61 // If the last input (which is not the first) is empty, it's ok 42 this.hostsError = newHostsErrors.join('. ')
62 if (this.hosts[lastIndex] === '' && lastIndex !== 0) {
63 return true
64 } else {
65 return this.form.controls[`host-${lastIndex}`].valid
66 } 43 }
67 } 44 }
68 45
69 removeField (index: number) {
70 // Remove the last control
71 this.form.removeControl(`host-${this.hosts.length - 1}`)
72 this.hosts.splice(index, 1)
73 }
74
75 addFollowing () { 46 addFollowing () {
76 this.error = '' 47 this.error = ''
77 48
78 const notEmptyHosts = this.getNotEmptyHosts() 49 const hosts = this.getNotEmptyHosts()
79 if (notEmptyHosts.length === 0) { 50 if (hosts.length === 0) {
80 this.error = 'You need to specify at least 1 host.' 51 this.error = 'You need to specify hosts to follow.'
81 return
82 } 52 }
83 53
84 if (!this.isHostsUnique(notEmptyHosts)) { 54 if (!this.isHostsUnique(hosts)) {
85 this.error = 'Hosts need to be unique.' 55 this.error = 'Hosts need to be unique.'
86 return 56 return
87 } 57 }
88 58
89 const confirmMessage = 'Are you sure to make friends with:<br /> - ' + notEmptyHosts.join('<br /> - ') 59 const confirmMessage = 'If you confirm, you will send a follow request to:<br /> - ' + hosts.join('<br /> - ')
90 this.confirmService.confirm(confirmMessage, 'Follow new server(s)').subscribe( 60 this.confirmService.confirm(confirmMessage, 'Follow new server(s)').subscribe(
91 res => { 61 res => {
92 if (res === false) return 62 if (res === false) return
93 63
94 this.followService.follow(notEmptyHosts).subscribe( 64 this.followService.follow(hosts).subscribe(
95 status => { 65 status => {
96 this.notificationsService.success('Success', 'Follow request(s) sent!') 66 this.notificationsService.success('Success', 'Follow request(s) sent!')
97 this.router.navigate([ '/admin/follows/following-list' ]) 67
68 setTimeout(() => this.router.navigate([ '/admin/follows/following-list' ]), 500)
98 }, 69 },
99 70
100 err => this.notificationsService.error('Error', err.message) 71 err => this.notificationsService.error('Error', err.message)
@@ -103,18 +74,15 @@ export class FollowingAddComponent implements OnInit {
103 ) 74 )
104 } 75 }
105 76
106 private getNotEmptyHosts () {
107 const notEmptyHosts = []
108
109 Object.keys(this.form.value).forEach((hostKey) => {
110 const host = this.form.value[hostKey]
111 if (host !== '') notEmptyHosts.push(host)
112 })
113
114 return notEmptyHosts
115 }
116
117 private isHostsUnique (hosts: string[]) { 77 private isHostsUnique (hosts: string[]) {
118 return hosts.every(host => hosts.indexOf(host) === hosts.lastIndexOf(host)) 78 return hosts.every(host => hosts.indexOf(host) === hosts.lastIndexOf(host))
119 } 79 }
80
81 private getNotEmptyHosts () {
82 const hosts = this.hostsString
83 .split('\n')
84 .filter(host => host && host.length !== 0) // Eject empty hosts
85
86 return hosts
87 }
120} 88}
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 a73084312..2b6cc9113 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,20 +1,14 @@
1<div class="row"> 1<p-dataTable
2 <div class="content-padding"> 2 [value]="following" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
3 <h3>Following list</h3> 3 sortField="createdAt" (onLazyLoad)="loadLazy($event)"
4 4>
5 <p-dataTable 5 <p-column field="id" header="ID"></p-column>
6 [value]="following" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" 6 <p-column field="following.host" header="Host"></p-column>
7 sortField="createdAt" (onLazyLoad)="loadLazy($event)" 7 <p-column field="state" header="State"></p-column>
8 > 8 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
9 <p-column field="id" header="ID"></p-column> 9 <p-column styleClass="action-cell">
10 <p-column field="following.host" header="Host"></p-column> 10 <ng-template pTemplate="body" let-following="rowData">
11 <p-column field="state" header="State"></p-column> 11 <my-delete-button (click)="removeFollowing(following)"></my-delete-button>
12 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> 12 </ng-template>
13 <p-column header="Unfollow" styleClass="action-cell"> 13 </p-column>
14 <ng-template pTemplate="body" let-following="rowData"> 14</p-dataTable>
15 <span (click)="removeFollowing(following)" class="glyphicon glyphicon-remove glyphicon-black" title="Unfollow"></span>
16 </ng-template>
17 </p-column>
18 </p-dataTable>
19 </div>
20</div>
diff --git a/client/src/app/+admin/follows/follows.component.html b/client/src/app/+admin/follows/follows.component.html
index b67bc9736..1baba5a4d 100644
--- a/client/src/app/+admin/follows/follows.component.html
+++ b/client/src/app/+admin/follows/follows.component.html
@@ -1,4 +1,6 @@
1<div class="follows-menu"> 1<div class="admin-sub-header">
2 <div class="admin-sub-title">Manage follows</div>
3
2 <tabset #followsMenuTabs> 4 <tabset #followsMenuTabs>
3 <tab *ngFor="let link of links"> 5 <tab *ngFor="let link of links">
4 <ng-template tabHeading> 6 <ng-template tabHeading>
@@ -8,4 +10,6 @@
8 </tabset> 10 </tabset>
9</div> 11</div>
10 12
13
14
11<router-outlet></router-outlet> 15<router-outlet></router-outlet>
diff --git a/client/src/app/+admin/follows/follows.component.scss b/client/src/app/+admin/follows/follows.component.scss
index d8ab41975..835fa3b78 100644
--- a/client/src/app/+admin/follows/follows.component.scss
+++ b/client/src/app/+admin/follows/follows.component.scss
@@ -1,21 +1,4 @@
1.follows-menu { 1.admin-sub-title {
2 margin-top: 20px; 2 flex-grow: 0;
3} 3 margin-right: 30px;
4
5tabset /deep/ {
6 .nav-link {
7 padding: 0;
8 }
9
10 .tab-link {
11 display: block;
12 text-align: center;
13 height: 40px;
14 width: 120px;
15 line-height: 40px;
16
17 &:hover, &:active, &:focus {
18 text-decoration: none !important;
19 }
20 }
21} 4}
diff --git a/client/src/app/+admin/follows/follows.component.ts b/client/src/app/+admin/follows/follows.component.ts
index a1be82585..f29ad384f 100644
--- a/client/src/app/+admin/follows/follows.component.ts
+++ b/client/src/app/+admin/follows/follows.component.ts
@@ -47,7 +47,7 @@ export class FollowsComponent implements OnInit, AfterViewInit {
47 for (let i = 0; i < this.links.length; i++) { 47 for (let i = 0; i < this.links.length; i++) {
48 const path = this.links[i].path 48 const path = this.links[i].path
49 49
50 if (url.endsWith(path) === true) { 50 if (url.endsWith(path) === true && this.followsMenuTabs.tabs[i]) {
51 this.followsMenuTabs.tabs[i].active = true 51 this.followsMenuTabs.tabs[i].active = true
52 return 52 return
53 } 53 }
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 a90267172..7aa5f4254 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
@@ -1,18 +1,20 @@
1<div class="row"> 1<div class="admin-sub-header">
2 <div class="content-padding"> 2 <div class="admin-sub-title">Jobs list</div>
3 <h3>Jobs list</h3>
4
5 <p-dataTable
6 [value]="jobs" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
7 sortField="createdAt" (onLazyLoad)="loadLazy($event)"
8 >
9 <p-column field="id" header="ID"></p-column>
10 <p-column field="category" header="Category"></p-column>
11 <p-column field="handlerName" header="Handler name"></p-column>
12 <p-column field="handlerInputData" header="Input data"></p-column>
13 <p-column field="state" header="State"></p-column>
14 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
15 <p-column field="updatedAt" header="Updated date"></p-column>
16 </p-dataTable>
17 </div>
18</div> 3</div>
4
5<p-dataTable
6 [value]="jobs" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
7 sortField="createdAt" (onLazyLoad)="loadLazy($event)" [scrollable]="true" [virtualScroll]="true" [scrollHeight]="scrollHeight"
8>
9 <p-column field="id" header="ID" [style]="{ width: '40px' }"></p-column>
10 <p-column field="category" header="Category" [style]="{ width: '100px' }"></p-column>
11 <p-column field="handlerName" header="Handler name" [style]="{ width: '200px' }"></p-column>
12 <p-column header="Input data">
13 <ng-template pTemplate="body" let-job="rowData">
14 <pre>{{ job.handlerInputData }}</pre>
15 </ng-template>
16 </p-column>
17 <p-column field="state" header="State" [style]="{ width: '100px' }"></p-column>
18 <p-column field="createdAt" header="Created date" [sortable]="true" [style]="{ width: '250px' }"></p-column>
19 <p-column field="updatedAt" header="Updated date" [style]="{ width: '250px' }"></p-column>
20</p-dataTable>
diff --git a/client/src/app/+admin/jobs/jobs-list/jobs-list.component.scss b/client/src/app/+admin/jobs/jobs-list/jobs-list.component.scss
new file mode 100644
index 000000000..9dde13216
--- /dev/null
+++ b/client/src/app/+admin/jobs/jobs-list/jobs-list.component.scss
@@ -0,0 +1,3 @@
1pre {
2 font-size: 13px;
3}
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 88fe259fb..f93847f29 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
@@ -1,22 +1,24 @@
1import { Component } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { NotificationsService } from 'angular2-notifications' 2import { NotificationsService } from 'angular2-notifications'
3import { SortMeta } from 'primeng/primeng' 3import { SortMeta } from 'primeng/primeng'
4import { Job } from '../../../../../../shared/index' 4import { Job } from '../../../../../../shared/index'
5import { RestPagination, RestTable } from '../../../shared' 5import { RestPagination, RestTable } from '../../../shared'
6import { viewportHeight } from '../../../shared/misc/utils'
6import { JobService } from '../shared' 7import { JobService } from '../shared'
7import { RestExtractor } from '../../../shared/rest/rest-extractor.service' 8import { RestExtractor } from '../../../shared/rest/rest-extractor.service'
8 9
9@Component({ 10@Component({
10 selector: 'my-jobs-list', 11 selector: 'my-jobs-list',
11 templateUrl: './jobs-list.component.html', 12 templateUrl: './jobs-list.component.html',
12 styleUrls: [ ] 13 styleUrls: [ './jobs-list.component.scss' ]
13}) 14})
14export class JobsListComponent extends RestTable { 15export class JobsListComponent extends RestTable implements OnInit {
15 jobs: Job[] = [] 16 jobs: Job[] = []
16 totalRecords = 0 17 totalRecords = 0
17 rowsPerPage = 10 18 rowsPerPage = 20
18 sort: SortMeta = { field: 'createdAt', order: 1 } 19 sort: SortMeta = { field: 'createdAt', order: 1 }
19 pagination: RestPagination = { count: this.rowsPerPage, start: 0 } 20 pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
21 scrollHeight = ''
20 22
21 constructor ( 23 constructor (
22 private notificationsService: NotificationsService, 24 private notificationsService: NotificationsService,
@@ -26,10 +28,14 @@ export class JobsListComponent extends RestTable {
26 super() 28 super()
27 } 29 }
28 30
31 ngOnInit () {
32 // 270 -> headers + footer...
33 this.scrollHeight = (viewportHeight() - 380) + 'px'
34 }
35
29 protected loadData () { 36 protected loadData () {
30 this.jobsService 37 this.jobsService
31 .getJobs(this.pagination, this.sort) 38 .getJobs(this.pagination, this.sort)
32 .map(res => this.restExtractor.applyToResultListData(res, this.formatJob.bind(this)))
33 .subscribe( 39 .subscribe(
34 resultList => { 40 resultList => {
35 this.jobs = resultList.data 41 this.jobs = resultList.data
@@ -39,12 +45,4 @@ export class JobsListComponent extends RestTable {
39 err => this.notificationsService.error('Error', err.message) 45 err => this.notificationsService.error('Error', err.message)
40 ) 46 )
41 } 47 }
42
43 private formatJob (job: Job) {
44 const handlerInputData = JSON.stringify(job.handlerInputData)
45
46 return Object.assign(job, {
47 handlerInputData
48 })
49 }
50} 48}
diff --git a/client/src/app/+admin/jobs/shared/job.service.ts b/client/src/app/+admin/jobs/shared/job.service.ts
index 49f1ab6f5..0cfbdbbea 100644
--- a/client/src/app/+admin/jobs/shared/job.service.ts
+++ b/client/src/app/+admin/jobs/shared/job.service.ts
@@ -25,6 +25,13 @@ export class JobService {
25 25
26 return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL, { params }) 26 return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL, { params })
27 .map(res => this.restExtractor.convertResultListDateToHuman(res)) 27 .map(res => this.restExtractor.convertResultListDateToHuman(res))
28 .map(res => this.restExtractor.applyToResultListData(res, this.prettyPrintData))
28 .catch(err => this.restExtractor.handleError(err)) 29 .catch(err => this.restExtractor.handleError(err))
29 } 30 }
31
32 private prettyPrintData (obj: Job) {
33 const handlerInputData = JSON.stringify(obj.handlerInputData, null, 2)
34
35 return Object.assign(obj, { handlerInputData })
36 }
30} 37}
diff --git a/client/src/app/+admin/users/shared/user.service.ts b/client/src/app/+admin/users/shared/user.service.ts
index e4bd5df37..dc77cc1d8 100644
--- a/client/src/app/+admin/users/shared/user.service.ts
+++ b/client/src/app/+admin/users/shared/user.service.ts
@@ -1,14 +1,12 @@
1import { Injectable } from '@angular/core'
2import { HttpClient, HttpParams } from '@angular/common/http' 1import { HttpClient, HttpParams } from '@angular/common/http'
3import { Observable } from 'rxjs/Observable' 2import { Injectable } from '@angular/core'
3import { BytesPipe } from 'ngx-pipes'
4import { SortMeta } from 'primeng/components/common/sortmeta'
4import 'rxjs/add/operator/catch' 5import 'rxjs/add/operator/catch'
5import 'rxjs/add/operator/map' 6import 'rxjs/add/operator/map'
6 7import { Observable } from 'rxjs/Observable'
7import { SortMeta } from 'primeng/components/common/sortmeta' 8import { ResultList, UserCreate, UserUpdate } from '../../../../../../shared'
8import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe' 9import { RestExtractor, RestPagination, RestService, User } from '../../../shared'
9
10import { RestExtractor, User, RestPagination, RestService } from '../../../shared'
11import { UserCreate, UserUpdate, ResultList } from '../../../../../../shared'
12 10
13@Injectable() 11@Injectable()
14export class UserService { 12export class UserService {
diff --git a/client/src/app/+admin/users/user-edit/user-edit.component.html b/client/src/app/+admin/users/user-edit/user-edit.component.html
index 349be13c1..963e2f39a 100644
--- a/client/src/app/+admin/users/user-edit/user-edit.component.html
+++ b/client/src/app/+admin/users/user-edit/user-edit.component.html
@@ -1,73 +1,68 @@
1<div class="row"> 1<div class="admin-sub-title" *ngIf="isCreation() === true">Add user</div>
2 <div class="content-padding"> 2<div class="admin-sub-title" *ngIf="isCreation() === false">Edit user {{ username }}</div>
3 3
4 <h3 *ngIf="isCreation() === true">Add user</h3> 4<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
5 <h3 *ngIf="isCreation() === false">Edit user {{ username }}</h3>
6 5
7 <div *ngIf="error" class="alert alert-danger">{{ error }}</div> 6<form role="form" (ngSubmit)="formValidated()" [formGroup]="form">
8 7 <div class="form-group" *ngIf="isCreation()">
9 <form role="form" (ngSubmit)="formValidated()" [formGroup]="form"> 8 <label for="username">Username</label>
10 <div class="form-group" *ngIf="isCreation()"> 9 <input
11 <label for="username">Username</label> 10 type="text" class="form-control" id="username" placeholder="john"
12 <input 11 formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
13 type="text" class="form-control" id="username" placeholder="john" 12 >
14 formControlName="username" 13 <div *ngIf="formErrors.username" class="form-error">
15 > 14 {{ formErrors.username }}
16 <div *ngIf="formErrors.username" class="alert alert-danger"> 15 </div>
17 {{ formErrors.username }} 16 </div>
18 </div>
19 </div>
20
21 <div class="form-group">
22 <label for="email">Email</label>
23 <input
24 type="text" class="form-control" id="email" placeholder="mail@example.com"
25 formControlName="email"
26 >
27 <div *ngIf="formErrors.email" class="alert alert-danger">
28 {{ formErrors.email }}
29 </div>
30 </div>
31 17
32 <div class="form-group" *ngIf="isCreation()"> 18 <div class="form-group">
33 <label for="password">Password</label> 19 <label for="email">Email</label>
34 <input 20 <input
35 type="password" class="form-control" id="password" 21 type="text" class="form-control" id="email" placeholder="mail@example.com"
36 formControlName="password" 22 formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }"
37 > 23 >
38 <div *ngIf="formErrors.password" class="alert alert-danger"> 24 <div *ngIf="formErrors.email" class="form-error">
39 {{ formErrors.password }} 25 {{ formErrors.email }}
40 </div> 26 </div>
41 </div> 27 </div>
42 28
43 <div class="form-group"> 29 <div class="form-group" *ngIf="isCreation()">
44 <label for="role">Role</label> 30 <label for="password">Password</label>
45 <select class="form-control" id="role" formControlName="role"> 31 <input
46 <option *ngFor="let role of roles" [value]="role.value"> 32 type="password" class="form-control" id="password"
47 {{ role.label }} 33 formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
48 </option> 34 >
49 </select> 35 <div *ngIf="formErrors.password" class="form-error">
36 {{ formErrors.password }}
37 </div>
38 </div>
50 39
51 <div *ngIf="formErrors.role" class="alert alert-danger"> 40 <div class="form-group">
52 {{ formErrors.role }} 41 <label for="role">Role</label>
53 </div> 42 <select class="form-control" id="role" formControlName="role">
54 </div> 43 <option *ngFor="let role of roles" [value]="role.value">
44 {{ role.label }}
45 </option>
46 </select>
55 47
56 <div class="form-group"> 48 <div *ngIf="formErrors.role" class="form-error">
57 <label for="videoQuota">Video quota</label> 49 {{ formErrors.role }}
58 <select class="form-control" id="videoQuota" formControlName="videoQuota"> 50 </div>
59 <option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value"> 51 </div>
60 {{ videoQuotaOption.label }}
61 </option>
62 </select>
63 52
64 <div class="transcoding-information" *ngIf="isTranscodingInformationDisplayed()"> 53 <div class="form-group">
65 Transcoding is enabled on server. The video quota only take in account <strong>original</strong> video. <br /> 54 <label for="videoQuota">Video quota</label>
66 In maximum, this user could use ~ {{ computeQuotaWithTranscoding() | bytes }}. 55 <select class="form-control" id="videoQuota" formControlName="videoQuota">
67 </div> 56 <option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value">
68 </div> 57 {{ videoQuotaOption.label }}
58 </option>
59 </select>
69 60
70 <input type="submit" value="{{ getFormButtonTitle() }}" class="btn btn-default" [disabled]="!form.valid"> 61 <div class="transcoding-information" *ngIf="isTranscodingInformationDisplayed()">
71 </form> 62 Transcoding is enabled on server. The video quota only take in account <strong>original</strong> video. <br />
63 In maximum, this user could use ~ {{ computeQuotaWithTranscoding() | bytes }}.
64 </div>
72 </div> 65 </div>
73</div> 66
67 <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid">
68</form>
diff --git a/client/src/app/+admin/users/user-edit/user-edit.component.scss b/client/src/app/+admin/users/user-edit/user-edit.component.scss
index 401caa0c6..68d270c19 100644
--- a/client/src/app/+admin/users/user-edit/user-edit.component.scss
+++ b/client/src/app/+admin/users/user-edit/user-edit.component.scss
@@ -1,3 +1,21 @@
1.admin-sub-title {
2 margin-bottom: 30px;
3}
4
5input:not([type=submit]) {
6 @include peertube-input-text(340px);
7 display: block;
8}
9
10select {
11 @include peertube-select(340px);
12}
13
14input[type=submit] {
15 @include peertube-button;
16 @include orange-button;
17}
18
1.transcoding-information { 19.transcoding-information {
2 margin-top: 5px; 20 margin-top: 5px;
3 font-size: 11px; 21 font-size: 11px;
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 16a8a8033..b3d90ba1e 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
@@ -1,35 +1,26 @@
1<div class="row"> 1<div class="admin-sub-header">
2 <div class="content-padding"> 2 <div class="admin-sub-title">Users list</div>
3 3
4 <h3>Users list</h3> 4 <a class="add-button" routerLink="/admin/users/add">
5 5 <span class="icon icon-add"></span>
6 <p-dataTable 6 Add user
7 [value]="users" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" 7 </a>
8 sortField="id" (onLazyLoad)="loadLazy($event)"
9 >
10 <p-column field="id" header="ID" [sortable]="true"></p-column>
11 <p-column field="username" header="Username" [sortable]="true"></p-column>
12 <p-column field="email" header="Email"></p-column>
13 <p-column field="videoQuota" header="Video quota"></p-column>
14 <p-column field="roleLabel" header="Role"></p-column>
15 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
16 <p-column header="Edit" styleClass="action-cell">
17 <ng-template pTemplate="body" let-user="rowData">
18 <a [routerLink]="getRouterUserEditLink(user)" title="Edit this user">
19 <span class="glyphicon glyphicon-pencil glyphicon-black"></span>
20 </a>
21 </ng-template>
22 </p-column>
23 <p-column header="Delete" styleClass="action-cell">
24 <ng-template pTemplate="body" let-user="rowData">
25 <span (click)="removeUser(user)" class="glyphicon glyphicon-remove glyphicon-black" title="Remove this user"></span>
26 </ng-template>
27 </p-column>
28 </p-dataTable>
29
30 <a class="add-user btn btn-success pull-right" [routerLink]="['/admin/users/add']">
31 <span class="glyphicon glyphicon-plus"></span>
32 Add user
33 </a>
34 </div>
35</div> 8</div>
9
10<p-dataTable
11 [value]="users" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
12 sortField="id" (onLazyLoad)="loadLazy($event)"
13>
14 <p-column field="id" header="ID" [sortable]="true"></p-column>
15 <p-column field="username" header="Username" [sortable]="true"></p-column>
16 <p-column field="email" header="Email"></p-column>
17 <p-column field="videoQuota" header="Video quota"></p-column>
18 <p-column field="roleLabel" header="Role"></p-column>
19 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
20 <p-column styleClass="action-cell">
21 <ng-template pTemplate="body" let-user="rowData">
22 <my-edit-button [routerLink]="getRouterUserEditLink(user)"></my-edit-button>
23 <my-delete-button (click)="removeUser(user)"></my-delete-button>
24 </ng-template>
25 </p-column>
26</p-dataTable>
diff --git a/client/src/app/+admin/users/user-list/user-list.component.scss b/client/src/app/+admin/users/user-list/user-list.component.scss
index 71adef653..8b22f67ff 100644
--- a/client/src/app/+admin/users/user-list/user-list.component.scss
+++ b/client/src/app/+admin/users/user-list/user-list.component.scss
@@ -1,3 +1,11 @@
1.add-user { 1 .add-button {
2 margin-top: 10px; 2 @include peertube-button-link;
3} 3 @include orange-button;
4
5 .icon.icon-add {
6 @include icon(22px);
7
8 margin-right: 3px;
9 background-image: url('../../../../assets/images/admin/add.svg');
10 }
11 }
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 ab0a9d99f..d655a5e9b 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
@@ -1,24 +1,19 @@
1<div class="row"> 1<div class="admin-sub-header">
2 <div class="content-padding"> 2 <div class="admin-sub-title">Video abuses list</div>
3
4 <h3>Video abuses list</h3>
5
6 <p-dataTable
7 [value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
8 sortField="id" (onLazyLoad)="loadLazy($event)"
9 >
10 <p-column field="id" header="ID" [sortable]="true"></p-column>
11 <p-column field="reason" header="Reason"></p-column>
12 <p-column field="reporterServerHost" header="Reporter server host"></p-column>
13 <p-column field="reporterUsername" header="Reporter username"></p-column>
14 <p-column field="videoName" header="Video name"></p-column>
15 <p-column header="Video" styleClass="action-cell">
16 <ng-template pTemplate="body" let-videoAbuse="rowData">
17 <a [routerLink]="getRouterVideoLink(videoAbuse.videoId)" title="Go to the video">{{ videoAbuse.videoId }}</a>
18 </ng-template>
19 </p-column>
20 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
21 </p-dataTable>
22
23 </div>
24</div> 3</div>
4
5<p-dataTable
6 [value]="videoAbuses" [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="reason" header="Reason"></p-column>
11 <p-column field="reporterServerHost" header="Reporter server host"></p-column>
12 <p-column field="reporterUsername" header="Reporter username"></p-column>
13 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
14 <p-column header="Video">
15 <ng-template pTemplate="body" let-videoAbuse="rowData">
16 <a [routerLink]="getRouterVideoLink(videoAbuse.videoId)" title="Go to the video">{{ videoAbuse.videoName }}</a>
17 </ng-template>
18 </p-column>
19</p-dataTable>
diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.scss b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.scss
new file mode 100644
index 000000000..6a4762650
--- /dev/null
+++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.scss
@@ -0,0 +1,6 @@
1/deep/ a {
2
3 &, &:hover, &:active, &:focus {
4 color: #000;
5 }
6}
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 654603d01..b4d3bbd24 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
@@ -8,7 +8,8 @@ import { VideoAbuse } from '../../../../../../shared'
8 8
9@Component({ 9@Component({
10 selector: 'my-video-abuse-list', 10 selector: 'my-video-abuse-list',
11 templateUrl: './video-abuse-list.component.html' 11 templateUrl: './video-abuse-list.component.html',
12 styleUrls: [ './video-abuse-list.component.scss']
12}) 13})
13export class VideoAbuseListComponent extends RestTable implements OnInit { 14export class VideoAbuseListComponent extends RestTable implements OnInit {
14 videoAbuses: VideoAbuse[] = [] 15 videoAbuses: VideoAbuse[] = []
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 05d116798..1d813fa07 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
@@ -18,7 +18,7 @@
18 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> 18 <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
19 <p-column header="Delete" styleClass="action-cell"> 19 <p-column header="Delete" styleClass="action-cell">
20 <ng-template pTemplate="body" let-entry="rowData"> 20 <ng-template pTemplate="body" let-entry="rowData">
21 <span (click)="removeVideoFromBlacklist(entry)" class="glyphicon glyphicon-remove glyphicon-black" title="Remove this video from blacklist"></span> 21 <my-delete-button (click)="removeVideoFromBlacklist(entry)"></my-delete-button>
22 </ng-template> 22 </ng-template>
23 </p-column> 23 </p-column>
24 </p-dataTable> 24 </p-dataTable>