diff options
Diffstat (limited to 'client')
17 files changed, 107 insertions, 78 deletions
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.html b/client/src/app/+admin/follows/followers-list/followers-list.component.html index 8fe0d2348..14c62f1af 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.html +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.html | |||
@@ -9,14 +9,14 @@ | |||
9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | 9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" |
10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} followers" | 11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} followers" |
12 | [(selection)]="selectedFollows" | 12 | [(selection)]="selectedRows" |
13 | > | 13 | > |
14 | <ng-template pTemplate="caption"> | 14 | <ng-template pTemplate="caption"> |
15 | <div class="caption"> | 15 | <div class="caption"> |
16 | <div class="left-buttons"> | 16 | <div class="left-buttons"> |
17 | <my-action-dropdown | 17 | <my-action-dropdown |
18 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" | 18 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" |
19 | [actions]="bulkFollowsActions" [entry]="selectedFollows" | 19 | [actions]="bulkActions" [entry]="selectedRows" |
20 | > | 20 | > |
21 | </my-action-dropdown> | 21 | </my-action-dropdown> |
22 | </div> | 22 | </div> |
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.ts b/client/src/app/+admin/follows/followers-list/followers-list.component.ts index b2d333e83..6dd64fc57 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.ts +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.ts | |||
@@ -12,7 +12,7 @@ import { ActorFollow } from '@shared/models' | |||
12 | templateUrl: './followers-list.component.html', | 12 | templateUrl: './followers-list.component.html', |
13 | styleUrls: [ './followers-list.component.scss' ] | 13 | styleUrls: [ './followers-list.component.scss' ] |
14 | }) | 14 | }) |
15 | export class FollowersListComponent extends RestTable implements OnInit { | 15 | export class FollowersListComponent extends RestTable <ActorFollow> implements OnInit { |
16 | followers: ActorFollow[] = [] | 16 | followers: ActorFollow[] = [] |
17 | totalRecords = 0 | 17 | totalRecords = 0 |
18 | sort: SortMeta = { field: 'createdAt', order: -1 } | 18 | sort: SortMeta = { field: 'createdAt', order: -1 } |
@@ -20,8 +20,7 @@ export class FollowersListComponent extends RestTable implements OnInit { | |||
20 | 20 | ||
21 | searchFilters: AdvancedInputFilter[] = [] | 21 | searchFilters: AdvancedInputFilter[] = [] |
22 | 22 | ||
23 | selectedFollows: ActorFollow[] = [] | 23 | bulkActions: DropdownAction<ActorFollow[]>[] = [] |
24 | bulkFollowsActions: DropdownAction<ActorFollow[]>[] = [] | ||
25 | 24 | ||
26 | constructor ( | 25 | constructor ( |
27 | private confirmService: ConfirmService, | 26 | private confirmService: ConfirmService, |
@@ -36,7 +35,7 @@ export class FollowersListComponent extends RestTable implements OnInit { | |||
36 | 35 | ||
37 | this.searchFilters = this.followService.buildFollowsListFilters() | 36 | this.searchFilters = this.followService.buildFollowsListFilters() |
38 | 37 | ||
39 | this.bulkFollowsActions = [ | 38 | this.bulkActions = [ |
40 | { | 39 | { |
41 | label: $localize`Reject`, | 40 | label: $localize`Reject`, |
42 | handler: follows => this.rejectFollower(follows), | 41 | handler: follows => this.rejectFollower(follows), |
@@ -105,12 +104,14 @@ export class FollowersListComponent extends RestTable implements OnInit { | |||
105 | } | 104 | } |
106 | 105 | ||
107 | async deleteFollowers (follows: ActorFollow[]) { | 106 | async deleteFollowers (follows: ActorFollow[]) { |
107 | const icuParams = { count: follows.length, followerName: this.buildFollowerName(follows[0]) } | ||
108 | |||
108 | let message = $localize`Deleted followers will be able to send again a follow request.` | 109 | let message = $localize`Deleted followers will be able to send again a follow request.` |
109 | message += '<br /><br />' | 110 | message += '<br /><br />' |
110 | 111 | ||
111 | // eslint-disable-next-line max-len | 112 | // eslint-disable-next-line max-len |
112 | message += prepareIcu($localize`Do you really want to delete {count, plural, =1 {{followerName} follow request?} other {{count} follow requests?}}`)( | 113 | message += prepareIcu($localize`Do you really want to delete {count, plural, =1 {{followerName} follow request?} other {{count} follow requests?}}`)( |
113 | { count: follows.length, followerName: this.buildFollowerName(follows[0]) }, | 114 | icuParams, |
114 | $localize`Do you really want to delete these follow requests?` | 115 | $localize`Do you really want to delete these follow requests?` |
115 | ) | 116 | ) |
116 | 117 | ||
@@ -122,7 +123,7 @@ export class FollowersListComponent extends RestTable implements OnInit { | |||
122 | next: () => { | 123 | next: () => { |
123 | // eslint-disable-next-line max-len | 124 | // eslint-disable-next-line max-len |
124 | const message = prepareIcu($localize`Removed {count, plural, =1 {{followerName} follow request} other {{count} follow requests}}`)( | 125 | const message = prepareIcu($localize`Removed {count, plural, =1 {{followerName} follow request} other {{count} follow requests}}`)( |
125 | { count: follows.length, followerName: this.buildFollowerName(follows[0]) }, | 126 | icuParams, |
126 | $localize`Follow requests removed` | 127 | $localize`Follow requests removed` |
127 | ) | 128 | ) |
128 | 129 | ||
@@ -139,10 +140,6 @@ export class FollowersListComponent extends RestTable implements OnInit { | |||
139 | return follow.follower.name + '@' + follow.follower.host | 140 | return follow.follower.name + '@' + follow.follower.host |
140 | } | 141 | } |
141 | 142 | ||
142 | isInSelectionMode () { | ||
143 | return this.selectedFollows.length !== 0 | ||
144 | } | ||
145 | |||
146 | protected reloadData () { | 143 | protected reloadData () { |
147 | this.followService.getFollowers({ pagination: this.pagination, sort: this.sort, search: this.search }) | 144 | this.followService.getFollowers({ pagination: this.pagination, sort: this.sort, search: this.search }) |
148 | .subscribe({ | 145 | .subscribe({ |
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.html b/client/src/app/+admin/follows/following-list/following-list.component.html index f7abb7ede..eca79be71 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.html +++ b/client/src/app/+admin/follows/following-list/following-list.component.html | |||
@@ -9,14 +9,14 @@ | |||
9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | 9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" |
10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} hosts" | 11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} hosts" |
12 | [(selection)]="selectedFollows" | 12 | [(selection)]="selectedRows" |
13 | > | 13 | > |
14 | <ng-template pTemplate="caption"> | 14 | <ng-template pTemplate="caption"> |
15 | <div class="caption"> | 15 | <div class="caption"> |
16 | <div class="left-buttons"> | 16 | <div class="left-buttons"> |
17 | <my-action-dropdown | 17 | <my-action-dropdown |
18 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" | 18 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" |
19 | [actions]="bulkFollowsActions" [entry]="selectedFollows" | 19 | [actions]="bulkActions" [entry]="selectedRows" |
20 | > | 20 | > |
21 | </my-action-dropdown> | 21 | </my-action-dropdown> |
22 | 22 | ||
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.ts b/client/src/app/+admin/follows/following-list/following-list.component.ts index e3a56651a..e986a610a 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.ts +++ b/client/src/app/+admin/follows/following-list/following-list.component.ts | |||
@@ -12,7 +12,7 @@ import { prepareIcu } from '@app/helpers' | |||
12 | templateUrl: './following-list.component.html', | 12 | templateUrl: './following-list.component.html', |
13 | styleUrls: [ './following-list.component.scss' ] | 13 | styleUrls: [ './following-list.component.scss' ] |
14 | }) | 14 | }) |
15 | export class FollowingListComponent extends RestTable implements OnInit { | 15 | export class FollowingListComponent extends RestTable <ActorFollow> implements OnInit { |
16 | @ViewChild('followModal') followModal: FollowModalComponent | 16 | @ViewChild('followModal') followModal: FollowModalComponent |
17 | 17 | ||
18 | following: ActorFollow[] = [] | 18 | following: ActorFollow[] = [] |
@@ -22,8 +22,7 @@ export class FollowingListComponent extends RestTable implements OnInit { | |||
22 | 22 | ||
23 | searchFilters: AdvancedInputFilter[] = [] | 23 | searchFilters: AdvancedInputFilter[] = [] |
24 | 24 | ||
25 | selectedFollows: ActorFollow[] = [] | 25 | bulkActions: DropdownAction<ActorFollow[]>[] = [] |
26 | bulkFollowsActions: DropdownAction<ActorFollow[]>[] = [] | ||
27 | 26 | ||
28 | constructor ( | 27 | constructor ( |
29 | private notifier: Notifier, | 28 | private notifier: Notifier, |
@@ -38,7 +37,7 @@ export class FollowingListComponent extends RestTable implements OnInit { | |||
38 | 37 | ||
39 | this.searchFilters = this.followService.buildFollowsListFilters() | 38 | this.searchFilters = this.followService.buildFollowsListFilters() |
40 | 39 | ||
41 | this.bulkFollowsActions = [ | 40 | this.bulkActions = [ |
42 | { | 41 | { |
43 | label: $localize`Delete`, | 42 | label: $localize`Delete`, |
44 | handler: follows => this.removeFollowing(follows) | 43 | handler: follows => this.removeFollowing(follows) |
@@ -58,10 +57,6 @@ export class FollowingListComponent extends RestTable implements OnInit { | |||
58 | return follow.following.name === 'peertube' | 57 | return follow.following.name === 'peertube' |
59 | } | 58 | } |
60 | 59 | ||
61 | isInSelectionMode () { | ||
62 | return this.selectedFollows.length !== 0 | ||
63 | } | ||
64 | |||
65 | buildFollowingName (follow: ActorFollow) { | 60 | buildFollowingName (follow: ActorFollow) { |
66 | return follow.following.name + '@' + follow.following.host | 61 | return follow.following.name + '@' + follow.following.host |
67 | } | 62 | } |
diff --git a/client/src/app/+admin/moderation/registration-list/admin-registration.service.ts b/client/src/app/+admin/moderation/registration-list/admin-registration.service.ts index 012f942b3..10e2938c7 100644 --- a/client/src/app/+admin/moderation/registration-list/admin-registration.service.ts +++ b/client/src/app/+admin/moderation/registration-list/admin-registration.service.ts | |||
@@ -1,8 +1,10 @@ | |||
1 | import { SortMeta } from 'primeng/api' | 1 | import { SortMeta } from 'primeng/api' |
2 | import { catchError } from 'rxjs/operators' | 2 | import { from } from 'rxjs' |
3 | import { catchError, concatMap, 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 { RestExtractor, RestPagination, RestService } from '@app/core' | 6 | import { RestExtractor, RestPagination, RestService } from '@app/core' |
7 | import { arrayify } from '@shared/core-utils' | ||
6 | import { ResultList, UserRegistration } from '@shared/models' | 8 | import { ResultList, UserRegistration } from '@shared/models' |
7 | import { environment } from '../../../../environments/environment' | 9 | import { environment } from '../../../../environments/environment' |
8 | 10 | ||
@@ -54,10 +56,14 @@ export class AdminRegistrationService { | |||
54 | .pipe(catchError(res => this.restExtractor.handleError(res))) | 56 | .pipe(catchError(res => this.restExtractor.handleError(res))) |
55 | } | 57 | } |
56 | 58 | ||
57 | removeRegistration (registration: UserRegistration) { | 59 | removeRegistrations (registrationsArg: UserRegistration | UserRegistration[]) { |
58 | const url = AdminRegistrationService.BASE_REGISTRATION_URL + '/' + registration.id | 60 | const registrations = arrayify(registrationsArg) |
59 | 61 | ||
60 | return this.authHttp.delete(url) | 62 | return from(registrations) |
61 | .pipe(catchError(res => this.restExtractor.handleError(res))) | 63 | .pipe( |
64 | concatMap(r => this.authHttp.delete(AdminRegistrationService.BASE_REGISTRATION_URL + '/' + r.id)), | ||
65 | toArray(), | ||
66 | catchError(err => this.restExtractor.handleError(err)) | ||
67 | ) | ||
62 | } | 68 | } |
63 | } | 69 | } |
diff --git a/client/src/app/+admin/moderation/registration-list/registration-list.component.html b/client/src/app/+admin/moderation/registration-list/registration-list.component.html index 4f9d06acc..a2b888101 100644 --- a/client/src/app/+admin/moderation/registration-list/registration-list.component.html +++ b/client/src/app/+admin/moderation/registration-list/registration-list.component.html | |||
@@ -7,12 +7,20 @@ | |||
7 | [value]="registrations" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start" | 7 | [value]="registrations" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start" |
8 | [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" | 8 | [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" |
9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | 9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" |
10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 10 | [(selection)]="selectedRows" [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} registrations" | 11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} registrations" |
12 | [expandedRowKeys]="expandedRows" | 12 | [expandedRowKeys]="expandedRows" |
13 | > | 13 | > |
14 | <ng-template pTemplate="caption"> | 14 | <ng-template pTemplate="caption"> |
15 | <div class="caption"> | 15 | <div class="caption"> |
16 | <div class="left-buttons"> | ||
17 | <my-action-dropdown | ||
18 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" | ||
19 | [actions]="bulkActions" [entry]="selectedRows" | ||
20 | > | ||
21 | </my-action-dropdown> | ||
22 | </div> | ||
23 | |||
16 | <div class="ms-auto"> | 24 | <div class="ms-auto"> |
17 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> | 25 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> |
18 | </div> | 26 | </div> |
@@ -21,6 +29,9 @@ | |||
21 | 29 | ||
22 | <ng-template pTemplate="header"> | 30 | <ng-template pTemplate="header"> |
23 | <tr> <!-- header --> | 31 | <tr> <!-- header --> |
32 | <th style="width: 40px"> | ||
33 | <p-tableHeaderCheckbox ariaLabel="Select all rows" i18n-ariaLabel></p-tableHeaderCheckbox> | ||
34 | </th> | ||
24 | <th style="width: 40px;"></th> | 35 | <th style="width: 40px;"></th> |
25 | <th style="width: 150px;"></th> | 36 | <th style="width: 150px;"></th> |
26 | <th i18n>Account</th> | 37 | <th i18n>Account</th> |
@@ -34,7 +45,11 @@ | |||
34 | </ng-template> | 45 | </ng-template> |
35 | 46 | ||
36 | <ng-template pTemplate="body" let-expanded="expanded" let-registration> | 47 | <ng-template pTemplate="body" let-expanded="expanded" let-registration> |
37 | <tr> | 48 | <tr [pSelectableRow]="registration"> |
49 | <td class="checkbox-cell"> | ||
50 | <p-tableCheckbox [value]="registration" ariaLabel="Select this row" i18n-ariaLabel></p-tableCheckbox> | ||
51 | </td> | ||
52 | |||
38 | <td class="expand-cell" [pRowToggler]="registration"> | 53 | <td class="expand-cell" [pRowToggler]="registration"> |
39 | <my-table-expander-icon [expanded]="expanded"></my-table-expander-icon> | 54 | <my-table-expander-icon [expanded]="expanded"></my-table-expander-icon> |
40 | </td> | 55 | </td> |
diff --git a/client/src/app/+admin/moderation/registration-list/registration-list.component.ts b/client/src/app/+admin/moderation/registration-list/registration-list.component.ts index 37514edf5..569eccaa2 100644 --- a/client/src/app/+admin/moderation/registration-list/registration-list.component.ts +++ b/client/src/app/+admin/moderation/registration-list/registration-list.component.ts | |||
@@ -1,7 +1,8 @@ | |||
1 | import { SortMeta } from 'primeng/api' | 1 | import { SortMeta } from 'primeng/api' |
2 | import { Component, OnInit, ViewChild } from '@angular/core' | 2 | import { Component, OnInit, ViewChild } from '@angular/core' |
3 | import { ActivatedRoute, Router } from '@angular/router' | 3 | import { ActivatedRoute, Router } from '@angular/router' |
4 | import { MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' | 4 | import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' |
5 | import { prepareIcu } from '@app/helpers' | ||
5 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | 6 | import { AdvancedInputFilter } from '@app/shared/shared-forms' |
6 | import { DropdownAction } from '@app/shared/shared-main' | 7 | import { DropdownAction } from '@app/shared/shared-main' |
7 | import { UserRegistration, UserRegistrationState } from '@shared/models' | 8 | import { UserRegistration, UserRegistrationState } from '@shared/models' |
@@ -13,7 +14,7 @@ import { ProcessRegistrationModalComponent } from './process-registration-modal. | |||
13 | templateUrl: './registration-list.component.html', | 14 | templateUrl: './registration-list.component.html', |
14 | styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './registration-list.component.scss' ] | 15 | styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './registration-list.component.scss' ] |
15 | }) | 16 | }) |
16 | export class RegistrationListComponent extends RestTable implements OnInit { | 17 | export class RegistrationListComponent extends RestTable <UserRegistration> implements OnInit { |
17 | @ViewChild('processRegistrationModal', { static: true }) processRegistrationModal: ProcessRegistrationModalComponent | 18 | @ViewChild('processRegistrationModal', { static: true }) processRegistrationModal: ProcessRegistrationModalComponent |
18 | 19 | ||
19 | registrations: (UserRegistration & { registrationReasonHTML?: string, moderationResponseHTML?: string })[] = [] | 20 | registrations: (UserRegistration & { registrationReasonHTML?: string, moderationResponseHTML?: string })[] = [] |
@@ -22,6 +23,7 @@ export class RegistrationListComponent extends RestTable implements OnInit { | |||
22 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 23 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
23 | 24 | ||
24 | registrationActions: DropdownAction<UserRegistration>[][] = [] | 25 | registrationActions: DropdownAction<UserRegistration>[][] = [] |
26 | bulkActions: DropdownAction<UserRegistration[]>[] = [] | ||
25 | 27 | ||
26 | inputFilters: AdvancedInputFilter[] = [] | 28 | inputFilters: AdvancedInputFilter[] = [] |
27 | 29 | ||
@@ -33,6 +35,7 @@ export class RegistrationListComponent extends RestTable implements OnInit { | |||
33 | private server: ServerService, | 35 | private server: ServerService, |
34 | private notifier: Notifier, | 36 | private notifier: Notifier, |
35 | private markdownRenderer: MarkdownService, | 37 | private markdownRenderer: MarkdownService, |
38 | private confirmService: ConfirmService, | ||
36 | private adminRegistrationService: AdminRegistrationService | 39 | private adminRegistrationService: AdminRegistrationService |
37 | ) { | 40 | ) { |
38 | super() | 41 | super() |
@@ -40,22 +43,28 @@ export class RegistrationListComponent extends RestTable implements OnInit { | |||
40 | this.registrationActions = [ | 43 | this.registrationActions = [ |
41 | [ | 44 | [ |
42 | { | 45 | { |
43 | label: $localize`Accept this registration`, | 46 | label: $localize`Accept this request`, |
44 | handler: registration => this.openRegistrationRequestProcessModal(registration, 'accept'), | 47 | handler: registration => this.openRegistrationRequestProcessModal(registration, 'accept'), |
45 | isDisplayed: registration => registration.state.id === UserRegistrationState.PENDING | 48 | isDisplayed: registration => registration.state.id === UserRegistrationState.PENDING |
46 | }, | 49 | }, |
47 | { | 50 | { |
48 | label: $localize`Reject this registration`, | 51 | label: $localize`Reject this request`, |
49 | handler: registration => this.openRegistrationRequestProcessModal(registration, 'reject'), | 52 | handler: registration => this.openRegistrationRequestProcessModal(registration, 'reject'), |
50 | isDisplayed: registration => registration.state.id === UserRegistrationState.PENDING | 53 | isDisplayed: registration => registration.state.id === UserRegistrationState.PENDING |
51 | }, | 54 | }, |
52 | { | 55 | { |
53 | label: $localize`Remove this registration request`, | 56 | label: $localize`Remove this request`, |
54 | handler: registration => this.removeRegistration(registration), | 57 | handler: registration => this.removeRegistrations([ registration ]) |
55 | isDisplayed: registration => registration.state.id !== UserRegistrationState.PENDING | ||
56 | } | 58 | } |
57 | ] | 59 | ] |
58 | ] | 60 | ] |
61 | |||
62 | this.bulkActions = [ | ||
63 | { | ||
64 | label: $localize`Delete`, | ||
65 | handler: registrations => this.removeRegistrations(registrations) | ||
66 | } | ||
67 | ] | ||
59 | } | 68 | } |
60 | 69 | ||
61 | ngOnInit () { | 70 | ngOnInit () { |
@@ -107,11 +116,28 @@ export class RegistrationListComponent extends RestTable implements OnInit { | |||
107 | this.processRegistrationModal.openModal(registration, mode) | 116 | this.processRegistrationModal.openModal(registration, mode) |
108 | } | 117 | } |
109 | 118 | ||
110 | private removeRegistration (registration: UserRegistration) { | 119 | private async removeRegistrations (registrations: UserRegistration[]) { |
111 | this.adminRegistrationService.removeRegistration(registration) | 120 | const icuParams = { count: registrations.length, username: registrations[0].username } |
121 | |||
122 | // eslint-disable-next-line max-len | ||
123 | const message = prepareIcu($localize`Do you really want to delete {count, plural, =1 {{username} registration request?} other {{count} registration requests?}}`)( | ||
124 | icuParams, | ||
125 | $localize`Do you really want to delete these registration requests?` | ||
126 | ) | ||
127 | |||
128 | const res = await this.confirmService.confirm(message, $localize`Delete`) | ||
129 | if (res === false) return | ||
130 | |||
131 | this.adminRegistrationService.removeRegistrations(registrations) | ||
112 | .subscribe({ | 132 | .subscribe({ |
113 | next: () => { | 133 | next: () => { |
114 | this.notifier.success($localize`Registration request deleted.`) | 134 | // eslint-disable-next-line max-len |
135 | const message = prepareIcu($localize`Removed {count, plural, =1 {{username} registration request} other {{count} registration requests}}`)( | ||
136 | icuParams, | ||
137 | $localize`Registration requests removed` | ||
138 | ) | ||
139 | |||
140 | this.notifier.success(message) | ||
115 | this.reloadData() | 141 | this.reloadData() |
116 | }, | 142 | }, |
117 | 143 | ||
diff --git a/client/src/app/+admin/overview/comments/video-comment-list.component.html b/client/src/app/+admin/overview/comments/video-comment-list.component.html index d2ca5f700..b0d8131bf 100644 --- a/client/src/app/+admin/overview/comments/video-comment-list.component.html +++ b/client/src/app/+admin/overview/comments/video-comment-list.component.html | |||
@@ -13,14 +13,14 @@ | |||
13 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [selectionPageOnly]="true" | 13 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [selectionPageOnly]="true" |
14 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 14 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
15 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} comments" | 15 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} comments" |
16 | [expandedRowKeys]="expandedRows" [(selection)]="selectedComments" | 16 | [expandedRowKeys]="expandedRows" [(selection)]="selectedRows" |
17 | > | 17 | > |
18 | <ng-template pTemplate="caption"> | 18 | <ng-template pTemplate="caption"> |
19 | <div class="caption"> | 19 | <div class="caption"> |
20 | <div> | 20 | <div> |
21 | <my-action-dropdown | 21 | <my-action-dropdown |
22 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" | 22 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" |
23 | [actions]="bulkCommentActions" [entry]="selectedComments" | 23 | [actions]="bulkActions" [entry]="selectedRows" |
24 | > | 24 | > |
25 | </my-action-dropdown> | 25 | </my-action-dropdown> |
26 | </div> | 26 | </div> |
diff --git a/client/src/app/+admin/overview/comments/video-comment-list.component.ts b/client/src/app/+admin/overview/comments/video-comment-list.component.ts index c95d2ffeb..cfa68ed9d 100644 --- a/client/src/app/+admin/overview/comments/video-comment-list.component.ts +++ b/client/src/app/+admin/overview/comments/video-comment-list.component.ts | |||
@@ -14,7 +14,7 @@ import { prepareIcu } from '@app/helpers' | |||
14 | templateUrl: './video-comment-list.component.html', | 14 | templateUrl: './video-comment-list.component.html', |
15 | styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './video-comment-list.component.scss' ] | 15 | styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './video-comment-list.component.scss' ] |
16 | }) | 16 | }) |
17 | export class VideoCommentListComponent extends RestTable implements OnInit { | 17 | export class VideoCommentListComponent extends RestTable <VideoCommentAdmin> implements OnInit { |
18 | comments: VideoCommentAdmin[] | 18 | comments: VideoCommentAdmin[] |
19 | totalRecords = 0 | 19 | totalRecords = 0 |
20 | sort: SortMeta = { field: 'createdAt', order: -1 } | 20 | sort: SortMeta = { field: 'createdAt', order: -1 } |
@@ -40,8 +40,7 @@ export class VideoCommentListComponent extends RestTable implements OnInit { | |||
40 | } | 40 | } |
41 | ] | 41 | ] |
42 | 42 | ||
43 | selectedComments: VideoCommentAdmin[] = [] | 43 | bulkActions: DropdownAction<VideoCommentAdmin[]>[] = [] |
44 | bulkCommentActions: DropdownAction<VideoCommentAdmin[]>[] = [] | ||
45 | 44 | ||
46 | inputFilters: AdvancedInputFilter[] = [ | 45 | inputFilters: AdvancedInputFilter[] = [ |
47 | { | 46 | { |
@@ -100,7 +99,7 @@ export class VideoCommentListComponent extends RestTable implements OnInit { | |||
100 | ngOnInit () { | 99 | ngOnInit () { |
101 | this.initialize() | 100 | this.initialize() |
102 | 101 | ||
103 | this.bulkCommentActions = [ | 102 | this.bulkActions = [ |
104 | { | 103 | { |
105 | label: $localize`Delete`, | 104 | label: $localize`Delete`, |
106 | handler: comments => this.removeComments(comments), | 105 | handler: comments => this.removeComments(comments), |
@@ -118,10 +117,6 @@ export class VideoCommentListComponent extends RestTable implements OnInit { | |||
118 | return this.markdownRenderer.textMarkdownToHTML({ markdown: text, withHtml: true, withEmoji: true }) | 117 | return this.markdownRenderer.textMarkdownToHTML({ markdown: text, withHtml: true, withEmoji: true }) |
119 | } | 118 | } |
120 | 119 | ||
121 | isInSelectionMode () { | ||
122 | return this.selectedComments.length !== 0 | ||
123 | } | ||
124 | |||
125 | reloadData () { | 120 | reloadData () { |
126 | this.videoCommentService.getAdminVideoComments({ | 121 | this.videoCommentService.getAdminVideoComments({ |
127 | pagination: this.pagination, | 122 | pagination: this.pagination, |
@@ -162,7 +157,7 @@ export class VideoCommentListComponent extends RestTable implements OnInit { | |||
162 | 157 | ||
163 | error: err => this.notifier.error(err.message), | 158 | error: err => this.notifier.error(err.message), |
164 | 159 | ||
165 | complete: () => this.selectedComments = [] | 160 | complete: () => this.selectedRows = [] |
166 | }) | 161 | }) |
167 | } | 162 | } |
168 | 163 | ||
diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.html b/client/src/app/+admin/overview/users/user-list/user-list.component.html index 5e5ac368c..7eb5e0fc7 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.html +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.html | |||
@@ -6,7 +6,7 @@ | |||
6 | <p-table | 6 | <p-table |
7 | [value]="users" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start" | 7 | [value]="users" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start" |
8 | [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" [resizableColumns]="true" | 8 | [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" [resizableColumns]="true" |
9 | [(selection)]="selectedUsers" [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [selectionPageOnly]="true" | 9 | [(selection)]="selectedRows" [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [selectionPageOnly]="true" |
10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} users" | 11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} users" |
12 | [expandedRowKeys]="expandedRows" | 12 | [expandedRowKeys]="expandedRows" |
@@ -16,7 +16,7 @@ | |||
16 | <div class="left-buttons"> | 16 | <div class="left-buttons"> |
17 | <my-action-dropdown | 17 | <my-action-dropdown |
18 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" | 18 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" |
19 | [actions]="bulkUserActions" [entry]="selectedUsers" | 19 | [actions]="bulkActions" [entry]="selectedRows" |
20 | > | 20 | > |
21 | </my-action-dropdown> | 21 | </my-action-dropdown> |
22 | 22 | ||
diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.ts b/client/src/app/+admin/overview/users/user-list/user-list.component.ts index 99987fdff..7d62302f8 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.ts | |||
@@ -22,7 +22,7 @@ type UserForList = User & { | |||
22 | templateUrl: './user-list.component.html', | 22 | templateUrl: './user-list.component.html', |
23 | styleUrls: [ './user-list.component.scss' ] | 23 | styleUrls: [ './user-list.component.scss' ] |
24 | }) | 24 | }) |
25 | export class UserListComponent extends RestTable implements OnInit { | 25 | export class UserListComponent extends RestTable <User> implements OnInit { |
26 | private static readonly LOCAL_STORAGE_SELECTED_COLUMNS_KEY = 'admin-user-list-selected-columns' | 26 | private static readonly LOCAL_STORAGE_SELECTED_COLUMNS_KEY = 'admin-user-list-selected-columns' |
27 | 27 | ||
28 | @ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent | 28 | @ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent |
@@ -35,8 +35,7 @@ export class UserListComponent extends RestTable implements OnInit { | |||
35 | 35 | ||
36 | highlightBannedUsers = false | 36 | highlightBannedUsers = false |
37 | 37 | ||
38 | selectedUsers: User[] = [] | 38 | bulkActions: DropdownAction<User[]>[][] = [] |
39 | bulkUserActions: DropdownAction<User[]>[][] = [] | ||
40 | columns: { id: string, label: string }[] | 39 | columns: { id: string, label: string }[] |
41 | 40 | ||
42 | inputFilters: AdvancedInputFilter[] = [ | 41 | inputFilters: AdvancedInputFilter[] = [ |
@@ -95,7 +94,7 @@ export class UserListComponent extends RestTable implements OnInit { | |||
95 | 94 | ||
96 | this.initialize() | 95 | this.initialize() |
97 | 96 | ||
98 | this.bulkUserActions = [ | 97 | this.bulkActions = [ |
99 | [ | 98 | [ |
100 | { | 99 | { |
101 | label: $localize`Delete`, | 100 | label: $localize`Delete`, |
@@ -249,7 +248,7 @@ export class UserListComponent extends RestTable implements OnInit { | |||
249 | const res = await this.confirmService.confirm(message, $localize`Delete`) | 248 | const res = await this.confirmService.confirm(message, $localize`Delete`) |
250 | if (res === false) return | 249 | if (res === false) return |
251 | 250 | ||
252 | this.userAdminService.removeUser(users) | 251 | this.userAdminService.removeUsers(users) |
253 | .subscribe({ | 252 | .subscribe({ |
254 | next: () => { | 253 | next: () => { |
255 | this.notifier.success( | 254 | this.notifier.success( |
@@ -284,12 +283,8 @@ export class UserListComponent extends RestTable implements OnInit { | |||
284 | }) | 283 | }) |
285 | } | 284 | } |
286 | 285 | ||
287 | isInSelectionMode () { | ||
288 | return this.selectedUsers.length !== 0 | ||
289 | } | ||
290 | |||
291 | protected reloadData () { | 286 | protected reloadData () { |
292 | this.selectedUsers = [] | 287 | this.selectedRows = [] |
293 | 288 | ||
294 | this.userAdminService.getUsers({ | 289 | this.userAdminService.getUsers({ |
295 | pagination: this.pagination, | 290 | pagination: this.pagination, |
diff --git a/client/src/app/+admin/overview/videos/video-list.component.html b/client/src/app/+admin/overview/videos/video-list.component.html index a6cd2e257..5b8405ad9 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.html +++ b/client/src/app/+admin/overview/videos/video-list.component.html | |||
@@ -6,7 +6,7 @@ | |||
6 | <p-table | 6 | <p-table |
7 | [value]="videos" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start" | 7 | [value]="videos" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start" |
8 | [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" [resizableColumns]="true" | 8 | [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" [resizableColumns]="true" |
9 | [(selection)]="selectedVideos" [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [selectionPageOnly]="true" | 9 | [(selection)]="selectedRows" [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [selectionPageOnly]="true" |
10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} videos" | 11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} videos" |
12 | [expandedRowKeys]="expandedRows" [ngClass]="{ loading: loading }" | 12 | [expandedRowKeys]="expandedRows" [ngClass]="{ loading: loading }" |
@@ -16,7 +16,7 @@ | |||
16 | <div class="left-buttons"> | 16 | <div class="left-buttons"> |
17 | <my-action-dropdown | 17 | <my-action-dropdown |
18 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" | 18 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" |
19 | [actions]="bulkVideoActions" [entry]="selectedVideos" | 19 | [actions]="bulkActions" [entry]="selectedRows" |
20 | > | 20 | > |
21 | </my-action-dropdown> | 21 | </my-action-dropdown> |
22 | </div> | 22 | </div> |
diff --git a/client/src/app/+admin/overview/videos/video-list.component.ts b/client/src/app/+admin/overview/videos/video-list.component.ts index 4d3e9873c..cd5d2eb34 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.ts +++ b/client/src/app/+admin/overview/videos/video-list.component.ts | |||
@@ -17,7 +17,7 @@ import { VideoAdminService } from './video-admin.service' | |||
17 | templateUrl: './video-list.component.html', | 17 | templateUrl: './video-list.component.html', |
18 | styleUrls: [ './video-list.component.scss' ] | 18 | styleUrls: [ './video-list.component.scss' ] |
19 | }) | 19 | }) |
20 | export class VideoListComponent extends RestTable implements OnInit { | 20 | export class VideoListComponent extends RestTable <Video> implements OnInit { |
21 | @ViewChild('videoBlockModal') videoBlockModal: VideoBlockComponent | 21 | @ViewChild('videoBlockModal') videoBlockModal: VideoBlockComponent |
22 | 22 | ||
23 | videos: Video[] = [] | 23 | videos: Video[] = [] |
@@ -26,9 +26,7 @@ export class VideoListComponent extends RestTable implements OnInit { | |||
26 | sort: SortMeta = { field: 'publishedAt', order: -1 } | 26 | sort: SortMeta = { field: 'publishedAt', order: -1 } |
27 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 27 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
28 | 28 | ||
29 | bulkVideoActions: DropdownAction<Video[]>[][] = [] | 29 | bulkActions: DropdownAction<Video[]>[][] = [] |
30 | |||
31 | selectedVideos: Video[] = [] | ||
32 | 30 | ||
33 | inputFilters: AdvancedInputFilter[] | 31 | inputFilters: AdvancedInputFilter[] |
34 | 32 | ||
@@ -72,7 +70,7 @@ export class VideoListComponent extends RestTable implements OnInit { | |||
72 | 70 | ||
73 | this.inputFilters = this.videoAdminService.buildAdminInputFilter() | 71 | this.inputFilters = this.videoAdminService.buildAdminInputFilter() |
74 | 72 | ||
75 | this.bulkVideoActions = [ | 73 | this.bulkActions = [ |
76 | [ | 74 | [ |
77 | { | 75 | { |
78 | label: $localize`Delete`, | 76 | label: $localize`Delete`, |
@@ -126,10 +124,6 @@ export class VideoListComponent extends RestTable implements OnInit { | |||
126 | return 'VideoListComponent' | 124 | return 'VideoListComponent' |
127 | } | 125 | } |
128 | 126 | ||
129 | isInSelectionMode () { | ||
130 | return this.selectedVideos.length !== 0 | ||
131 | } | ||
132 | |||
133 | getPrivacyBadgeClass (video: Video) { | 127 | getPrivacyBadgeClass (video: Video) { |
134 | if (video.privacy.id === VideoPrivacy.PUBLIC) return 'badge-green' | 128 | if (video.privacy.id === VideoPrivacy.PUBLIC) return 'badge-green' |
135 | 129 | ||
@@ -190,7 +184,7 @@ export class VideoListComponent extends RestTable implements OnInit { | |||
190 | } | 184 | } |
191 | 185 | ||
192 | reloadData () { | 186 | reloadData () { |
193 | this.selectedVideos = [] | 187 | this.selectedRows = [] |
194 | 188 | ||
195 | this.loading = true | 189 | this.loading = true |
196 | 190 | ||
diff --git a/client/src/app/core/renderer/linkifier.service.ts b/client/src/app/core/renderer/linkifier.service.ts index 78df92cc9..d99591d6c 100644 --- a/client/src/app/core/renderer/linkifier.service.ts +++ b/client/src/app/core/renderer/linkifier.service.ts | |||
@@ -15,7 +15,7 @@ export class LinkifierService { | |||
15 | }, | 15 | }, |
16 | formatHref: { | 16 | formatHref: { |
17 | mention: (href: string) => { | 17 | mention: (href: string) => { |
18 | return getAbsoluteAPIUrl() + '/services/redirect/accounts/' + href.substr(1) | 18 | return getAbsoluteAPIUrl() + '/services/redirect/accounts/' + href.substring(1) |
19 | } | 19 | } |
20 | } | 20 | } |
21 | } | 21 | } |
diff --git a/client/src/app/core/rest/rest-table.ts b/client/src/app/core/rest/rest-table.ts index ec5646b5d..cfaa16af9 100644 --- a/client/src/app/core/rest/rest-table.ts +++ b/client/src/app/core/rest/rest-table.ts | |||
@@ -7,7 +7,7 @@ import { RestPagination } from './rest-pagination' | |||
7 | 7 | ||
8 | const debugLogger = debug('peertube:tables:RestTable') | 8 | const debugLogger = debug('peertube:tables:RestTable') |
9 | 9 | ||
10 | export abstract class RestTable { | 10 | export abstract class RestTable <T = unknown> { |
11 | 11 | ||
12 | abstract totalRecords: number | 12 | abstract totalRecords: number |
13 | abstract sort: SortMeta | 13 | abstract sort: SortMeta |
@@ -17,6 +17,8 @@ export abstract class RestTable { | |||
17 | rowsPerPage = this.rowsPerPageOptions[0] | 17 | rowsPerPage = this.rowsPerPageOptions[0] |
18 | expandedRows = {} | 18 | expandedRows = {} |
19 | 19 | ||
20 | selectedRows: T[] = [] | ||
21 | |||
20 | search: string | 22 | search: string |
21 | 23 | ||
22 | protected route: ActivatedRoute | 24 | protected route: ActivatedRoute |
@@ -75,6 +77,10 @@ export abstract class RestTable { | |||
75 | this.reloadData() | 77 | this.reloadData() |
76 | } | 78 | } |
77 | 79 | ||
80 | isInSelectionMode () { | ||
81 | return this.selectedRows.length !== 0 | ||
82 | } | ||
83 | |||
78 | protected abstract reloadData (): void | 84 | protected abstract reloadData (): void |
79 | 85 | ||
80 | private getSortLocalStorageKey () { | 86 | private getSortLocalStorageKey () { |
diff --git a/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts b/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts index c69a45c25..50dccf862 100644 --- a/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts +++ b/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts | |||
@@ -105,7 +105,7 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges { | |||
105 | const res = await this.confirmService.confirm(message, $localize`Delete ${user.username}`) | 105 | const res = await this.confirmService.confirm(message, $localize`Delete ${user.username}`) |
106 | if (res === false) return | 106 | if (res === false) return |
107 | 107 | ||
108 | this.userAdminService.removeUser(user) | 108 | this.userAdminService.removeUsers(user) |
109 | .subscribe({ | 109 | .subscribe({ |
110 | next: () => { | 110 | next: () => { |
111 | this.notifier.success($localize`User ${user.username} deleted.`) | 111 | this.notifier.success($localize`User ${user.username} deleted.`) |
diff --git a/client/src/app/shared/shared-users/user-admin.service.ts b/client/src/app/shared/shared-users/user-admin.service.ts index 0b04023a3..6224f0bd5 100644 --- a/client/src/app/shared/shared-users/user-admin.service.ts +++ b/client/src/app/shared/shared-users/user-admin.service.ts | |||
@@ -64,7 +64,7 @@ export class UserAdminService { | |||
64 | ) | 64 | ) |
65 | } | 65 | } |
66 | 66 | ||
67 | removeUser (usersArg: UserServerModel | UserServerModel[]) { | 67 | removeUsers (usersArg: UserServerModel | UserServerModel[]) { |
68 | const users = arrayify(usersArg) | 68 | const users = arrayify(usersArg) |
69 | 69 | ||
70 | return from(users) | 70 | return from(users) |