diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2020-05-03 23:01:57 +0200 |
---|---|---|
committer | Rigel Kent <par@rigelk.eu> | 2020-05-04 15:01:44 +0200 |
commit | 25a42e293be90d35afad2096e9db2fa3d617d855 (patch) | |
tree | 5739da8e2aed75447cf0fd608089cc8849c0da33 /client/src/app/+admin/moderation | |
parent | 801d957155d574bda984206021cdd1fe58ef56b9 (diff) | |
download | PeerTube-25a42e293be90d35afad2096e9db2fa3d617d855.tar.gz PeerTube-25a42e293be90d35afad2096e9db2fa3d617d855.tar.zst PeerTube-25a42e293be90d35afad2096e9db2fa3d617d855.zip |
Fix rowsPerPage change, add filter clear button, update video-abuse-list search query param dynamically
Diffstat (limited to 'client/src/app/+admin/moderation')
7 files changed, 64 insertions, 34 deletions
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html index 99b4e267c..262705603 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html | |||
@@ -6,11 +6,13 @@ | |||
6 | > | 6 | > |
7 | <ng-template pTemplate="caption"> | 7 | <ng-template pTemplate="caption"> |
8 | <div class="caption"> | 8 | <div class="caption"> |
9 | <div class="ml-auto"> | 9 | <div class="ml-auto has-feedback has-clear"> |
10 | <input | 10 | <input |
11 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | 11 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." |
12 | (keyup)="onSearch($event)" | 12 | (keyup)="onSearch($event)" |
13 | > | 13 | > |
14 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
15 | <span class="sr-only" i18n>Clear filters</span> | ||
14 | </div> | 16 | </div> |
15 | </div> | 17 | </div> |
16 | </ng-template> | 18 | </ng-template> |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html index aecdca387..17364ae04 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html | |||
@@ -6,11 +6,13 @@ | |||
6 | > | 6 | > |
7 | <ng-template pTemplate="caption"> | 7 | <ng-template pTemplate="caption"> |
8 | <div class="caption"> | 8 | <div class="caption"> |
9 | <div class="ml-auto"> | 9 | <div class="ml-auto has-feedback has-clear"> |
10 | <input | 10 | <input |
11 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | 11 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." |
12 | (keyup)="onSearch($event)" | 12 | (keyup)="onSearch($event)" |
13 | > | 13 | > |
14 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
15 | <span class="sr-only" i18n>Clear filters</span> | ||
14 | </div> | 16 | </div> |
15 | <a class="ml-2 block-button" (click)="addServersToBlock()" (key.enter)="addServersToBlock()"> | 17 | <a class="ml-2 block-button" (click)="addServersToBlock()" (key.enter)="addServersToBlock()"> |
16 | <my-global-icon iconName="add"></my-global-icon> | 18 | <my-global-icon iconName="add"></my-global-icon> |
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.html b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.html index 704d43ac4..588d38395 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.html +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.html | |||
@@ -14,7 +14,7 @@ | |||
14 | alt="Avatar" | 14 | alt="Avatar" |
15 | > | 15 | > |
16 | <div> | 16 | <div> |
17 | <span class="text-muted">{{ createByString(videoAbuse.reporterAccount) }}</span> | 17 | <span class="text-muted">{{ videoAbuse.reporterAccount.nameWithHost }}</span> |
18 | </div> | 18 | </div> |
19 | </a> | 19 | </a> |
20 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'reportee:"' + videoAbuse.reporterAccount.displayName + '"' }" class="ml-auto text-muted video-details-links" i18n> | 20 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'reportee:"' + videoAbuse.reporterAccount.displayName + '"' }" class="ml-auto text-muted video-details-links" i18n> |
@@ -34,7 +34,7 @@ | |||
34 | alt="Avatar" | 34 | alt="Avatar" |
35 | > | 35 | > |
36 | <div> | 36 | <div> |
37 | <span class="text-muted">{{ videoAbuse.video.channel.ownerAccount ? createByString(videoAbuse.video.channel.ownerAccount) : '' }}</span> | 37 | <span class="text-muted">{{ videoAbuse.video.channel.ownerAccount ? videoAbuse.video.channel.ownerAccount.nameWithHost : '' }}</span> |
38 | </div> | 38 | </div> |
39 | </a> | 39 | </a> |
40 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'reportee:"' +videoAbuse.video.channel.ownerAccount.displayName + '"' }" class="ml-auto text-muted video-details-links" i18n> | 40 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'reportee:"' +videoAbuse.video.channel.ownerAccount.displayName + '"' }" class="ml-auto text-muted video-details-links" i18n> |
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.ts b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.ts index 5481915b9..d9cb19845 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.ts +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import { Component, ViewEncapsulation, Input } from '@angular/core' | 1 | import { Component, Input } from '@angular/core' |
2 | import { VideoAbuse } from '../../../../../../shared' | ||
3 | import { Account } from '@app/shared/account/account.model' | 2 | import { Account } from '@app/shared/account/account.model' |
3 | import { Actor } from '@app/shared/actor/actor.model' | ||
4 | import { ProcessedVideoAbuse } from './video-abuse-list.component' | ||
4 | 5 | ||
5 | @Component({ | 6 | @Component({ |
6 | selector: 'my-video-abuse-details', | 7 | selector: 'my-video-abuse-details', |
@@ -8,9 +9,9 @@ import { Account } from '@app/shared/account/account.model' | |||
8 | styleUrls: [ '../moderation.component.scss' ] | 9 | styleUrls: [ '../moderation.component.scss' ] |
9 | }) | 10 | }) |
10 | export class VideoAbuseDetailsComponent { | 11 | export class VideoAbuseDetailsComponent { |
11 | @Input() videoAbuse: VideoAbuse | 12 | @Input() videoAbuse: ProcessedVideoAbuse |
12 | 13 | ||
13 | createByString (account: Account) { | 14 | switchToDefaultAvatar ($event: Event) { |
14 | return Account.CREATE_BY_STRING(account.name, account.host) | 15 | ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() |
15 | } | 16 | } |
16 | } | 17 | } |
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html index 2e7b60e2f..ba05073cf 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html | |||
@@ -3,25 +3,19 @@ | |||
3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" [resizableColumns]="true" | 3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" [resizableColumns]="true" |
4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} reports" | 5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} reports" |
6 | (onPage)="onPage()" [expandedRowKeys]="expandedRows" | 6 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" |
7 | > | 7 | > |
8 | <ng-template pTemplate="caption"> | 8 | <ng-template pTemplate="caption"> |
9 | <div class="caption"> | 9 | <div class="caption"> |
10 | <div class="ml-auto"> | 10 | <div class="ml-auto"> |
11 | <div class="input-group"> | 11 | <div class="input-group has-feedback has-clear"> |
12 | <div class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body"> | 12 | <div class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body"> |
13 | <div class="input-group-text" ngbDropdownToggle> | 13 | <div class="input-group-text" ngbDropdownToggle> |
14 | <span class="caret" aria-haspopup="menu" role="button"></span> | 14 | <span class="caret" aria-haspopup="menu" role="button"></span> |
15 | </div> | 15 | </div> |
16 | 16 | ||
17 | <div role="menu" ngbDropdownMenu> | 17 | <div role="menu" ngbDropdownMenu> |
18 | <h6 class="dropdown-header" i18n>Filter reports</h6> | 18 | <h6 class="dropdown-header" i18n>Advanced report filters</h6> |
19 | |||
20 | <!-- TODO: | ||
21 | <div class="dropdown-item" i18n>Reports opened by admins</div> | ||
22 | <div class="dropdown-item" i18n>Reports on videos with multiple reports</div> | ||
23 | <div class="dropdown-item" i18n>Unassigned reports</div> | ||
24 | --> | ||
25 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:pending' }" class="dropdown-item" i18n>Unsolved reports</a> | 19 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:pending' }" class="dropdown-item" i18n>Unsolved reports</a> |
26 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:accepted' }" class="dropdown-item" i18n>Accepted reports</a> | 20 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:accepted' }" class="dropdown-item" i18n>Accepted reports</a> |
27 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:rejected' }" class="dropdown-item" i18n>Refused reports</a> | 21 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:rejected' }" class="dropdown-item" i18n>Refused reports</a> |
@@ -31,8 +25,10 @@ | |||
31 | </div> | 25 | </div> |
32 | <input | 26 | <input |
33 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | 27 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." |
34 | (keyup)="onSearch($event)" | 28 | (keyup)="onAbuseSearch($event)" |
35 | > | 29 | > |
30 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetTableFilter()"></a> | ||
31 | <span class="sr-only" i18n>Clear filters</span> | ||
36 | </div> | 32 | </div> |
37 | </div> | 33 | </div> |
38 | </div> | 34 | </div> |
@@ -68,7 +64,7 @@ | |||
68 | > | 64 | > |
69 | <div> | 65 | <div> |
70 | {{ videoAbuse.reporterAccount.displayName }} | 66 | {{ videoAbuse.reporterAccount.displayName }} |
71 | <span class="text-muted">{{ createByString(videoAbuse.reporterAccount) }}</span> | 67 | <span class="text-muted">{{ videoAbuse.reporterAccount.nameWithHost }}</span> |
72 | </div> | 68 | </div> |
73 | </div> | 69 | </div> |
74 | </a> | 70 | </a> |
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts index 83d194d52..f54e3dccd 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts | |||
@@ -16,9 +16,23 @@ import { getAbsoluteAPIUrl } from '@app/shared/misc/utils' | |||
16 | import { DomSanitizer } from '@angular/platform-browser' | 16 | import { DomSanitizer } from '@angular/platform-browser' |
17 | import { BlocklistService } from '@app/shared/blocklist' | 17 | import { BlocklistService } from '@app/shared/blocklist' |
18 | import { VideoService } from '@app/shared/video/video.service' | 18 | import { VideoService } from '@app/shared/video/video.service' |
19 | import { ActivatedRoute } from '@angular/router' | 19 | import { ActivatedRoute, Params, Router } from '@angular/router' |
20 | import { filter } from 'rxjs/operators' | 20 | import { filter } from 'rxjs/operators' |
21 | 21 | ||
22 | export type ProcessedVideoAbuse = VideoAbuse & { | ||
23 | moderationCommentHtml?: string, | ||
24 | reasonHtml?: string | ||
25 | embedHtml?: string | ||
26 | updatedAt?: Date | ||
27 | // override bare server-side definitions with rich client-side definitions | ||
28 | reporterAccount: Account | ||
29 | video: VideoAbuse['video'] & { | ||
30 | channel: VideoAbuse['video']['channel'] & { | ||
31 | ownerAccount: Account | ||
32 | } | ||
33 | } | ||
34 | } | ||
35 | |||
22 | @Component({ | 36 | @Component({ |
23 | selector: 'my-video-abuse-list', | 37 | selector: 'my-video-abuse-list', |
24 | templateUrl: './video-abuse-list.component.html', | 38 | templateUrl: './video-abuse-list.component.html', |
@@ -27,7 +41,7 @@ import { filter } from 'rxjs/operators' | |||
27 | export class VideoAbuseListComponent extends RestTable implements OnInit, AfterViewInit { | 41 | export class VideoAbuseListComponent extends RestTable implements OnInit, AfterViewInit { |
28 | @ViewChild('moderationCommentModal', { static: true }) moderationCommentModal: ModerationCommentModalComponent | 42 | @ViewChild('moderationCommentModal', { static: true }) moderationCommentModal: ModerationCommentModalComponent |
29 | 43 | ||
30 | videoAbuses: (VideoAbuse & { moderationCommentHtml?: string, reasonHtml?: string })[] = [] | 44 | videoAbuses: ProcessedVideoAbuse[] = [] |
31 | totalRecords = 0 | 45 | totalRecords = 0 |
32 | sort: SortMeta = { field: 'createdAt', order: 1 } | 46 | sort: SortMeta = { field: 'createdAt', order: 1 } |
33 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 47 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
@@ -44,7 +58,8 @@ export class VideoAbuseListComponent extends RestTable implements OnInit, AfterV | |||
44 | private i18n: I18n, | 58 | private i18n: I18n, |
45 | private markdownRenderer: MarkdownService, | 59 | private markdownRenderer: MarkdownService, |
46 | private sanitizer: DomSanitizer, | 60 | private sanitizer: DomSanitizer, |
47 | private route: ActivatedRoute | 61 | private route: ActivatedRoute, |
62 | private router: Router | ||
48 | ) { | 63 | ) { |
49 | super() | 64 | super() |
50 | 65 | ||
@@ -212,15 +227,24 @@ export class VideoAbuseListComponent extends RestTable implements OnInit, AfterV | |||
212 | this.loadData() | 227 | this.loadData() |
213 | } | 228 | } |
214 | 229 | ||
215 | createByString (account: Account) { | 230 | /* Table filter functions */ |
216 | return Account.CREATE_BY_STRING(account.name, account.host) | 231 | onAbuseSearch (event: Event) { |
232 | this.onSearch(event) | ||
233 | this.setQueryParams((event.target as HTMLInputElement).value) | ||
234 | } | ||
235 | |||
236 | setQueryParams (search: string) { | ||
237 | const queryParams: Params = {} | ||
238 | if (search) Object.assign(queryParams, { search }) | ||
239 | this.router.navigate([ '/admin/moderation/video-abuses/list' ], { queryParams }) | ||
217 | } | 240 | } |
218 | 241 | ||
219 | setTableFilter (filter: string) { | 242 | resetTableFilter () { |
220 | // FIXME: cannot use ViewChild, so create a component for the filter input | 243 | this.setTableFilter('') |
221 | const filterInput = document.getElementById('table-filter') as HTMLInputElement | 244 | this.setQueryParams('') |
222 | if (filterInput) filterInput.value = filter | 245 | this.resetSearch() |
223 | } | 246 | } |
247 | /* END Table filter functions */ | ||
224 | 248 | ||
225 | isVideoAbuseAccepted (videoAbuse: VideoAbuse) { | 249 | isVideoAbuseAccepted (videoAbuse: VideoAbuse) { |
226 | return videoAbuse.state.id === VideoAbuseState.ACCEPTED | 250 | return videoAbuse.state.id === VideoAbuseState.ACCEPTED |
@@ -279,17 +303,20 @@ export class VideoAbuseListComponent extends RestTable implements OnInit, AfterV | |||
279 | }).subscribe( | 303 | }).subscribe( |
280 | async resultList => { | 304 | async resultList => { |
281 | this.totalRecords = resultList.total | 305 | this.totalRecords = resultList.total |
306 | this.videoAbuses = [] | ||
282 | 307 | ||
283 | this.videoAbuses = resultList.data | 308 | for (const abuse of resultList.data) { |
284 | |||
285 | for (const abuse of this.videoAbuses) { | ||
286 | Object.assign(abuse, { | 309 | Object.assign(abuse, { |
287 | reasonHtml: await this.toHtml(abuse.reason), | 310 | reasonHtml: await this.toHtml(abuse.reason), |
288 | moderationCommentHtml: await this.toHtml(abuse.moderationComment), | 311 | moderationCommentHtml: await this.toHtml(abuse.moderationComment), |
289 | embedHtml: this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(abuse)), | 312 | embedHtml: this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(abuse)), |
290 | reporterAccount: new Account(abuse.reporterAccount) | 313 | reporterAccount: new Account(abuse.reporterAccount) |
291 | }) | 314 | }) |
315 | |||
316 | if (abuse.video.channel?.ownerAccount) abuse.video.channel.ownerAccount = new Account(abuse.video.channel.ownerAccount) | ||
292 | if (abuse.updatedAt === abuse.createdAt) delete abuse.updatedAt | 317 | if (abuse.updatedAt === abuse.createdAt) delete abuse.updatedAt |
318 | |||
319 | this.videoAbuses.push(abuse as ProcessedVideoAbuse) | ||
293 | } | 320 | } |
294 | 321 | ||
295 | }, | 322 | }, |
diff --git a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html b/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html index b3f7789df..eb194b023 100644 --- a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html +++ b/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html | |||
@@ -3,15 +3,17 @@ | |||
3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" | 3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" |
4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} blacklisted videos" | 5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} blacklisted videos" |
6 | (onPage)="onPage()" [expandedRowKeys]="expandedRows" | 6 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" |
7 | > | 7 | > |
8 | <ng-template pTemplate="caption"> | 8 | <ng-template pTemplate="caption"> |
9 | <div class="caption"> | 9 | <div class="caption"> |
10 | <div class="ml-auto"> | 10 | <div class="ml-auto has-feedback has-clear"> |
11 | <input | 11 | <input |
12 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | 12 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." |
13 | (keyup)="onSearch($event)" | 13 | (keyup)="onSearch($event)" |
14 | > | 14 | > |
15 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
16 | <span class="sr-only" i18n>Clear filters</span> | ||
15 | </div> | 17 | </div> |
16 | </div> | 18 | </div> |
17 | </ng-template> | 19 | </ng-template> |