mirror of https://github.com/Chocobozzz/PeerTube
Improve admin users list table
* Fix last login sort with null values * Remember last selected columns * Display last login date by defaultpull/5004/head
parent
3eba7ab815
commit
87a0cac618
|
@ -5,7 +5,7 @@
|
|||
|
||||
<p-table
|
||||
[value]="users" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions"
|
||||
[sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" [resizableColumns]="true" [(selection)]="selectedUsers"
|
||||
[sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" [resizableColumns]="true" [(selection)]="selectedUsers"
|
||||
[lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [selectionPageOnly]="true"
|
||||
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
|
||||
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} users"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { SortMeta } from 'primeng/api'
|
||||
import { Component, OnInit, ViewChild } from '@angular/core'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService } from '@app/core'
|
||||
import { AuthService, ConfirmService, LocalStorageService, Notifier, RestPagination, RestTable, ServerService } from '@app/core'
|
||||
import { getAPIHost } from '@app/helpers'
|
||||
import { AdvancedInputFilter } from '@app/shared/shared-forms'
|
||||
import { Actor, DropdownAction } from '@app/shared/shared-main'
|
||||
|
@ -22,6 +22,8 @@ type UserForList = User & {
|
|||
styleUrls: [ './user-list.component.scss' ]
|
||||
})
|
||||
export class UserListComponent extends RestTable implements OnInit {
|
||||
private static readonly LOCAL_STORAGE_SELECTED_COLUMNS_KEY = 'admin-user-list-selected-columns'
|
||||
|
||||
@ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent
|
||||
|
||||
users: (User & { accountMutedStatus: AccountMutedStatus })[] = []
|
||||
|
@ -56,7 +58,7 @@ export class UserListComponent extends RestTable implements OnInit {
|
|||
|
||||
requiresEmailVerification = false
|
||||
|
||||
private _selectedColumns: string[]
|
||||
private _selectedColumns: string[] = []
|
||||
|
||||
constructor (
|
||||
protected route: ActivatedRoute,
|
||||
|
@ -66,7 +68,8 @@ export class UserListComponent extends RestTable implements OnInit {
|
|||
private serverService: ServerService,
|
||||
private auth: AuthService,
|
||||
private blocklist: BlocklistService,
|
||||
private userAdminService: UserAdminService
|
||||
private userAdminService: UserAdminService,
|
||||
private peertubeLocalStorage: LocalStorageService
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
@ -76,11 +79,13 @@ export class UserListComponent extends RestTable implements OnInit {
|
|||
}
|
||||
|
||||
get selectedColumns () {
|
||||
return this._selectedColumns
|
||||
return this._selectedColumns || []
|
||||
}
|
||||
|
||||
set selectedColumns (val: string[]) {
|
||||
this._selectedColumns = val
|
||||
|
||||
this.saveSelectedColumns()
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
|
@ -126,14 +131,35 @@ export class UserListComponent extends RestTable implements OnInit {
|
|||
{ id: 'role', label: $localize`Role` },
|
||||
{ id: 'email', label: $localize`Email` },
|
||||
{ id: 'quota', label: $localize`Video quota` },
|
||||
{ id: 'createdAt', label: $localize`Created` }
|
||||
{ id: 'createdAt', label: $localize`Created` },
|
||||
{ id: 'lastLoginDate', label: $localize`Last login` },
|
||||
|
||||
{ id: 'quotaDaily', label: $localize`Daily quota` },
|
||||
{ id: 'pluginAuth', label: $localize`Auth plugin` }
|
||||
]
|
||||
|
||||
this.selectedColumns = this.columns.map(c => c.id)
|
||||
this.loadSelectedColumns()
|
||||
}
|
||||
|
||||
this.columns.push({ id: 'quotaDaily', label: $localize`Daily quota` })
|
||||
this.columns.push({ id: 'pluginAuth', label: $localize`Auth plugin` })
|
||||
this.columns.push({ id: 'lastLoginDate', label: $localize`Last login` })
|
||||
loadSelectedColumns () {
|
||||
const result = this.peertubeLocalStorage.getItem(UserListComponent.LOCAL_STORAGE_SELECTED_COLUMNS_KEY)
|
||||
|
||||
if (result) {
|
||||
try {
|
||||
this.selectedColumns = JSON.parse(result)
|
||||
return
|
||||
} catch (err) {
|
||||
console.error('Cannot load selected columns.', err)
|
||||
}
|
||||
}
|
||||
|
||||
// Default behaviour
|
||||
this.selectedColumns = [ 'username', 'role', 'email', 'quota', 'createdAt', 'lastLoginDate' ]
|
||||
return
|
||||
}
|
||||
|
||||
saveSelectedColumns () {
|
||||
this.peertubeLocalStorage.setItem(UserListComponent.LOCAL_STORAGE_SELECTED_COLUMNS_KEY, JSON.stringify(this.selectedColumns))
|
||||
}
|
||||
|
||||
getIdentifier () {
|
||||
|
|
|
@ -39,6 +39,10 @@ export abstract class RestTable {
|
|||
}
|
||||
}
|
||||
|
||||
saveSort () {
|
||||
peertubeLocalStorage.setItem(this.getSortLocalStorageKey(), JSON.stringify(this.sort))
|
||||
}
|
||||
|
||||
loadLazy (event: LazyLoadEvent) {
|
||||
logger('Load lazy %o.', event)
|
||||
|
||||
|
@ -60,10 +64,6 @@ export abstract class RestTable {
|
|||
this.saveSort()
|
||||
}
|
||||
|
||||
saveSort () {
|
||||
peertubeLocalStorage.setItem(this.getSortLocalStorageKey(), JSON.stringify(this.sort))
|
||||
}
|
||||
|
||||
onSearch (search: string) {
|
||||
this.search = search
|
||||
this.reloadData()
|
||||
|
|
|
@ -32,7 +32,7 @@ import {
|
|||
usersListValidator,
|
||||
usersRegisterValidator,
|
||||
usersRemoveValidator,
|
||||
usersSortValidator,
|
||||
adminUsersSortValidator,
|
||||
usersUpdateValidator
|
||||
} from '../../../middlewares'
|
||||
import {
|
||||
|
@ -84,7 +84,7 @@ usersRouter.get('/',
|
|||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_USERS),
|
||||
paginationValidator,
|
||||
usersSortValidator,
|
||||
adminUsersSortValidator,
|
||||
setDefaultSort,
|
||||
setDefaultPagination,
|
||||
usersListValidator,
|
||||
|
@ -277,7 +277,7 @@ async function autocompleteUsers (req: express.Request, res: express.Response) {
|
|||
}
|
||||
|
||||
async function listUsers (req: express.Request, res: express.Response) {
|
||||
const resultList = await UserModel.listForApi({
|
||||
const resultList = await UserModel.listForAdminApi({
|
||||
start: req.query.start,
|
||||
count: req.query.count,
|
||||
sort: req.query.sort,
|
||||
|
|
|
@ -58,7 +58,7 @@ const WEBSERVER = {
|
|||
|
||||
// Sortable columns per schema
|
||||
const SORTABLE_COLUMNS = {
|
||||
USERS: [ 'id', 'username', 'videoQuotaUsed', 'createdAt', 'lastLoginDate', 'role' ],
|
||||
ADMIN_USERS: [ 'id', 'username', 'videoQuotaUsed', 'createdAt', 'lastLoginDate', 'role' ],
|
||||
USER_SUBSCRIPTIONS: [ 'id', 'createdAt' ],
|
||||
ACCOUNTS: [ 'createdAt' ],
|
||||
JOBS: [ 'createdAt' ],
|
||||
|
|
|
@ -28,7 +28,7 @@ function createSortableColumns (sortableColumns: string[]) {
|
|||
return sortableColumns.concat(sortableColumnDesc)
|
||||
}
|
||||
|
||||
const usersSortValidator = checkSortFactory(SORTABLE_COLUMNS.USERS)
|
||||
const adminUsersSortValidator = checkSortFactory(SORTABLE_COLUMNS.ADMIN_USERS)
|
||||
const accountsSortValidator = checkSortFactory(SORTABLE_COLUMNS.ACCOUNTS)
|
||||
const jobsSortValidator = checkSortFactory(SORTABLE_COLUMNS.JOBS, [ 'jobs' ])
|
||||
const abusesSortValidator = checkSortFactory(SORTABLE_COLUMNS.ABUSES)
|
||||
|
@ -59,7 +59,7 @@ const videoChannelsFollowersSortValidator = checkSortFactory(SORTABLE_COLUMNS.CH
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
usersSortValidator,
|
||||
adminUsersSortValidator,
|
||||
abusesSortValidator,
|
||||
videoChannelsSortValidator,
|
||||
videoImportsSortValidator,
|
||||
|
|
|
@ -66,7 +66,7 @@ import { ActorModel } from '../actor/actor'
|
|||
import { ActorFollowModel } from '../actor/actor-follow'
|
||||
import { ActorImageModel } from '../actor/actor-image'
|
||||
import { OAuthTokenModel } from '../oauth/oauth-token'
|
||||
import { getSort, throwIfNotValid } from '../utils'
|
||||
import { getAdminUsersSort, throwIfNotValid } from '../utils'
|
||||
import { VideoModel } from '../video/video'
|
||||
import { VideoChannelModel } from '../video/video-channel'
|
||||
import { VideoImportModel } from '../video/video-import'
|
||||
|
@ -461,7 +461,7 @@ export class UserModel extends Model<Partial<AttributesOnly<UserModel>>> {
|
|||
return this.count()
|
||||
}
|
||||
|
||||
static listForApi (parameters: {
|
||||
static listForAdminApi (parameters: {
|
||||
start: number
|
||||
count: number
|
||||
sort: string
|
||||
|
@ -497,7 +497,7 @@ export class UserModel extends Model<Partial<AttributesOnly<UserModel>>> {
|
|||
const query: FindOptions = {
|
||||
offset: start,
|
||||
limit: count,
|
||||
order: getSort(sort),
|
||||
order: getAdminUsersSort(sort),
|
||||
where
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@ function getSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderIt
|
|||
|
||||
if (field.toLowerCase() === 'match') { // Search
|
||||
finalField = Sequelize.col('similarity')
|
||||
} else if (field === 'videoQuotaUsed') { // Users list
|
||||
finalField = Sequelize.col('videoQuotaUsed')
|
||||
} else {
|
||||
finalField = field
|
||||
}
|
||||
|
@ -20,6 +18,25 @@ function getSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderIt
|
|||
return [ [ finalField, direction ], lastSort ]
|
||||
}
|
||||
|
||||
function getAdminUsersSort (value: string): OrderItem[] {
|
||||
const { direction, field } = buildDirectionAndField(value)
|
||||
|
||||
let finalField: string | ReturnType<typeof Sequelize.col>
|
||||
|
||||
if (field === 'videoQuotaUsed') { // Users list
|
||||
finalField = Sequelize.col('videoQuotaUsed')
|
||||
} else {
|
||||
finalField = field
|
||||
}
|
||||
|
||||
const nullPolicy = direction === 'ASC'
|
||||
? 'NULLS FIRST'
|
||||
: 'NULLS LAST'
|
||||
|
||||
// FIXME: typings
|
||||
return [ [ finalField as any, direction, nullPolicy ], [ 'id', 'ASC' ] ]
|
||||
}
|
||||
|
||||
function getPlaylistSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] {
|
||||
const { direction, field } = buildDirectionAndField(value)
|
||||
|
||||
|
@ -260,6 +277,7 @@ export {
|
|||
buildLocalAccountIdsIn,
|
||||
getSort,
|
||||
getCommentSort,
|
||||
getAdminUsersSort,
|
||||
getVideoSort,
|
||||
getBlacklistSort,
|
||||
createSimilarityAttribute,
|
||||
|
|
Loading…
Reference in New Issue