Add bulk action on following/followers
This commit is contained in:
parent
073deef886
commit
e3d6c6434f
|
@ -9,9 +9,18 @@
|
||||||
[lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false"
|
[lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false"
|
||||||
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
|
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
|
||||||
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} followers"
|
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} followers"
|
||||||
|
[(selection)]="selectedFollows"
|
||||||
>
|
>
|
||||||
<ng-template pTemplate="caption">
|
<ng-template pTemplate="caption">
|
||||||
<div class="caption">
|
<div class="caption">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<my-action-dropdown
|
||||||
|
*ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange"
|
||||||
|
[actions]="bulkFollowsActions" [entry]="selectedFollows"
|
||||||
|
>
|
||||||
|
</my-action-dropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="ms-auto">
|
<div class="ms-auto">
|
||||||
<my-advanced-input-filter [filters]="searchFilters" (search)="onSearch($event)"></my-advanced-input-filter>
|
<my-advanced-input-filter [filters]="searchFilters" (search)="onSearch($event)"></my-advanced-input-filter>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,6 +29,9 @@
|
||||||
|
|
||||||
<ng-template pTemplate="header">
|
<ng-template pTemplate="header">
|
||||||
<tr>
|
<tr>
|
||||||
|
<th style="width: 40px">
|
||||||
|
<p-tableHeaderCheckbox ariaLabel="Select all rows" i18n-ariaLabel></p-tableHeaderCheckbox>
|
||||||
|
</th>
|
||||||
<th style="width: 150px;" i18n>Actions</th>
|
<th style="width: 150px;" i18n>Actions</th>
|
||||||
<th i18n>Follower</th>
|
<th i18n>Follower</th>
|
||||||
<th style="width: 100px;" i18n pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th>
|
<th style="width: 100px;" i18n pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th>
|
||||||
|
@ -30,15 +42,19 @@
|
||||||
|
|
||||||
<ng-template pTemplate="body" let-follow>
|
<ng-template pTemplate="body" let-follow>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="action-cell">
|
<td class="checkbox-cell">
|
||||||
<my-button *ngIf="follow.state !== 'accepted'" i18n-title title="Accept" icon="tick" (click)="acceptFollower(follow)"></my-button>
|
<p-tableCheckbox [value]="follow" ariaLabel="Select this row" i18n-ariaLabel></p-tableCheckbox>
|
||||||
<my-button *ngIf="follow.state !== 'rejected'" i18n-title title="Refuse" icon="cross" (click)="rejectFollower(follow)"></my-button>
|
</td>
|
||||||
|
|
||||||
<my-delete-button *ngIf="follow.state === 'rejected'" (click)="deleteFollower(follow)"></my-delete-button>
|
<td class="action-cell">
|
||||||
|
<my-button *ngIf="follow.state !== 'accepted'" i18n-title title="Accept" icon="tick" (click)="acceptFollower([ follow ])"></my-button>
|
||||||
|
<my-button *ngIf="follow.state !== 'rejected'" i18n-title title="Reject" icon="cross" (click)="rejectFollower([ follow ])"></my-button>
|
||||||
|
|
||||||
|
<my-delete-button *ngIf="follow.state === 'rejected'" (click)="deleteFollowers([ follow ])"></my-delete-button>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a [href]="follow.follower.url" i18n-title title="Open actor page in a new tab" target="_blank" rel="noopener noreferrer">
|
<a [href]="follow.follower.url" i18n-title title="Open actor page in a new tab" target="_blank" rel="noopener noreferrer">
|
||||||
{{ follow.follower.name + '@' + follow.follower.host }}
|
{{ buildFollowerName(follow) }}
|
||||||
<my-global-icon iconName="external-link"></my-global-icon>
|
<my-global-icon iconName="external-link"></my-global-icon>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
@ -56,7 +72,7 @@
|
||||||
|
|
||||||
<ng-template pTemplate="emptymessage">
|
<ng-template pTemplate="emptymessage">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="5">
|
<td colspan="6">
|
||||||
<div class="no-results">
|
<div class="no-results">
|
||||||
<ng-container *ngIf="search" i18n>No follower found matching current filters.</ng-container>
|
<ng-container *ngIf="search" i18n>No follower found matching current filters.</ng-container>
|
||||||
<ng-container *ngIf="!search" i18n>Your instance doesn't have any follower.</ng-container>
|
<ng-container *ngIf="!search" i18n>Your instance doesn't have any follower.</ng-container>
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { SortMeta } from 'primeng/api'
|
import { SortMeta } from 'primeng/api'
|
||||||
import { Component, OnInit } from '@angular/core'
|
import { Component, OnInit } from '@angular/core'
|
||||||
import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
|
import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
|
||||||
|
import { prepareIcu } from '@app/helpers'
|
||||||
import { AdvancedInputFilter } from '@app/shared/shared-forms'
|
import { AdvancedInputFilter } from '@app/shared/shared-forms'
|
||||||
import { InstanceFollowService } from '@app/shared/shared-instance'
|
import { InstanceFollowService } from '@app/shared/shared-instance'
|
||||||
|
import { DropdownAction } from '@app/shared/shared-main'
|
||||||
import { ActorFollow } from '@shared/models'
|
import { ActorFollow } from '@shared/models'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -16,7 +18,10 @@ export class FollowersListComponent extends RestTable implements OnInit {
|
||||||
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 }
|
||||||
|
|
||||||
searchFilters: AdvancedInputFilter[]
|
searchFilters: AdvancedInputFilter[] = []
|
||||||
|
|
||||||
|
selectedFollows: ActorFollow[] = []
|
||||||
|
bulkFollowsActions: DropdownAction<ActorFollow[]>[] = []
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private confirmService: ConfirmService,
|
private confirmService: ConfirmService,
|
||||||
|
@ -24,66 +29,73 @@ export class FollowersListComponent extends RestTable implements OnInit {
|
||||||
private followService: InstanceFollowService
|
private followService: InstanceFollowService
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
this.searchFilters = this.followService.buildFollowsListFilters()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.initialize()
|
this.initialize()
|
||||||
|
|
||||||
|
this.searchFilters = this.followService.buildFollowsListFilters()
|
||||||
|
|
||||||
|
this.bulkFollowsActions = [
|
||||||
|
{
|
||||||
|
label: $localize`Reject`,
|
||||||
|
handler: follows => this.rejectFollower(follows),
|
||||||
|
isDisplayed: follows => follows.every(f => f.state !== 'rejected')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: $localize`Accept`,
|
||||||
|
handler: follows => this.acceptFollower(follows),
|
||||||
|
isDisplayed: follows => follows.every(f => f.state !== 'accepted')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: $localize`Delete`,
|
||||||
|
handler: follows => this.deleteFollowers(follows),
|
||||||
|
isDisplayed: follows => follows.every(f => f.state === 'rejected')
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
getIdentifier () {
|
getIdentifier () {
|
||||||
return 'FollowersListComponent'
|
return 'FollowersListComponent'
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptFollower (follow: ActorFollow) {
|
acceptFollower (follows: ActorFollow[]) {
|
||||||
follow.state = 'accepted'
|
this.followService.acceptFollower(follows)
|
||||||
|
|
||||||
this.followService.acceptFollower(follow)
|
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
const handle = follow.follower.name + '@' + follow.follower.host
|
// eslint-disable-next-line max-len
|
||||||
this.notifier.success($localize`${handle} accepted in instance followers`)
|
const message = prepareIcu($localize`Accepted {count, plural, =1 {{followerName} follow request} other {{count} follow requests}}`)(
|
||||||
|
{ count: follows.length, followerName: this.buildFollowerName(follows[0]) },
|
||||||
|
$localize`Follow requests accepted`
|
||||||
|
)
|
||||||
|
this.notifier.success(message)
|
||||||
|
|
||||||
|
this.reloadData()
|
||||||
},
|
},
|
||||||
|
|
||||||
error: err => {
|
error: err => this.notifier.error(err.message)
|
||||||
follow.state = 'pending'
|
|
||||||
this.notifier.error(err.message)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async rejectFollower (follow: ActorFollow) {
|
async rejectFollower (follows: ActorFollow[]) {
|
||||||
const message = $localize`Do you really want to reject this follower?`
|
// eslint-disable-next-line max-len
|
||||||
|
const message = prepareIcu($localize`Do you really want to reject {count, plural, =1 {{followerName} follow request?} other {{count} follow requests?}}`)(
|
||||||
|
{ count: follows.length, followerName: this.buildFollowerName(follows[0]) },
|
||||||
|
$localize`Do you really want to reject these follow requests?`
|
||||||
|
)
|
||||||
|
|
||||||
const res = await this.confirmService.confirm(message, $localize`Reject`)
|
const res = await this.confirmService.confirm(message, $localize`Reject`)
|
||||||
if (res === false) return
|
if (res === false) return
|
||||||
|
|
||||||
this.followService.rejectFollower(follow)
|
this.followService.rejectFollower(follows)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
const handle = follow.follower.name + '@' + follow.follower.host
|
// eslint-disable-next-line max-len
|
||||||
this.notifier.success($localize`${handle} rejected from instance followers`)
|
const message = prepareIcu($localize`Rejected {count, plural, =1 {{followerName} follow request} other {{count} follow requests}}`)(
|
||||||
|
{ count: follows.length, followerName: this.buildFollowerName(follows[0]) },
|
||||||
this.reloadData()
|
$localize`Follow requests rejected`
|
||||||
},
|
)
|
||||||
|
this.notifier.success(message)
|
||||||
error: err => {
|
|
||||||
follow.state = 'pending'
|
|
||||||
this.notifier.error(err.message)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteFollower (follow: ActorFollow) {
|
|
||||||
const message = $localize`Do you really want to delete this follower? It will be able to send again another follow request.`
|
|
||||||
const res = await this.confirmService.confirm(message, $localize`Delete`)
|
|
||||||
if (res === false) return
|
|
||||||
|
|
||||||
this.followService.removeFollower(follow)
|
|
||||||
.subscribe({
|
|
||||||
next: () => {
|
|
||||||
const handle = follow.follower.name + '@' + follow.follower.host
|
|
||||||
this.notifier.success($localize`${handle} removed from instance followers`)
|
|
||||||
|
|
||||||
this.reloadData()
|
this.reloadData()
|
||||||
},
|
},
|
||||||
|
@ -92,6 +104,45 @@ export class FollowersListComponent extends RestTable implements OnInit {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteFollowers (follows: ActorFollow[]) {
|
||||||
|
let message = $localize`Deleted followers will be able to send again a follow request.`
|
||||||
|
message += '<br /><br />'
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
message += prepareIcu($localize`Do you really want to delete {count, plural, =1 {{followerName} follow request?} other {{count} follow requests?}}`)(
|
||||||
|
{ count: follows.length, followerName: this.buildFollowerName(follows[0]) },
|
||||||
|
$localize`Do you really want to delete these follow requests?`
|
||||||
|
)
|
||||||
|
|
||||||
|
const res = await this.confirmService.confirm(message, $localize`Delete`)
|
||||||
|
if (res === false) return
|
||||||
|
|
||||||
|
this.followService.removeFollower(follows)
|
||||||
|
.subscribe({
|
||||||
|
next: () => {
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
const message = prepareIcu($localize`Removed {count, plural, =1 {{followerName} follow request} other {{count} follow requests}}`)(
|
||||||
|
{ count: follows.length, followerName: this.buildFollowerName(follows[0]) },
|
||||||
|
$localize`Follow requests removed`
|
||||||
|
)
|
||||||
|
|
||||||
|
this.notifier.success(message)
|
||||||
|
|
||||||
|
this.reloadData()
|
||||||
|
},
|
||||||
|
|
||||||
|
error: err => this.notifier.error(err.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
buildFollowerName (follow: ActorFollow) {
|
||||||
|
return follow.follower.name + '@' + follow.follower.host
|
||||||
|
}
|
||||||
|
|
||||||
|
isInSelectionMode () {
|
||||||
|
return this.selectedFollows.length !== 0
|
||||||
|
}
|
||||||
|
|
||||||
protected reloadData () {
|
protected reloadData () {
|
||||||
this.followService.getFollowers({ pagination: this.pagination, sort: this.sort, search: this.search })
|
this.followService.getFollowers({ pagination: this.pagination, sort: this.sort, search: this.search })
|
||||||
.subscribe({
|
.subscribe({
|
||||||
|
|
|
@ -9,11 +9,18 @@
|
||||||
[lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false"
|
[lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false"
|
||||||
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
|
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
|
||||||
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} hosts"
|
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} hosts"
|
||||||
|
[(selection)]="selectedFollows"
|
||||||
>
|
>
|
||||||
<ng-template pTemplate="caption">
|
<ng-template pTemplate="caption">
|
||||||
<div class="caption">
|
<div class="caption">
|
||||||
<div class="left-buttons">
|
<div class="left-buttons">
|
||||||
<a class="follow-button" (click)="openFollowModal()" (key.enter)="openFollowModal()">
|
<my-action-dropdown
|
||||||
|
*ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange"
|
||||||
|
[actions]="bulkFollowsActions" [entry]="selectedFollows"
|
||||||
|
>
|
||||||
|
</my-action-dropdown>
|
||||||
|
|
||||||
|
<a *ngIf="!isInSelectionMode()" class="follow-button" (click)="openFollowModal()" (key.enter)="openFollowModal()">
|
||||||
<my-global-icon iconName="following" aria-hidden="true"></my-global-icon>
|
<my-global-icon iconName="following" aria-hidden="true"></my-global-icon>
|
||||||
<ng-container i18n>Follow</ng-container>
|
<ng-container i18n>Follow</ng-container>
|
||||||
</a>
|
</a>
|
||||||
|
@ -27,6 +34,9 @@
|
||||||
|
|
||||||
<ng-template pTemplate="header">
|
<ng-template pTemplate="header">
|
||||||
<tr>
|
<tr>
|
||||||
|
<th style="width: 40px">
|
||||||
|
<p-tableHeaderCheckbox ariaLabel="Select all rows" i18n-ariaLabel></p-tableHeaderCheckbox>
|
||||||
|
</th>
|
||||||
<th style="width: 150px;" i18n>Action</th>
|
<th style="width: 150px;" i18n>Action</th>
|
||||||
<th i18n>Following</th>
|
<th i18n>Following</th>
|
||||||
<th style="width: 100px;" i18n pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th>
|
<th style="width: 100px;" i18n pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th>
|
||||||
|
@ -35,14 +45,18 @@
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template pTemplate="body" let-follow>
|
<ng-template pSelectableRow="follow" pTemplate="body" let-follow>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td class="checkbox-cell">
|
||||||
|
<p-tableCheckbox [value]="follow" ariaLabel="Select this row" i18n-ariaLabel></p-tableCheckbox>
|
||||||
|
</td>
|
||||||
|
|
||||||
<td class="action-cell">
|
<td class="action-cell">
|
||||||
<my-delete-button label (click)="removeFollowing(follow)"></my-delete-button>
|
<my-delete-button label (click)="removeFollowing([ follow ])"></my-delete-button>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a [href]="follow.following.url" i18n-title title="Open instance in a new tab" target="_blank" rel="noopener noreferrer">
|
<a [href]="follow.following.url" i18n-title title="Open instance in a new tab" target="_blank" rel="noopener noreferrer">
|
||||||
{{ follow.following.name + '@' + follow.following.host }}
|
{{ buildFollowingName(follow) }}
|
||||||
<my-global-icon iconName="external-link"></my-global-icon>
|
<my-global-icon iconName="external-link"></my-global-icon>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
@ -65,7 +79,7 @@
|
||||||
|
|
||||||
<ng-template pTemplate="emptymessage">
|
<ng-template pTemplate="emptymessage">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="5">
|
<td colspan="6">
|
||||||
<div class="no-results">
|
<div class="no-results">
|
||||||
<ng-container *ngIf="search" i18n>No host found matching current filters.</ng-container>
|
<ng-container *ngIf="search" i18n>No host found matching current filters.</ng-container>
|
||||||
<ng-container *ngIf="!search" i18n>Your instance is not following anyone.</ng-container>
|
<ng-container *ngIf="!search" i18n>Your instance is not following anyone.</ng-container>
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { AdvancedInputFilter } from '@app/shared/shared-forms'
|
||||||
import { InstanceFollowService } from '@app/shared/shared-instance'
|
import { InstanceFollowService } from '@app/shared/shared-instance'
|
||||||
import { ActorFollow } from '@shared/models'
|
import { ActorFollow } from '@shared/models'
|
||||||
import { FollowModalComponent } from './follow-modal.component'
|
import { FollowModalComponent } from './follow-modal.component'
|
||||||
|
import { DropdownAction } from '@app/shared/shared-main'
|
||||||
|
import { prepareIcu } from '@app/helpers'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './following-list.component.html',
|
templateUrl: './following-list.component.html',
|
||||||
|
@ -18,7 +20,10 @@ export class FollowingListComponent extends RestTable implements OnInit {
|
||||||
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 }
|
||||||
|
|
||||||
searchFilters: AdvancedInputFilter[]
|
searchFilters: AdvancedInputFilter[] = []
|
||||||
|
|
||||||
|
selectedFollows: ActorFollow[] = []
|
||||||
|
bulkFollowsActions: DropdownAction<ActorFollow[]>[] = []
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private notifier: Notifier,
|
private notifier: Notifier,
|
||||||
|
@ -26,12 +31,19 @@ export class FollowingListComponent extends RestTable implements OnInit {
|
||||||
private followService: InstanceFollowService
|
private followService: InstanceFollowService
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
this.searchFilters = this.followService.buildFollowsListFilters()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.initialize()
|
this.initialize()
|
||||||
|
|
||||||
|
this.searchFilters = this.followService.buildFollowsListFilters()
|
||||||
|
|
||||||
|
this.bulkFollowsActions = [
|
||||||
|
{
|
||||||
|
label: $localize`Delete`,
|
||||||
|
handler: follows => this.removeFollowing(follows)
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
getIdentifier () {
|
getIdentifier () {
|
||||||
|
@ -46,17 +58,33 @@ export class FollowingListComponent extends RestTable implements OnInit {
|
||||||
return follow.following.name === 'peertube'
|
return follow.following.name === 'peertube'
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeFollowing (follow: ActorFollow) {
|
isInSelectionMode () {
|
||||||
const res = await this.confirmService.confirm(
|
return this.selectedFollows.length !== 0
|
||||||
$localize`Do you really want to unfollow ${follow.following.host}?`,
|
}
|
||||||
$localize`Unfollow`
|
|
||||||
|
buildFollowingName (follow: ActorFollow) {
|
||||||
|
return follow.following.name + '@' + follow.following.host
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeFollowing (follows: ActorFollow[]) {
|
||||||
|
const message = prepareIcu($localize`Do you really want to unfollow {count, plural, =1 {{entryName}?} other {{count} entries?}}`)(
|
||||||
|
{ count: follows.length, entryName: this.buildFollowingName(follows[0]) },
|
||||||
|
$localize`Do you really want to unfollow these entries?`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const res = await this.confirmService.confirm(message, $localize`Unfollow`)
|
||||||
if (res === false) return
|
if (res === false) return
|
||||||
|
|
||||||
this.followService.unfollow(follow)
|
this.followService.unfollow(follows)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
this.notifier.success($localize`You are not following ${follow.following.host} anymore.`)
|
// eslint-disable-next-line max-len
|
||||||
|
const message = prepareIcu($localize`You are not following {count, plural, =1 {{entryName} anymore.} other {these {count} entries anymore.}}`)(
|
||||||
|
{ count: follows.length, entryName: this.buildFollowingName(follows[0]) },
|
||||||
|
$localize`You are not following them anymore.`
|
||||||
|
)
|
||||||
|
|
||||||
|
this.notifier.success(message)
|
||||||
this.reloadData()
|
this.reloadData()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { SortMeta } from 'primeng/api'
|
import { SortMeta } from 'primeng/api'
|
||||||
import { Observable } from 'rxjs'
|
import { from, Observable } from 'rxjs'
|
||||||
import { catchError, map } from 'rxjs/operators'
|
import { catchError, concatMap, map, toArray } from 'rxjs/operators'
|
||||||
import { HttpClient, HttpParams } from '@angular/common/http'
|
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { RestExtractor, RestPagination, RestService } from '@app/core'
|
import { RestExtractor, RestPagination, RestService } from '@app/core'
|
||||||
|
import { arrayify } from '@shared/core-utils'
|
||||||
import { ActivityPubActorType, ActorFollow, FollowState, ResultList, ServerFollowCreate } from '@shared/models'
|
import { ActivityPubActorType, ActorFollow, FollowState, ResultList, ServerFollowCreate } from '@shared/models'
|
||||||
import { environment } from '../../../environments/environment'
|
import { environment } from '../../../environments/environment'
|
||||||
import { AdvancedInputFilter } from '../shared-forms'
|
import { AdvancedInputFilter } from '../shared-forms'
|
||||||
|
@ -81,32 +82,64 @@ export class InstanceFollowService {
|
||||||
.pipe(catchError(res => this.restExtractor.handleError(res)))
|
.pipe(catchError(res => this.restExtractor.handleError(res)))
|
||||||
}
|
}
|
||||||
|
|
||||||
unfollow (follow: ActorFollow) {
|
unfollow (followsArg: ActorFollow[] | ActorFollow) {
|
||||||
const handle = follow.following.name + '@' + follow.following.host
|
const follows = arrayify(followsArg)
|
||||||
|
|
||||||
return this.authHttp.delete(InstanceFollowService.BASE_APPLICATION_URL + '/following/' + handle)
|
return from(follows)
|
||||||
.pipe(catchError(res => this.restExtractor.handleError(res)))
|
.pipe(
|
||||||
|
concatMap(follow => {
|
||||||
|
const handle = follow.following.name + '@' + follow.following.host
|
||||||
|
|
||||||
|
return this.authHttp.delete(InstanceFollowService.BASE_APPLICATION_URL + '/following/' + handle)
|
||||||
|
}),
|
||||||
|
toArray(),
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptFollower (follow: ActorFollow) {
|
acceptFollower (followsArg: ActorFollow[] | ActorFollow) {
|
||||||
const handle = follow.follower.name + '@' + follow.follower.host
|
const follows = arrayify(followsArg)
|
||||||
|
|
||||||
return this.authHttp.post(`${InstanceFollowService.BASE_APPLICATION_URL}/followers/${handle}/accept`, {})
|
return from(follows)
|
||||||
.pipe(catchError(res => this.restExtractor.handleError(res)))
|
.pipe(
|
||||||
|
concatMap(follow => {
|
||||||
|
const handle = follow.follower.name + '@' + follow.follower.host
|
||||||
|
|
||||||
|
return this.authHttp.post(`${InstanceFollowService.BASE_APPLICATION_URL}/followers/${handle}/accept`, {})
|
||||||
|
}),
|
||||||
|
toArray(),
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
rejectFollower (follow: ActorFollow) {
|
rejectFollower (followsArg: ActorFollow[] | ActorFollow) {
|
||||||
const handle = follow.follower.name + '@' + follow.follower.host
|
const follows = arrayify(followsArg)
|
||||||
|
|
||||||
return this.authHttp.post(`${InstanceFollowService.BASE_APPLICATION_URL}/followers/${handle}/reject`, {})
|
return from(follows)
|
||||||
.pipe(catchError(res => this.restExtractor.handleError(res)))
|
.pipe(
|
||||||
|
concatMap(follow => {
|
||||||
|
const handle = follow.follower.name + '@' + follow.follower.host
|
||||||
|
|
||||||
|
return this.authHttp.post(`${InstanceFollowService.BASE_APPLICATION_URL}/followers/${handle}/reject`, {})
|
||||||
|
}),
|
||||||
|
toArray(),
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
removeFollower (follow: ActorFollow) {
|
removeFollower (followsArg: ActorFollow[] | ActorFollow) {
|
||||||
const handle = follow.follower.name + '@' + follow.follower.host
|
const follows = arrayify(followsArg)
|
||||||
|
|
||||||
return this.authHttp.delete(`${InstanceFollowService.BASE_APPLICATION_URL}/followers/${handle}`)
|
return from(follows)
|
||||||
.pipe(catchError(res => this.restExtractor.handleError(res)))
|
.pipe(
|
||||||
|
concatMap(follow => {
|
||||||
|
const handle = follow.follower.name + '@' + follow.follower.host
|
||||||
|
|
||||||
|
return this.authHttp.delete(`${InstanceFollowService.BASE_APPLICATION_URL}/followers/${handle}`)
|
||||||
|
}),
|
||||||
|
toArray(),
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
buildFollowsListFilters (): AdvancedInputFilter[] {
|
buildFollowsListFilters (): AdvancedInputFilter[] {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { AuthService, ComponentPaginationLight, RestExtractor, RestService, ServerService, UserService } from '@app/core'
|
import { AuthService, ComponentPaginationLight, RestExtractor, RestService, ServerService, UserService } from '@app/core'
|
||||||
import { objectToFormData } from '@app/helpers'
|
import { objectToFormData } from '@app/helpers'
|
||||||
|
import { arrayify } from '@shared/core-utils'
|
||||||
import {
|
import {
|
||||||
BooleanBothQuery,
|
BooleanBothQuery,
|
||||||
FeedFormat,
|
FeedFormat,
|
||||||
|
@ -285,7 +286,7 @@ export class VideoService {
|
||||||
}
|
}
|
||||||
|
|
||||||
removeVideo (idArg: number | number[]) {
|
removeVideo (idArg: number | number[]) {
|
||||||
const ids = Array.isArray(idArg) ? idArg : [ idArg ]
|
const ids = arrayify(idArg)
|
||||||
|
|
||||||
return from(ids)
|
return from(ids)
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { catchError, concatMap, map, toArray } from 'rxjs/operators'
|
||||||
import { HttpClient, HttpParams } from '@angular/common/http'
|
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { RestExtractor, RestPagination, RestService } from '@app/core'
|
import { RestExtractor, RestPagination, RestService } from '@app/core'
|
||||||
|
import { arrayify } from '@shared/core-utils'
|
||||||
import { AccountBlock as AccountBlockServer, BlockStatus, ResultList, ServerBlock } from '@shared/models'
|
import { AccountBlock as AccountBlockServer, BlockStatus, ResultList, ServerBlock } from '@shared/models'
|
||||||
import { environment } from '../../../environments/environment'
|
import { environment } from '../../../environments/environment'
|
||||||
import { Account } from '../shared-main'
|
import { Account } from '../shared-main'
|
||||||
|
@ -122,7 +123,7 @@ export class BlocklistService {
|
||||||
}
|
}
|
||||||
|
|
||||||
blockAccountByInstance (accountsArg: Pick<Account, 'nameWithHost'> | Pick<Account, 'nameWithHost'>[]) {
|
blockAccountByInstance (accountsArg: Pick<Account, 'nameWithHost'> | Pick<Account, 'nameWithHost'>[]) {
|
||||||
const accounts = Array.isArray(accountsArg) ? accountsArg : [ accountsArg ]
|
const accounts = arrayify(accountsArg)
|
||||||
|
|
||||||
return from(accounts)
|
return from(accounts)
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { catchError, concatMap, map, toArray } from 'rxjs/operators'
|
||||||
import { HttpClient, HttpParams } from '@angular/common/http'
|
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { RestExtractor, RestPagination, RestService } from '@app/core'
|
import { RestExtractor, RestPagination, RestService } from '@app/core'
|
||||||
|
import { arrayify } from '@shared/core-utils'
|
||||||
import { ResultList, VideoBlacklist, VideoBlacklistType } from '@shared/models'
|
import { ResultList, VideoBlacklist, VideoBlacklistType } from '@shared/models'
|
||||||
import { environment } from '../../../environments/environment'
|
import { environment } from '../../../environments/environment'
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ export class VideoBlockService {
|
||||||
}
|
}
|
||||||
|
|
||||||
unblockVideo (videoIdArgs: number | number[]) {
|
unblockVideo (videoIdArgs: number | number[]) {
|
||||||
const videoIds = Array.isArray(videoIdArgs) ? videoIdArgs : [ videoIdArgs ]
|
const videoIds = arrayify(videoIdArgs)
|
||||||
|
|
||||||
return observableFrom(videoIds)
|
return observableFrom(videoIds)
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { HttpClient, HttpParams } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { RestExtractor, RestPagination, RestService, UserService } from '@app/core'
|
import { RestExtractor, RestPagination, RestService, UserService } from '@app/core'
|
||||||
import { getBytes } from '@root-helpers/bytes'
|
import { getBytes } from '@root-helpers/bytes'
|
||||||
|
import { arrayify } from '@shared/core-utils'
|
||||||
import { ResultList, User as UserServerModel, UserCreate, UserRole, UserUpdate } from '@shared/models'
|
import { ResultList, User as UserServerModel, UserCreate, UserRole, UserUpdate } from '@shared/models'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -65,7 +66,7 @@ export class UserAdminService {
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUser (usersArg: UserServerModel | UserServerModel[]) {
|
removeUser (usersArg: UserServerModel | UserServerModel[]) {
|
||||||
const users = Array.isArray(usersArg) ? usersArg : [ usersArg ]
|
const users = arrayify(usersArg)
|
||||||
|
|
||||||
return from(users)
|
return from(users)
|
||||||
.pipe(
|
.pipe(
|
||||||
|
@ -77,7 +78,7 @@ export class UserAdminService {
|
||||||
|
|
||||||
banUsers (usersArg: UserServerModel | UserServerModel[], reason?: string) {
|
banUsers (usersArg: UserServerModel | UserServerModel[], reason?: string) {
|
||||||
const body = reason ? { reason } : {}
|
const body = reason ? { reason } : {}
|
||||||
const users = Array.isArray(usersArg) ? usersArg : [ usersArg ]
|
const users = arrayify(usersArg)
|
||||||
|
|
||||||
return from(users)
|
return from(users)
|
||||||
.pipe(
|
.pipe(
|
||||||
|
@ -88,7 +89,7 @@ export class UserAdminService {
|
||||||
}
|
}
|
||||||
|
|
||||||
unbanUsers (usersArg: UserServerModel | UserServerModel[]) {
|
unbanUsers (usersArg: UserServerModel | UserServerModel[]) {
|
||||||
const users = Array.isArray(usersArg) ? usersArg : [ usersArg ]
|
const users = arrayify(usersArg)
|
||||||
|
|
||||||
return from(users)
|
return from(users)
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
@ -276,7 +276,7 @@ export class ActorFollowModel extends Model<Partial<AttributesOnly<ActorFollowMo
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const where: WhereAttributeHash<Attributes<ActorFollowModel>> = { actorId}
|
const where: WhereAttributeHash<Attributes<ActorFollowModel>> = { actorId }
|
||||||
if (state) where.state = state
|
if (state) where.state = state
|
||||||
|
|
||||||
const query: FindOptions<Attributes<ActorFollowModel>> = {
|
const query: FindOptions<Attributes<ActorFollowModel>> = {
|
||||||
|
|
|
@ -8,6 +8,14 @@ function findCommonElement <T> (array1: T[], array2: T[]) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
// Avoid conflict with other toArray() functions
|
||||||
findCommonElement
|
function arrayify <T> (element: T | T[]) {
|
||||||
|
if (Array.isArray(element)) return element
|
||||||
|
|
||||||
|
return [ element ]
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
findCommonElement,
|
||||||
|
arrayify
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue