Client bulk delete
This commit is contained in:
parent
7d763d9749
commit
ce0e281d46
|
@ -5,7 +5,9 @@
|
|||
(scrolled)="onNearOfBottom()"
|
||||
(scrolledUp)="onNearOfTop()"
|
||||
>
|
||||
<div class="video" *ngFor="let video of videos">
|
||||
<div class="video" *ngFor="let video of videos; let i = index">
|
||||
<input type="checkbox" [(ngModel)]="checkedVideos[video.id]" />
|
||||
|
||||
<my-video-thumbnail [video]="video"></my-video-thumbnail>
|
||||
|
||||
<div class="video-info">
|
||||
|
@ -13,14 +15,30 @@
|
|||
<span class="video-info-date-views">{{ video.createdAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span>
|
||||
</div>
|
||||
|
||||
<a class="action-button action-button-delete" (click)="deleteVideo(video)">
|
||||
<span class="icon icon-delete"></span>
|
||||
Delete
|
||||
</a>
|
||||
<!-- Display only once -->
|
||||
<div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0">
|
||||
<div class="action-selection-mode-child">
|
||||
<span class="action-button" (click)="abortSelectionMode()">
|
||||
Cancel
|
||||
</span>
|
||||
|
||||
<a class="action-button" [routerLink]="[ '/videos', video.id, '/edit' ]">
|
||||
<span class="icon icon-edit"></span>
|
||||
Edit
|
||||
</a>
|
||||
<span class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
|
||||
<span class="icon icon-delete-white"></span>
|
||||
Delete
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template [ngIf]="isInSelectionMode() === false">
|
||||
<span class="action-button action-button-delete" (click)="deleteVideo(video)">
|
||||
<span class="icon icon-delete-grey"></span>
|
||||
Delete
|
||||
</span>
|
||||
|
||||
<a class="action-button" [routerLink]="[ '/videos', 'edit', video.uuid ]">
|
||||
<span class="icon icon-edit"></span>
|
||||
Edit
|
||||
</a>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,74 @@
|
|||
.action-selection-mode {
|
||||
width: 174px;
|
||||
|
||||
.action-selection-mode-child {
|
||||
position: fixed;
|
||||
}
|
||||
}
|
||||
|
||||
.action-button {
|
||||
@include peertube-button-link;
|
||||
|
||||
font-size: 15px;
|
||||
font-weight: $font-semibold;
|
||||
color: #585858;
|
||||
background-color: #E5E5E5;
|
||||
|
||||
&:hover {
|
||||
background-color: #EFEFEF;
|
||||
}
|
||||
|
||||
&.action-button-delete {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&.action-button-delete-selection {
|
||||
background-color: $orange-color;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background-color: $orange-hoover-color;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: inline-block;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
|
||||
&.icon-edit {
|
||||
background-image: url('../../../assets/images/account/edit.svg');
|
||||
}
|
||||
|
||||
&.icon-delete-grey {
|
||||
background-image: url('../../../assets/images/account/delete-grey.svg');
|
||||
}
|
||||
|
||||
&.icon-delete-white {
|
||||
background-image: url('../../../assets/images/account/delete-white.svg');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.video {
|
||||
display: flex;
|
||||
height: 130px;
|
||||
padding-bottom: 20px;
|
||||
|
||||
input[type=checkbox] {
|
||||
margin-right: 20px;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-top: 47px;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 1px solid #C6C6C6;
|
||||
|
@ -24,40 +90,4 @@
|
|||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.action-button {
|
||||
@include peertube-button-link;
|
||||
|
||||
font-size: 15px;
|
||||
font-weight: $font-semibold;
|
||||
color: #585858;
|
||||
background-color: #E5E5E5;
|
||||
|
||||
&:hover {
|
||||
background-color: #EFEFEF;
|
||||
}
|
||||
|
||||
&.action-button-delete {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.icon.icon-edit, .icon.icon-delete {
|
||||
display: inline-block;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
|
||||
&.icon-edit {
|
||||
background-image: url('../../../assets/images/account/edit.svg');
|
||||
}
|
||||
|
||||
&.icon-delete {
|
||||
background-image: url('../../../assets/images/account/delete.svg');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { Component, OnInit } from '@angular/core'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { NotificationsService } from 'angular2-notifications'
|
||||
import 'rxjs/add/observable/from'
|
||||
import 'rxjs/add/operator/concatAll'
|
||||
import { Observable } from 'rxjs/Observable'
|
||||
import { ConfirmService } from '../../core/confirm'
|
||||
import { AbstractVideoList } from '../../shared/video/abstract-video-list'
|
||||
import { Video } from '../../shared/video/video.model'
|
||||
|
@ -14,6 +17,7 @@ import { VideoService } from '../../shared/video/video.service'
|
|||
export class AccountVideosComponent extends AbstractVideoList implements OnInit {
|
||||
titlePage = 'My videos'
|
||||
currentRoute = '/account/videos'
|
||||
checkedVideos: { [ id: number ]: boolean } = {}
|
||||
|
||||
constructor (protected router: Router,
|
||||
protected route: ActivatedRoute,
|
||||
|
@ -27,10 +31,47 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
|
|||
super.ngOnInit()
|
||||
}
|
||||
|
||||
abortSelectionMode () {
|
||||
this.checkedVideos = {}
|
||||
}
|
||||
|
||||
isInSelectionMode () {
|
||||
return Object.keys(this.checkedVideos).some(k => this.checkedVideos[k] === true)
|
||||
}
|
||||
|
||||
getVideosObservable () {
|
||||
return this.videoService.getMyVideos(this.pagination, this.sort)
|
||||
}
|
||||
|
||||
deleteSelectedVideos () {
|
||||
const toDeleteVideosIds = Object.keys(this.checkedVideos)
|
||||
.filter(k => this.checkedVideos[k] === true)
|
||||
.map(k => parseInt(k, 10))
|
||||
|
||||
this.confirmService.confirm(`Do you really want to delete ${toDeleteVideosIds.length} videos?`, 'Delete').subscribe(
|
||||
res => {
|
||||
if (res === false) return
|
||||
|
||||
const observables: Observable<any>[] = []
|
||||
for (const videoId of toDeleteVideosIds) {
|
||||
const o = this.videoService
|
||||
.removeVideo(videoId)
|
||||
.do(() => this.spliceVideosById(videoId))
|
||||
|
||||
observables.push(o)
|
||||
}
|
||||
|
||||
Observable.from(observables)
|
||||
.concatAll()
|
||||
.subscribe(
|
||||
res => this.notificationsService.success('Success', `${toDeleteVideosIds.length} videos deleted.`),
|
||||
|
||||
err => this.notificationsService.error('Error', err.text)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
deleteVideo (video: Video) {
|
||||
this.confirmService.confirm(`Do you really want to delete ${video.name}?`, 'Delete').subscribe(
|
||||
res => {
|
||||
|
@ -40,8 +81,7 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
|
|||
.subscribe(
|
||||
status => {
|
||||
this.notificationsService.success('Success', `Video ${video.name} deleted.`)
|
||||
const index = this.videos.findIndex(v => v.id === video.id)
|
||||
this.videos.splice(index, 1)
|
||||
this.spliceVideosById(video.id)
|
||||
},
|
||||
|
||||
error => this.notificationsService.error('Error', error.text)
|
||||
|
@ -49,4 +89,9 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
|
|||
}
|
||||
)
|
||||
}
|
||||
|
||||
private spliceVideosById (id: number) {
|
||||
const index = this.videos.findIndex(v => v.id === id)
|
||||
this.videos.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Artboard-4" transform="translate(-224.000000, -159.000000)">
|
||||
<g id="25" transform="translate(224.000000, 159.000000)">
|
||||
<path d="M5,7 L5,20.0081158 C5,21.1082031 5.89706013,22 7.00585866,22 L16.9941413,22 C18.1019465,22 19,21.1066027 19,20.0081158 L19,7" id="Path-296" stroke="#ffffff" stroke-width="2"></path>
|
||||
<rect id="Rectangle-424" fill="#ffffff" x="2" y="4" width="20" height="2" rx="1"></rect>
|
||||
<path d="M9,10.9970301 C9,10.4463856 9.44386482,10 10,10 C10.5522847,10 11,10.4530363 11,10.9970301 L11,17.0029699 C11,17.5536144 10.5561352,18 10,18 C9.44771525,18 9,17.5469637 9,17.0029699 L9,10.9970301 Z M13,10.9970301 C13,10.4463856 13.4438648,10 14,10 C14.5522847,10 15,10.4530363 15,10.9970301 L15,17.0029699 C15,17.5536144 14.5561352,18 14,18 C13.4477153,18 13,17.5469637 13,17.0029699 L13,10.9970301 Z" id="Combined-Shape" fill="#ffffff"></path>
|
||||
<path d="M9,5 L9,2.99895656 C9,2.44724809 9.45097518,2 9.99077797,2 L14.009222,2 C14.5564136,2 15,2.44266033 15,2.99895656 L15,5" id="Path-33" stroke="#ffffff" stroke-width="2" stroke-linejoin="round"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -33,15 +33,15 @@
|
|||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: #F97D46;
|
||||
background-color: $orange-hoover-color;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin peertube-button-link {
|
||||
display: inline-block;
|
||||
|
||||
@include peertube-button;
|
||||
@include disable-default-a-behaviour;
|
||||
@include peertube-button;
|
||||
}
|
||||
|
||||
@mixin avatar ($size) {
|
||||
|
|
|
@ -4,6 +4,7 @@ $font-bold: 700;
|
|||
|
||||
$grey-color: #555;
|
||||
$orange-color: #F1680D;
|
||||
$orange-hoover-color: #F97D46;
|
||||
|
||||
$black-background: #000;
|
||||
$grey-background: #f6f2f2;
|
||||
|
|
Loading…
Reference in New Issue