Increase rows per page, add reporter muting for abuse list
This commit is contained in:
parent
68d19a0ace
commit
9b4241e33b
9 changed files with 78 additions and 14 deletions
|
@ -8,7 +8,7 @@
|
||||||
<ng-template pTemplate="header">
|
<ng-template pTemplate="header">
|
||||||
<tr>
|
<tr>
|
||||||
<th i18n>Account</th>
|
<th i18n>Account</th>
|
||||||
<th style="width: 200px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
|
<th style="width: 190px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
|
||||||
<th style="width: 100px;"></th> <!-- column for action buttons -->
|
<th style="width: 100px;"></th> <!-- column for action buttons -->
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<ng-template pTemplate="header">
|
<ng-template pTemplate="header">
|
||||||
<tr>
|
<tr>
|
||||||
<th i18n>Instance</th>
|
<th i18n>Instance</th>
|
||||||
<th style="width: 200px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
|
<th style="width: 190px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
|
||||||
<th style="width: 100px;"></th> <!-- column for action buttons -->
|
<th style="width: 100px;"></th> <!-- column for action buttons -->
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
|
@ -29,6 +29,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.glyphicon-trash {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
.screenratio {
|
.screenratio {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
<p-table
|
<p-table
|
||||||
[value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
|
[value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions"
|
||||||
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id"
|
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" [resizableColumns]="true"
|
||||||
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
|
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
|
||||||
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} reports"
|
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} reports"
|
||||||
>
|
>
|
||||||
<ng-template pTemplate="header">
|
<ng-template pTemplate="header">
|
||||||
<tr> <!-- header -->
|
<tr> <!-- header -->
|
||||||
<th style="width: 40px;"></th>
|
<th style="width: 40px;"></th>
|
||||||
<th i18n>Reporter</th>
|
<th style="width: 20%;" pResizableColumn i18n>Reporter</th>
|
||||||
<th style="width: 200px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
|
|
||||||
<th i18n>Video</th>
|
<th i18n>Video</th>
|
||||||
|
<th style="width:190px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
|
||||||
<th i18n pSortableColumn="state" style="width: 80px;">State <p-sortIcon field="state"></p-sortIcon></th>
|
<th i18n pSortableColumn="state" style="width: 80px;">State <p-sortIcon field="state"></p-sortIcon></th>
|
||||||
<th style="width: 120px;"></th>
|
<th style="width: 120px;"></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -40,14 +40,15 @@
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>{{ videoAbuse.createdAt }}</td>
|
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
<span *ngIf="videoAbuse.video.deleted" i18n-title title="Video was deleted" class="glyphicon glyphicon-trash"></span>
|
||||||
<a [href]="getVideoUrl(videoAbuse)" i18n-title title="Open video in a new tab" target="_blank" rel="noopener noreferrer">
|
<a [href]="getVideoUrl(videoAbuse)" i18n-title title="Open video in a new tab" target="_blank" rel="noopener noreferrer">
|
||||||
{{ videoAbuse.video.name }}
|
{{ videoAbuse.video.name }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<td>{{ videoAbuse.createdAt }}</td>
|
||||||
|
|
||||||
<td class="c-hand video-abuse-states" [pRowToggler]="videoAbuse">
|
<td class="c-hand video-abuse-states" [pRowToggler]="videoAbuse">
|
||||||
<span *ngIf="isVideoAbuseAccepted(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-ok"></span>
|
<span *ngIf="isVideoAbuseAccepted(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-ok"></span>
|
||||||
<span *ngIf="isVideoAbuseRejected(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-remove"></span>
|
<span *ngIf="isVideoAbuseRejected(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-remove"></span>
|
||||||
|
@ -55,7 +56,7 @@
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="action-cell">
|
<td class="action-cell">
|
||||||
<my-action-dropdown placement="bottom-right auto" i18n-label label="Actions" [actions]="videoAbuseActions" [entry]="videoAbuse"></my-action-dropdown>
|
<my-action-dropdown placement="bottom-right auto" container="body" i18n-label label="Actions" [actions]="videoAbuseActions" [entry]="videoAbuse"></my-action-dropdown>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { buildVideoLink, buildVideoEmbed } from 'src/assets/player/utils'
|
||||||
import { getAbsoluteAPIUrl } from '@app/shared/misc/utils'
|
import { getAbsoluteAPIUrl } from '@app/shared/misc/utils'
|
||||||
import { DomSanitizer } from '@angular/platform-browser'
|
import { DomSanitizer } from '@angular/platform-browser'
|
||||||
import { BlocklistService } from '@app/shared/blocklist'
|
import { BlocklistService } from '@app/shared/blocklist'
|
||||||
|
import { VideoService } from '@app/shared/video/video.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-video-abuse-list',
|
selector: 'my-video-abuse-list',
|
||||||
|
@ -26,7 +27,8 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
|
||||||
|
|
||||||
videoAbuses: (VideoAbuse & { moderationCommentHtml?: string, reasonHtml?: string })[] = []
|
videoAbuses: (VideoAbuse & { moderationCommentHtml?: string, reasonHtml?: string })[] = []
|
||||||
totalRecords = 0
|
totalRecords = 0
|
||||||
rowsPerPage = 10
|
rowsPerPageOptions = [ 20, 50, 100 ]
|
||||||
|
rowsPerPage = this.rowsPerPageOptions[0]
|
||||||
sort: SortMeta = { field: 'createdAt', order: 1 }
|
sort: SortMeta = { field: 'createdAt', order: 1 }
|
||||||
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||||
|
|
||||||
|
@ -36,6 +38,7 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
|
||||||
private notifier: Notifier,
|
private notifier: Notifier,
|
||||||
private videoAbuseService: VideoAbuseService,
|
private videoAbuseService: VideoAbuseService,
|
||||||
private blocklistService: BlocklistService,
|
private blocklistService: BlocklistService,
|
||||||
|
private videoService: VideoService,
|
||||||
private videoBlacklistService: VideoBlacklistService,
|
private videoBlacklistService: VideoBlacklistService,
|
||||||
private confirmService: ConfirmService,
|
private confirmService: ConfirmService,
|
||||||
private i18n: I18n,
|
private i18n: I18n,
|
||||||
|
@ -78,10 +81,12 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
label: this.i18n('Actions for the video'),
|
label: this.i18n('Actions for the video'),
|
||||||
isHeader: true
|
isHeader: true,
|
||||||
|
isDisplayed: videoAbuse => !videoAbuse.video.deleted
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.i18n('Blacklist video'),
|
label: this.i18n('Blacklist video'),
|
||||||
|
isDisplayed: videoAbuse => !videoAbuse.video.deleted,
|
||||||
handler: videoAbuse => {
|
handler: videoAbuse => {
|
||||||
this.videoBlacklistService.blacklistVideo(videoAbuse.video.id, undefined, true)
|
this.videoBlacklistService.blacklistVideo(videoAbuse.video.id, undefined, true)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
|
@ -91,6 +96,48 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
|
||||||
this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED)
|
this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
err => this.notifier.error(err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.i18n('Delete video'),
|
||||||
|
isDisplayed: videoAbuse => !videoAbuse.video.deleted,
|
||||||
|
handler: async videoAbuse => {
|
||||||
|
const res = await this.confirmService.confirm(this.i18n('Do you really want to delete this video?'), this.i18n('Delete'))
|
||||||
|
if (res === false) return
|
||||||
|
|
||||||
|
this.videoService.removeVideo(videoAbuse.video.id)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
this.notifier.success(this.i18n('Video deleted.'))
|
||||||
|
|
||||||
|
this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED)
|
||||||
|
},
|
||||||
|
|
||||||
|
err => this.notifier.error(err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
label: this.i18n('Actions for the reporter'),
|
||||||
|
isHeader: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.i18n('Mute reporter'),
|
||||||
|
handler: async videoAbuse => {
|
||||||
|
const account = videoAbuse.reporterAccount as Account
|
||||||
|
|
||||||
|
this.blocklistService.blockAccountByInstance(account)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
this.notifier.success(this.i18n('Account {{nameWithHost}} muted by the instance.', { nameWithHost: account.nameWithHost }))
|
||||||
|
|
||||||
|
account.mutedByInstance = true
|
||||||
|
},
|
||||||
|
|
||||||
err => this.notifier.error(err.message)
|
err => this.notifier.error(err.message)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -180,7 +227,8 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
|
||||||
Object.assign(abuse, {
|
Object.assign(abuse, {
|
||||||
reasonHtml: await this.toHtml(abuse.reason),
|
reasonHtml: await this.toHtml(abuse.reason),
|
||||||
moderationCommentHtml: await this.toHtml(abuse.moderationComment),
|
moderationCommentHtml: await this.toHtml(abuse.moderationComment),
|
||||||
embedHtml: this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(abuse))
|
embedHtml: this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(abuse)),
|
||||||
|
reporterAccount: new Account(abuse.reporterAccount)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th>
|
<th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th>
|
||||||
<th style="width: 120px;" i18n>Sensitive</th>
|
<th style="width: 120px;" i18n>Sensitive</th>
|
||||||
<th style="width: 120px;" i18n>Unfederated</th>
|
<th style="width: 120px;" i18n>Unfederated</th>
|
||||||
<th style="width: 200px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th>
|
<th style="width: 190px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th>
|
||||||
<th style="width: 120px;"></th>
|
<th style="width: 120px;"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="dropdown-root" ngbDropdown [placement]="placement" container="body" *ngIf="areActionsDisplayed(actions, entry)">
|
<div class="dropdown-root" ngbDropdown [placement]="placement" [container]="container" *ngIf="areActionsDisplayed(actions, entry)">
|
||||||
<div
|
<div
|
||||||
class="action-button" [ngClass]="{ small: buttonSize === 'small', grey: theme === 'grey', orange: theme === 'orange', 'button-styled': buttonStyled }"
|
class="action-button" [ngClass]="{ small: buttonSize === 'small', grey: theme === 'grey', orange: theme === 'orange', 'button-styled': buttonStyled }"
|
||||||
ngbDropdownToggle role="button"
|
ngbDropdownToggle role="button"
|
||||||
|
|
|
@ -27,6 +27,7 @@ export class ActionDropdownComponent<T> {
|
||||||
@Input() entry: T
|
@Input() entry: T
|
||||||
|
|
||||||
@Input() placement = 'bottom-left auto'
|
@Input() placement = 'bottom-left auto'
|
||||||
|
@Input() container: null | 'body'
|
||||||
|
|
||||||
@Input() buttonSize: DropdownButtonSize = 'normal'
|
@Input() buttonSize: DropdownButtonSize = 'normal'
|
||||||
@Input() buttonDirection: DropdownDirection = 'horizontal'
|
@Input() buttonDirection: DropdownDirection = 'horizontal'
|
||||||
|
|
|
@ -191,12 +191,22 @@ p-table {
|
||||||
|
|
||||||
.ui-dropdown {
|
.ui-dropdown {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
||||||
|
&.ui-state-focus {
|
||||||
|
box-shadow: #{$focus-box-shadow-form} var(--mainColorLightest);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-dropdown-label {
|
||||||
|
color: var(--inputPlaceholderColor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-paginator-current {
|
.ui-paginator-current {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
color: var(--inputPlaceholderColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-paginator-first,
|
.ui-paginator-first,
|
||||||
|
|
Loading…
Reference in a new issue