diff options
author | Chocobozzz <me@florianbigard.com> | 2020-11-20 13:55:33 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2020-11-20 13:59:21 +0100 |
commit | 939917705fa3fa93ab7036b5e7e9aaf5f1d0023e (patch) | |
tree | 54e941e916a1da82f999fabb9b419287441d53fb | |
parent | 4749078b8af8fdaf40dd35c9e2da7e681b9ea664 (diff) | |
download | PeerTube-939917705fa3fa93ab7036b5e7e9aaf5f1d0023e.tar.gz PeerTube-939917705fa3fa93ab7036b5e7e9aaf5f1d0023e.tar.zst PeerTube-939917705fa3fa93ab7036b5e7e9aaf5f1d0023e.zip |
Add ability to bulk delete comments
5 files changed, 65 insertions, 8 deletions
diff --git a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html index 330ee2478..8b7c12ba3 100644 --- a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html +++ b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html | |||
@@ -13,9 +13,18 @@ | |||
13 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 13 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
14 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} comments" | 14 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} comments" |
15 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" | 15 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" |
16 | [(selection)]="selectedComments" | ||
16 | > | 17 | > |
17 | <ng-template pTemplate="caption"> | 18 | <ng-template pTemplate="caption"> |
18 | <div class="caption"> | 19 | <div class="caption"> |
20 | <div> | ||
21 | <my-action-dropdown | ||
22 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" | ||
23 | [actions]="bulkCommentActions" [entry]="selectedComments" | ||
24 | > | ||
25 | </my-action-dropdown> | ||
26 | </div> | ||
27 | |||
19 | <div class="ml-auto"> | 28 | <div class="ml-auto"> |
20 | <div class="input-group has-feedback has-clear"> | 29 | <div class="input-group has-feedback has-clear"> |
21 | <div class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body"> | 30 | <div class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body"> |
@@ -42,6 +51,9 @@ | |||
42 | 51 | ||
43 | <ng-template pTemplate="header"> | 52 | <ng-template pTemplate="header"> |
44 | <tr> | 53 | <tr> |
54 | <th style="width: 40px"> | ||
55 | <p-tableHeaderCheckbox></p-tableHeaderCheckbox> | ||
56 | </th> | ||
45 | <th style="width: 40px"></th> | 57 | <th style="width: 40px"></th> |
46 | <th style="width: 150px;"></th> | 58 | <th style="width: 150px;"></th> |
47 | <th style="width: 300px" i18n>Account</th> | 59 | <th style="width: 300px" i18n>Account</th> |
@@ -52,7 +64,12 @@ | |||
52 | </ng-template> | 64 | </ng-template> |
53 | 65 | ||
54 | <ng-template pTemplate="body" let-videoComment let-expanded="expanded"> | 66 | <ng-template pTemplate="body" let-videoComment let-expanded="expanded"> |
55 | <tr> | 67 | <tr [pSelectableRow]="videoComment"> |
68 | |||
69 | <td class="checkbox-cell"> | ||
70 | <p-tableCheckbox [value]="videoComment"></p-tableCheckbox> | ||
71 | </td> | ||
72 | |||
56 | <td class="expand-cell c-hand" [pRowToggler]="videoComment" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body"> | 73 | <td class="expand-cell c-hand" [pRowToggler]="videoComment" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body"> |
57 | <span class="expander"> | 74 | <span class="expander"> |
58 | <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i> | 75 | <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i> |
diff --git a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.scss b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.scss index 439835899..d208944fe 100644 --- a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.scss +++ b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.scss | |||
@@ -45,7 +45,9 @@ my-global-icon { | |||
45 | } | 45 | } |
46 | 46 | ||
47 | a { | 47 | a { |
48 | @include ellipsis | 48 | @include ellipsis; |
49 | |||
50 | color: pvar(--mainForegroundColor); | ||
49 | } | 51 | } |
50 | } | 52 | } |
51 | 53 | ||
diff --git a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts index 284ec541d..529e28f11 100644 --- a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts +++ b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts | |||
@@ -1,7 +1,6 @@ | |||
1 | import { SortMeta } from 'primeng/api' | 1 | import { SortMeta } from 'primeng/api' |
2 | import { filter } from 'rxjs/operators' | ||
3 | import { AfterViewInit, Component, OnInit } from '@angular/core' | 2 | import { AfterViewInit, Component, OnInit } from '@angular/core' |
4 | import { ActivatedRoute, Params, Router } from '@angular/router' | 3 | import { ActivatedRoute, Router } from '@angular/router' |
5 | import { AuthService, ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core' | 4 | import { AuthService, ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core' |
6 | import { DropdownAction } from '@app/shared/shared-main' | 5 | import { DropdownAction } from '@app/shared/shared-main' |
7 | import { BulkService } from '@app/shared/shared-moderation' | 6 | import { BulkService } from '@app/shared/shared-moderation' |
@@ -41,6 +40,9 @@ export class VideoCommentListComponent extends RestTable implements OnInit, Afte | |||
41 | } | 40 | } |
42 | ] | 41 | ] |
43 | 42 | ||
43 | selectedComments: VideoCommentAdmin[] = [] | ||
44 | bulkCommentActions: DropdownAction<VideoCommentAdmin[]>[] = [] | ||
45 | |||
44 | get authUser () { | 46 | get authUser () { |
45 | return this.auth.getUser() | 47 | return this.auth.getUser() |
46 | } | 48 | } |
@@ -78,6 +80,15 @@ export class VideoCommentListComponent extends RestTable implements OnInit, Afte | |||
78 | ngOnInit () { | 80 | ngOnInit () { |
79 | this.initialize() | 81 | this.initialize() |
80 | this.listenToSearchChange() | 82 | this.listenToSearchChange() |
83 | |||
84 | this.bulkCommentActions = [ | ||
85 | { | ||
86 | label: $localize`Delete`, | ||
87 | handler: comments => this.removeComments(comments), | ||
88 | isDisplayed: () => this.authUser.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT), | ||
89 | iconName: 'delete' | ||
90 | } | ||
91 | ] | ||
81 | } | 92 | } |
82 | 93 | ||
83 | ngAfterViewInit () { | 94 | ngAfterViewInit () { |
@@ -92,6 +103,10 @@ export class VideoCommentListComponent extends RestTable implements OnInit, Afte | |||
92 | return this.markdownRenderer.textMarkdownToHTML(text, true, true) | 103 | return this.markdownRenderer.textMarkdownToHTML(text, true, true) |
93 | } | 104 | } |
94 | 105 | ||
106 | isInSelectionMode () { | ||
107 | return this.selectedComments.length !== 0 | ||
108 | } | ||
109 | |||
95 | protected loadData () { | 110 | protected loadData () { |
96 | this.videoCommentService.getAdminVideoComments({ | 111 | this.videoCommentService.getAdminVideoComments({ |
97 | pagination: this.pagination, | 112 | pagination: this.pagination, |
@@ -114,6 +129,21 @@ export class VideoCommentListComponent extends RestTable implements OnInit, Afte | |||
114 | ) | 129 | ) |
115 | } | 130 | } |
116 | 131 | ||
132 | private async removeComments (comments: VideoCommentAdmin[]) { | ||
133 | const commentArgs = comments.map(c => ({ videoId: c.video.id, commentId: c.id })) | ||
134 | |||
135 | this.videoCommentService.deleteVideoComments(commentArgs).subscribe( | ||
136 | () => { | ||
137 | this.notifier.success($localize`${commentArgs.length} comments deleted.`) | ||
138 | this.loadData() | ||
139 | }, | ||
140 | |||
141 | err => this.notifier.error(err.message), | ||
142 | |||
143 | () => this.selectedComments = [] | ||
144 | ) | ||
145 | } | ||
146 | |||
117 | private deleteComment (comment: VideoCommentAdmin) { | 147 | private deleteComment (comment: VideoCommentAdmin) { |
118 | this.videoCommentService.deleteVideoComment(comment.video.id, comment.id) | 148 | this.videoCommentService.deleteVideoComment(comment.video.id, comment.id) |
119 | .subscribe( | 149 | .subscribe( |
diff --git a/client/src/app/shared/shared-video-comment/video-comment.service.ts b/client/src/app/shared/shared-video-comment/video-comment.service.ts index 1ab996a76..c107a33ab 100644 --- a/client/src/app/shared/shared-video-comment/video-comment.service.ts +++ b/client/src/app/shared/shared-video-comment/video-comment.service.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import { Observable } from 'rxjs' | 1 | import { SortMeta } from 'primeng/api' |
2 | import { catchError, map } from 'rxjs/operators' | 2 | import { from, Observable } from 'rxjs' |
3 | import { catchError, concatMap, map, toArray } from 'rxjs/operators' | ||
3 | import { HttpClient, HttpParams } from '@angular/common/http' | 4 | import { HttpClient, HttpParams } from '@angular/common/http' |
4 | import { Injectable } from '@angular/core' | 5 | import { Injectable } from '@angular/core' |
5 | import { ComponentPaginationLight, RestExtractor, RestPagination, RestService } from '@app/core' | 6 | import { ComponentPaginationLight, RestExtractor, RestPagination, RestService } from '@app/core' |
@@ -15,7 +16,6 @@ import { | |||
15 | import { environment } from '../../../environments/environment' | 16 | import { environment } from '../../../environments/environment' |
16 | import { VideoCommentThreadTree } from './video-comment-thread-tree.model' | 17 | import { VideoCommentThreadTree } from './video-comment-thread-tree.model' |
17 | import { VideoComment } from './video-comment.model' | 18 | import { VideoComment } from './video-comment.model' |
18 | import { SortMeta } from 'primeng/api' | ||
19 | 19 | ||
20 | @Injectable() | 20 | @Injectable() |
21 | export class VideoCommentService { | 21 | export class VideoCommentService { |
@@ -118,6 +118,14 @@ export class VideoCommentService { | |||
118 | ) | 118 | ) |
119 | } | 119 | } |
120 | 120 | ||
121 | deleteVideoComments (comments: { videoId: number | string, commentId: number }[]) { | ||
122 | return from(comments) | ||
123 | .pipe( | ||
124 | concatMap(c => this.deleteVideoComment(c.videoId, c.commentId)), | ||
125 | toArray() | ||
126 | ) | ||
127 | } | ||
128 | |||
121 | getVideoCommentsFeeds (videoUUID?: string) { | 129 | getVideoCommentsFeeds (videoUUID?: string) { |
122 | const feeds = [ | 130 | const feeds = [ |
123 | { | 131 | { |
diff --git a/client/src/sass/primeng-custom.scss b/client/src/sass/primeng-custom.scss index a48f797fc..ed32a7b38 100644 --- a/client/src/sass/primeng-custom.scss +++ b/client/src/sass/primeng-custom.scss | |||
@@ -924,7 +924,7 @@ p-toast { | |||
924 | .notification-block { | 924 | .notification-block { |
925 | display: flex; | 925 | display: flex; |
926 | align-items: center; | 926 | align-items: center; |
927 | padding: 10px; | 927 | padding: 10px 20px; |
928 | 928 | ||
929 | .message { | 929 | .message { |
930 | flex-grow: 1; | 930 | flex-grow: 1; |