mirror of https://github.com/Chocobozzz/PeerTube
Add bulk actions in users table
parent
80c7336a89
commit
791645e620
|
@ -10,10 +10,31 @@
|
||||||
<p-table
|
<p-table
|
||||||
[value]="users" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
|
[value]="users" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
|
||||||
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id"
|
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id"
|
||||||
|
[(selection)]="selectedUsers"
|
||||||
>
|
>
|
||||||
|
<ng-template pTemplate="caption">
|
||||||
|
<div class="caption">
|
||||||
|
<div>
|
||||||
|
<my-action-dropdown
|
||||||
|
*ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange"
|
||||||
|
[actions]="bulkUserActions" [entry]="selectedUsers"
|
||||||
|
>
|
||||||
|
</my-action-dropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..."
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
<ng-template pTemplate="header">
|
<ng-template pTemplate="header">
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 40px"></th>
|
<th style="width: 40px"></th>
|
||||||
|
<th style="width: 40px">
|
||||||
|
</th>
|
||||||
<th i18n pSortableColumn="username">Username <p-sortIcon field="username"></p-sortIcon></th>
|
<th i18n pSortableColumn="username">Username <p-sortIcon field="username"></p-sortIcon></th>
|
||||||
<th i18n>Email</th>
|
<th i18n>Email</th>
|
||||||
<th i18n>Video quota</th>
|
<th i18n>Video quota</th>
|
||||||
|
@ -25,12 +46,17 @@
|
||||||
|
|
||||||
<ng-template pTemplate="body" let-expanded="expanded" let-user>
|
<ng-template pTemplate="body" let-expanded="expanded" let-user>
|
||||||
|
|
||||||
<tr [ngClass]="{ banned: user.blocked }">
|
<tr [pSelectableRow]="user" [ngClass]="{ banned: user.blocked }">
|
||||||
|
<td>
|
||||||
|
<p-tableCheckbox [value]="user"></p-tableCheckbox>
|
||||||
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<span *ngIf="user.blockedReason" class="expander" [pRowToggler]="user">
|
<span *ngIf="user.blockedReason" class="expander" [pRowToggler]="user">
|
||||||
<i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i>
|
<i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
{{ user.username }}
|
{{ user.username }}
|
||||||
<span *ngIf="user.blocked" class="banned-info">(banned)</span>
|
<span *ngIf="user.blocked" class="banned-info">(banned)</span>
|
||||||
|
@ -40,7 +66,7 @@
|
||||||
<td>{{ user.roleLabel }}</td>
|
<td>{{ user.roleLabel }}</td>
|
||||||
<td>{{ user.createdAt }}</td>
|
<td>{{ user.createdAt }}</td>
|
||||||
<td class="action-cell">
|
<td class="action-cell">
|
||||||
<my-user-moderation-dropdown [user]="user" (userChanged)="onUserChanged()" (userDeleted)="onUserChanged()">
|
<my-user-moderation-dropdown *ngIf="!isInSelectionMode()" [user]="user" (userChanged)="onUserChanged()" (userDeleted)="onUserChanged()">
|
||||||
</my-user-moderation-dropdown>
|
</my-user-moderation-dropdown>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -56,3 +82,4 @@
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-table>
|
</p-table>
|
||||||
|
|
||||||
|
<my-user-ban-modal #userBanModal (userBanned)="onUsersBanned()"></my-user-ban-modal>
|
||||||
|
|
|
@ -15,4 +15,15 @@ tr.banned {
|
||||||
|
|
||||||
.ban-reason-label {
|
.ban-reason-label {
|
||||||
font-weight: $font-semibold;
|
font-weight: $font-semibold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caption {
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
input {
|
||||||
|
@include peertube-input-text(250px);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,12 @@
|
||||||
import { Component, OnInit } from '@angular/core'
|
import { Component, OnInit, ViewChild } from '@angular/core'
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
import { SortMeta } from 'primeng/components/common/sortmeta'
|
import { SortMeta } from 'primeng/components/common/sortmeta'
|
||||||
import { ConfirmService } from '../../../core'
|
import { ConfirmService } from '../../../core'
|
||||||
import { RestPagination, RestTable, UserService } from '../../../shared'
|
import { RestPagination, RestTable, UserService } from '../../../shared'
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { User } from '../../../../../../shared'
|
import { User } from '../../../../../../shared'
|
||||||
|
import { UserBanModalComponent } from '@app/shared/moderation'
|
||||||
|
import { DropdownAction } from '@app/shared/buttons/action-dropdown.component'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-user-list',
|
selector: 'my-user-list',
|
||||||
|
@ -12,12 +14,17 @@ import { User } from '../../../../../../shared'
|
||||||
styleUrls: [ './user-list.component.scss' ]
|
styleUrls: [ './user-list.component.scss' ]
|
||||||
})
|
})
|
||||||
export class UserListComponent extends RestTable implements OnInit {
|
export class UserListComponent extends RestTable implements OnInit {
|
||||||
|
@ViewChild('userBanModal') userBanModal: UserBanModalComponent
|
||||||
|
|
||||||
users: User[] = []
|
users: User[] = []
|
||||||
totalRecords = 0
|
totalRecords = 0
|
||||||
rowsPerPage = 10
|
rowsPerPage = 10
|
||||||
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 }
|
||||||
|
|
||||||
|
selectedUsers: User[] = []
|
||||||
|
bulkUserActions: DropdownAction<User>[] = []
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private confirmService: ConfirmService,
|
private confirmService: ConfirmService,
|
||||||
|
@ -29,13 +36,28 @@ export class UserListComponent extends RestTable implements OnInit {
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.loadSort()
|
this.loadSort()
|
||||||
}
|
|
||||||
|
|
||||||
onUserChanged () {
|
this.bulkUserActions = [
|
||||||
this.loadData()
|
{
|
||||||
|
label: this.i18n('Delete'),
|
||||||
|
handler: users => this.removeUsers(users)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.i18n('Ban'),
|
||||||
|
handler: users => this.openBanUserModal(users),
|
||||||
|
isDisplayed: users => users.every(u => u.blocked === false)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.i18n('Unban'),
|
||||||
|
handler: users => this.unbanUsers(users),
|
||||||
|
isDisplayed: users => users.every(u => u.blocked === true)
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
protected loadData () {
|
protected loadData () {
|
||||||
|
this.selectedUsers = []
|
||||||
|
|
||||||
this.userService.getUsers(this.pagination, this.sort)
|
this.userService.getUsers(this.pagination, this.sort)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
resultList => {
|
resultList => {
|
||||||
|
@ -46,4 +68,67 @@ export class UserListComponent extends RestTable implements OnInit {
|
||||||
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openBanUserModal (users: User[]) {
|
||||||
|
for (const user of users) {
|
||||||
|
if (user.username === 'root') {
|
||||||
|
this.notificationsService.error(this.i18n('Error'), this.i18n('You cannot ban root.'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.userBanModal.openModal(users)
|
||||||
|
}
|
||||||
|
|
||||||
|
onUsersBanned () {
|
||||||
|
this.loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
async unbanUsers (users: User[]) {
|
||||||
|
const message = this.i18n('Do you really want to unban {{num}} users?', { num: users.length })
|
||||||
|
|
||||||
|
const res = await this.confirmService.confirm(message, this.i18n('Unban'))
|
||||||
|
if (res === false) return
|
||||||
|
|
||||||
|
this.userService.unbanUsers(users)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
const message = this.i18n('{{num}} users unbanned.', { num: users.length })
|
||||||
|
|
||||||
|
this.notificationsService.success(this.i18n('Success'), message)
|
||||||
|
this.loadData()
|
||||||
|
},
|
||||||
|
|
||||||
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeUsers (users: User[]) {
|
||||||
|
for (const user of users) {
|
||||||
|
if (user.username === 'root') {
|
||||||
|
this.notificationsService.error(this.i18n('Error'), this.i18n('You cannot delete root.'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = this.i18n('If you remove these users, you will not be able to create others with the same username!')
|
||||||
|
const res = await this.confirmService.confirm(message, this.i18n('Delete'))
|
||||||
|
if (res === false) return
|
||||||
|
|
||||||
|
this.userService.removeUser(users).subscribe(
|
||||||
|
() => {
|
||||||
|
this.notificationsService.success(
|
||||||
|
this.i18n('Success'),
|
||||||
|
this.i18n('{{num}} users deleted.', { num: users.length })
|
||||||
|
)
|
||||||
|
this.loadData()
|
||||||
|
},
|
||||||
|
|
||||||
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
isInSelectionMode () {
|
||||||
|
return this.selectedUsers.length !== 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<input
|
<input
|
||||||
type="text" id="search-video" name="search-video" i18n-placeholder placeholder="Search..."
|
type="text" id="search-video" name="search-video" i18n-placeholder placeholder="Search..."
|
||||||
[(ngModel)]="searchValue" (keyup.enter)="doSearch()"
|
[(ngModel)]="searchValue" (keyup.enter)="doSearch()"
|
||||||
>
|
>
|
||||||
<span (click)="doSearch()" class="icon icon-search"></span>
|
<span (click)="doSearch()" class="icon icon-search"></span>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
<div class="dropdown-root" ngbDropdown [placement]="placement">
|
<div class="dropdown-root" ngbDropdown [placement]="placement">
|
||||||
<div class="action-button" [ngClass]="{ small: buttonSize === 'small' }" ngbDropdownToggle role="button">
|
<div
|
||||||
<span class="icon icon-action"></span>
|
class="action-button" [ngClass]="{ small: buttonSize === 'small', grey: theme === 'grey', orange: theme === 'orange' }"
|
||||||
|
ngbDropdownToggle role="button"
|
||||||
|
>
|
||||||
|
<span *ngIf="!label" class="icon icon-action"></span>
|
||||||
|
<span *ngIf="label" class="dropdown-toggle">{{ label }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ngbDropdownMenu class="dropdown-menu">
|
<div ngbDropdownMenu class="dropdown-menu">
|
||||||
|
|
|
@ -3,7 +3,14 @@
|
||||||
|
|
||||||
.action-button {
|
.action-button {
|
||||||
@include peertube-button;
|
@include peertube-button;
|
||||||
@include grey-button;
|
|
||||||
|
&.grey {
|
||||||
|
@include grey-button;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.orange {
|
||||||
|
@include orange-button;
|
||||||
|
}
|
||||||
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
@ -30,6 +37,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-toggle::after {
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
.dropdown-item {
|
.dropdown-item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
@ -16,6 +16,8 @@ export type DropdownAction<T> = {
|
||||||
export class ActionDropdownComponent<T> {
|
export class ActionDropdownComponent<T> {
|
||||||
@Input() actions: DropdownAction<T>[] = []
|
@Input() actions: DropdownAction<T>[] = []
|
||||||
@Input() entry: T
|
@Input() entry: T
|
||||||
@Input() placement = 'left'
|
@Input() placement = 'bottom-left'
|
||||||
@Input() buttonSize: 'normal' | 'small' = 'normal'
|
@Input() buttonSize: 'normal' | 'small' = 'normal'
|
||||||
|
@Input() label: string
|
||||||
|
@Input() theme: 'orange' | 'grey' = 'grey'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<ng-template #modal>
|
<ng-template #modal>
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 i18n class="modal-title">Ban {{ userToBan.username }}</h4>
|
<h4 i18n class="modal-title">Ban</h4>
|
||||||
<span class="close" aria-hidden="true" (click)="hideBanUserModal()"></span>
|
<span class="close" aria-hidden="true" (click)="hideBanUserModal()"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,9 @@ import { User } from '../../../../../shared'
|
||||||
})
|
})
|
||||||
export class UserBanModalComponent extends FormReactive implements OnInit {
|
export class UserBanModalComponent extends FormReactive implements OnInit {
|
||||||
@ViewChild('modal') modal: NgbModal
|
@ViewChild('modal') modal: NgbModal
|
||||||
@Output() userBanned = new EventEmitter<User>()
|
@Output() userBanned = new EventEmitter<User | User[]>()
|
||||||
|
|
||||||
private userToBan: User
|
private usersToBan: User | User[]
|
||||||
private openedModal: NgbModalRef
|
private openedModal: NgbModalRef
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
@ -37,28 +37,29 @@ export class UserBanModalComponent extends FormReactive implements OnInit {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
openModal (user: User) {
|
openModal (user: User | User[]) {
|
||||||
this.userToBan = user
|
this.usersToBan = user
|
||||||
this.openedModal = this.modalService.open(this.modal)
|
this.openedModal = this.modalService.open(this.modal)
|
||||||
}
|
}
|
||||||
|
|
||||||
hideBanUserModal () {
|
hideBanUserModal () {
|
||||||
this.userToBan = undefined
|
this.usersToBan = undefined
|
||||||
this.openedModal.close()
|
this.openedModal.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
async banUser () {
|
async banUser () {
|
||||||
const reason = this.form.value['reason'] || undefined
|
const reason = this.form.value['reason'] || undefined
|
||||||
|
|
||||||
this.userService.banUser(this.userToBan, reason)
|
this.userService.banUsers(this.usersToBan, reason)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
() => {
|
() => {
|
||||||
this.notificationsService.success(
|
const message = Array.isArray(this.usersToBan)
|
||||||
this.i18n('Success'),
|
? this.i18n('{{num}} users banned.', { num: this.usersToBan.length })
|
||||||
this.i18n('User {{username}} banned.', { username: this.userToBan.username })
|
: this.i18n('User {{username}} banned.', { username: this.usersToBan.username })
|
||||||
)
|
|
||||||
|
|
||||||
this.userBanned.emit(this.userToBan)
|
this.notificationsService.success(this.i18n('Success'), message)
|
||||||
|
|
||||||
|
this.userBanned.emit(this.usersToBan)
|
||||||
this.hideBanUserModal()
|
this.hideBanUserModal()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<ng-container *ngIf="user && userActions.length !== 0">
|
<ng-container *ngIf="user && userActions.length !== 0">
|
||||||
<my-user-ban-modal #userBanModal (userBanned)="onUserBanned()"></my-user-ban-modal>
|
<my-user-ban-modal #userBanModal (userBanned)="onUserBanned()"></my-user-ban-modal>
|
||||||
|
|
||||||
<my-action-dropdown i18n-label label="Actions" [actions]="userActions" [entry]="user" [buttonSize]="buttonSize"></my-action-dropdown>
|
<my-action-dropdown [actions]="userActions" [entry]="user" [buttonSize]="buttonSize"></my-action-dropdown>
|
||||||
</ng-container>
|
</ng-container>
|
|
@ -2,7 +2,6 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angu
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { DropdownAction } from '@app/shared/buttons/action-dropdown.component'
|
import { DropdownAction } from '@app/shared/buttons/action-dropdown.component'
|
||||||
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
|
|
||||||
import { UserBanModalComponent } from '@app/shared/moderation/user-ban-modal.component'
|
import { UserBanModalComponent } from '@app/shared/moderation/user-ban-modal.component'
|
||||||
import { UserService } from '@app/shared/users'
|
import { UserService } from '@app/shared/users'
|
||||||
import { AuthService, ConfirmService } from '@app/core'
|
import { AuthService, ConfirmService } from '@app/core'
|
||||||
|
@ -24,8 +23,6 @@ export class UserModerationDropdownComponent implements OnInit {
|
||||||
|
|
||||||
userActions: DropdownAction<User>[] = []
|
userActions: DropdownAction<User>[] = []
|
||||||
|
|
||||||
private openedModal: NgbModalRef
|
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
|
@ -38,10 +35,6 @@ export class UserModerationDropdownComponent implements OnInit {
|
||||||
this.buildActions()
|
this.buildActions()
|
||||||
}
|
}
|
||||||
|
|
||||||
hideBanUserModal () {
|
|
||||||
this.openedModal.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
openBanUserModal (user: User) {
|
openBanUserModal (user: User) {
|
||||||
if (user.username === 'root') {
|
if (user.username === 'root') {
|
||||||
this.notificationsService.error(this.i18n('Error'), this.i18n('You cannot ban root.'))
|
this.notificationsService.error(this.i18n('Error'), this.i18n('You cannot ban root.'))
|
||||||
|
@ -60,7 +53,7 @@ export class UserModerationDropdownComponent implements OnInit {
|
||||||
const res = await this.confirmService.confirm(message, this.i18n('Unban'))
|
const res = await this.confirmService.confirm(message, this.i18n('Unban'))
|
||||||
if (res === false) return
|
if (res === false) return
|
||||||
|
|
||||||
this.userService.unbanUser(user)
|
this.userService.unbanUsers(user)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
() => {
|
() => {
|
||||||
this.notificationsService.success(
|
this.notificationsService.success(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
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 { ResultList, User, UserCreate, UserRole, UserUpdate, UserUpdateMe, UserVideoQuota } from '../../../../../shared'
|
import { ResultList, User, UserCreate, UserRole, UserUpdate, UserUpdateMe, UserVideoQuota } from '../../../../../shared'
|
||||||
|
@ -170,21 +170,38 @@ export class UserService {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUser (user: { id: number }) {
|
removeUser (usersArg: User | User[]) {
|
||||||
return this.authHttp.delete(UserService.BASE_USERS_URL + user.id)
|
const users = Array.isArray(usersArg) ? usersArg : [ usersArg ]
|
||||||
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
|
||||||
|
return from(users)
|
||||||
|
.pipe(
|
||||||
|
concatMap(u => this.authHttp.delete(UserService.BASE_USERS_URL + u.id)),
|
||||||
|
toArray(),
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
banUser (user: { id: number }, reason?: string) {
|
banUsers (usersArg: User | User[], reason?: string) {
|
||||||
const body = reason ? { reason } : {}
|
const body = reason ? { reason } : {}
|
||||||
|
const users = Array.isArray(usersArg) ? usersArg : [ usersArg ]
|
||||||
|
|
||||||
return this.authHttp.post(UserService.BASE_USERS_URL + user.id + '/block', body)
|
return from(users)
|
||||||
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
.pipe(
|
||||||
|
concatMap(u => this.authHttp.post(UserService.BASE_USERS_URL + u.id + '/block', body)),
|
||||||
|
toArray(),
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
unbanUser (user: { id: number }) {
|
unbanUsers (usersArg: User | User[]) {
|
||||||
return this.authHttp.post(UserService.BASE_USERS_URL + user.id + '/unblock', {})
|
const users = Array.isArray(usersArg) ? usersArg : [ usersArg ]
|
||||||
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
|
||||||
|
return from(users)
|
||||||
|
.pipe(
|
||||||
|
concatMap(u => this.authHttp.post(UserService.BASE_USERS_URL + u.id + '/unblock', {})),
|
||||||
|
toArray(),
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private formatUser (user: User) {
|
private formatUser (user: User) {
|
||||||
|
|
|
@ -14,8 +14,11 @@
|
||||||
p-table {
|
p-table {
|
||||||
font-size: 15px !important;
|
font-size: 15px !important;
|
||||||
|
|
||||||
|
.ui-table-caption {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
// border: 1px solid #E5E5E5 !important;
|
|
||||||
padding-left: 15px !important;
|
padding-left: 15px !important;
|
||||||
|
|
||||||
&:not(.action-cell) {
|
&:not(.action-cell) {
|
||||||
|
@ -28,6 +31,11 @@ p-table {
|
||||||
tr {
|
tr {
|
||||||
background-color: var(--mainBackgroundColor) !important;
|
background-color: var(--mainBackgroundColor) !important;
|
||||||
height: 46px;
|
height: 46px;
|
||||||
|
|
||||||
|
&.ui-state-highlight {
|
||||||
|
background-color:var(--submenuColor) !important;
|
||||||
|
color:var(--mainForegroundColor) !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-table-tbody {
|
.ui-table-tbody {
|
||||||
|
@ -216,4 +224,32 @@ p-calendar .ui-datepicker {
|
||||||
@include glyphicon-light;
|
@include glyphicon-light;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-chkbox-box {
|
||||||
|
&.ui-state-active {
|
||||||
|
border-color: var(--mainColor) !important;
|
||||||
|
background-color: var(--mainColor) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-chkbox-icon {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 5px;
|
||||||
|
width: 5px;
|
||||||
|
height: 12px;
|
||||||
|
opacity: 0;
|
||||||
|
transform: rotate(45deg) scale(0);
|
||||||
|
border-right: 2px solid var(--mainBackgroundColor);
|
||||||
|
border-bottom: 2px solid var(--mainBackgroundColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.pi-check:after {
|
||||||
|
opacity: 1;
|
||||||
|
transform: rotate(45deg) scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue