aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app
diff options
context:
space:
mode:
authorChocobozzz <florian.bigard@gmail.com>2017-12-06 15:07:17 +0100
committerChocobozzz <florian.bigard@gmail.com>2017-12-06 15:07:17 +0100
commitce0e281d46a7b574dcccb47958743656532bd312 (patch)
treeb2d26aef176f39ebdf37e5e7c28d6f6fb905bf10 /client/src/app
parent7d763d97497df1bbf7a01f61aa916d99a1338a33 (diff)
downloadPeerTube-ce0e281d46a7b574dcccb47958743656532bd312.tar.gz
PeerTube-ce0e281d46a7b574dcccb47958743656532bd312.tar.zst
PeerTube-ce0e281d46a7b574dcccb47958743656532bd312.zip
Client bulk delete
Diffstat (limited to 'client/src/app')
-rw-r--r--client/src/app/account/account-videos/account-videos.component.html36
-rw-r--r--client/src/app/account/account-videos/account-videos.component.scss102
-rw-r--r--client/src/app/account/account-videos/account-videos.component.ts49
3 files changed, 140 insertions, 47 deletions
diff --git a/client/src/app/account/account-videos/account-videos.component.html b/client/src/app/account/account-videos/account-videos.component.html
index 30db69429..030c2f19c 100644
--- a/client/src/app/account/account-videos/account-videos.component.html
+++ b/client/src/app/account/account-videos/account-videos.component.html
@@ -5,7 +5,9 @@
5 (scrolled)="onNearOfBottom()" 5 (scrolled)="onNearOfBottom()"
6 (scrolledUp)="onNearOfTop()" 6 (scrolledUp)="onNearOfTop()"
7> 7>
8 <div class="video" *ngFor="let video of videos"> 8 <div class="video" *ngFor="let video of videos; let i = index">
9 <input type="checkbox" [(ngModel)]="checkedVideos[video.id]" />
10
9 <my-video-thumbnail [video]="video"></my-video-thumbnail> 11 <my-video-thumbnail [video]="video"></my-video-thumbnail>
10 12
11 <div class="video-info"> 13 <div class="video-info">
@@ -13,14 +15,30 @@
13 <span class="video-info-date-views">{{ video.createdAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span> 15 <span class="video-info-date-views">{{ video.createdAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span>
14 </div> 16 </div>
15 17
16 <a class="action-button action-button-delete" (click)="deleteVideo(video)"> 18 <!-- Display only once -->
17 <span class="icon icon-delete"></span> 19 <div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0">
18 Delete 20 <div class="action-selection-mode-child">
19 </a> 21 <span class="action-button" (click)="abortSelectionMode()">
22 Cancel
23 </span>
24
25 <span class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
26 <span class="icon icon-delete-white"></span>
27 Delete
28 </span>
29 </div>
30 </div>
31
32 <ng-template [ngIf]="isInSelectionMode() === false">
33 <span class="action-button action-button-delete" (click)="deleteVideo(video)">
34 <span class="icon icon-delete-grey"></span>
35 Delete
36 </span>
20 37
21 <a class="action-button" [routerLink]="[ '/videos', video.id, '/edit' ]"> 38 <a class="action-button" [routerLink]="[ '/videos', 'edit', video.uuid ]">
22 <span class="icon icon-edit"></span> 39 <span class="icon icon-edit"></span>
23 Edit 40 Edit
24 </a> 41 </a>
42 </ng-template>
25 </div> 43 </div>
26</div> 44</div>
diff --git a/client/src/app/account/account-videos/account-videos.component.scss b/client/src/app/account/account-videos/account-videos.component.scss
index e7fe662b1..e76e3f4e5 100644
--- a/client/src/app/account/account-videos/account-videos.component.scss
+++ b/client/src/app/account/account-videos/account-videos.component.scss
@@ -1,8 +1,74 @@
1.action-selection-mode {
2 width: 174px;
3
4 .action-selection-mode-child {
5 position: fixed;
6 }
7}
8
9.action-button {
10 @include peertube-button-link;
11
12 font-size: 15px;
13 font-weight: $font-semibold;
14 color: #585858;
15 background-color: #E5E5E5;
16
17 &:hover {
18 background-color: #EFEFEF;
19 }
20
21 &.action-button-delete {
22 margin-right: 10px;
23 }
24
25 &.action-button-delete-selection {
26 background-color: $orange-color;
27 color: #fff;
28
29 &:hover {
30 background-color: $orange-hoover-color;
31 }
32 }
33
34 .icon {
35 display: inline-block;
36 background-repeat: no-repeat;
37 background-size: contain;
38 width: 21px;
39 height: 21px;
40 vertical-align: middle;
41 position: relative;
42 top: -2px;
43
44 &.icon-edit {
45 background-image: url('../../../assets/images/account/edit.svg');
46 }
47
48 &.icon-delete-grey {
49 background-image: url('../../../assets/images/account/delete-grey.svg');
50 }
51
52 &.icon-delete-white {
53 background-image: url('../../../assets/images/account/delete-white.svg');
54 }
55 }
56}
57
1.video { 58.video {
2 display: flex; 59 display: flex;
3 height: 130px; 60 height: 130px;
4 padding-bottom: 20px; 61 padding-bottom: 20px;
5 62
63 input[type=checkbox] {
64 margin-right: 20px;
65 outline: 0;
66 }
67
68 &:first-child {
69 margin-top: 47px;
70 }
71
6 &:not(:last-child) { 72 &:not(:last-child) {
7 margin-bottom: 20px; 73 margin-bottom: 20px;
8 border-bottom: 1px solid #C6C6C6; 74 border-bottom: 1px solid #C6C6C6;
@@ -24,40 +90,4 @@
24 font-size: 13px; 90 font-size: 13px;
25 } 91 }
26 } 92 }
27
28 .action-button {
29 @include peertube-button-link;
30
31 font-size: 15px;
32 font-weight: $font-semibold;
33 color: #585858;
34 background-color: #E5E5E5;
35
36 &:hover {
37 background-color: #EFEFEF;
38 }
39
40 &.action-button-delete {
41 margin-right: 10px;
42 }
43
44 .icon.icon-edit, .icon.icon-delete {
45 display: inline-block;
46 background-repeat: no-repeat;
47 background-size: contain;
48 width: 21px;
49 height: 21px;
50 vertical-align: middle;
51 position: relative;
52 top: -2px;
53
54 &.icon-edit {
55 background-image: url('../../../assets/images/account/edit.svg');
56 }
57
58 &.icon-delete {
59 background-image: url('../../../assets/images/account/delete.svg');
60 }
61 }
62 }
63} 93}
diff --git a/client/src/app/account/account-videos/account-videos.component.ts b/client/src/app/account/account-videos/account-videos.component.ts
index 9c2cc2404..5f12cfce0 100644
--- a/client/src/app/account/account-videos/account-videos.component.ts
+++ b/client/src/app/account/account-videos/account-videos.component.ts
@@ -1,6 +1,9 @@
1import { Component, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 2import { ActivatedRoute, Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications' 3import { NotificationsService } from 'angular2-notifications'
4import 'rxjs/add/observable/from'
5import 'rxjs/add/operator/concatAll'
6import { Observable } from 'rxjs/Observable'
4import { ConfirmService } from '../../core/confirm' 7import { ConfirmService } from '../../core/confirm'
5import { AbstractVideoList } from '../../shared/video/abstract-video-list' 8import { AbstractVideoList } from '../../shared/video/abstract-video-list'
6import { Video } from '../../shared/video/video.model' 9import { Video } from '../../shared/video/video.model'
@@ -14,6 +17,7 @@ import { VideoService } from '../../shared/video/video.service'
14export class AccountVideosComponent extends AbstractVideoList implements OnInit { 17export class AccountVideosComponent extends AbstractVideoList implements OnInit {
15 titlePage = 'My videos' 18 titlePage = 'My videos'
16 currentRoute = '/account/videos' 19 currentRoute = '/account/videos'
20 checkedVideos: { [ id: number ]: boolean } = {}
17 21
18 constructor (protected router: Router, 22 constructor (protected router: Router,
19 protected route: ActivatedRoute, 23 protected route: ActivatedRoute,
@@ -27,10 +31,47 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
27 super.ngOnInit() 31 super.ngOnInit()
28 } 32 }
29 33
34 abortSelectionMode () {
35 this.checkedVideos = {}
36 }
37
38 isInSelectionMode () {
39 return Object.keys(this.checkedVideos).some(k => this.checkedVideos[k] === true)
40 }
41
30 getVideosObservable () { 42 getVideosObservable () {
31 return this.videoService.getMyVideos(this.pagination, this.sort) 43 return this.videoService.getMyVideos(this.pagination, this.sort)
32 } 44 }
33 45
46 deleteSelectedVideos () {
47 const toDeleteVideosIds = Object.keys(this.checkedVideos)
48 .filter(k => this.checkedVideos[k] === true)
49 .map(k => parseInt(k, 10))
50
51 this.confirmService.confirm(`Do you really want to delete ${toDeleteVideosIds.length} videos?`, 'Delete').subscribe(
52 res => {
53 if (res === false) return
54
55 const observables: Observable<any>[] = []
56 for (const videoId of toDeleteVideosIds) {
57 const o = this.videoService
58 .removeVideo(videoId)
59 .do(() => this.spliceVideosById(videoId))
60
61 observables.push(o)
62 }
63
64 Observable.from(observables)
65 .concatAll()
66 .subscribe(
67 res => this.notificationsService.success('Success', `${toDeleteVideosIds.length} videos deleted.`),
68
69 err => this.notificationsService.error('Error', err.text)
70 )
71 }
72 )
73 }
74
34 deleteVideo (video: Video) { 75 deleteVideo (video: Video) {
35 this.confirmService.confirm(`Do you really want to delete ${video.name}?`, 'Delete').subscribe( 76 this.confirmService.confirm(`Do you really want to delete ${video.name}?`, 'Delete').subscribe(
36 res => { 77 res => {
@@ -40,8 +81,7 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
40 .subscribe( 81 .subscribe(
41 status => { 82 status => {
42 this.notificationsService.success('Success', `Video ${video.name} deleted.`) 83 this.notificationsService.success('Success', `Video ${video.name} deleted.`)
43 const index = this.videos.findIndex(v => v.id === video.id) 84 this.spliceVideosById(video.id)
44 this.videos.splice(index, 1)
45 }, 85 },
46 86
47 error => this.notificationsService.error('Error', error.text) 87 error => this.notificationsService.error('Error', error.text)
@@ -49,4 +89,9 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
49 } 89 }
50 ) 90 )
51 } 91 }
92
93 private spliceVideosById (id: number) {
94 const index = this.videos.findIndex(v => v.id === id)
95 this.videos.splice(index, 1)
96 }
52} 97}