Improve admin tables

This commit is contained in:
Chocobozzz 2018-02-23 14:36:16 +01:00
parent 621d99f53f
commit ab998f7b6d
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
18 changed files with 269 additions and 139 deletions

View File

@ -5,6 +5,7 @@
### Features ### Features
* Add ability for admin to inject custom JavaScript/CSS * Add ability for admin to inject custom JavaScript/CSS
* Add help tooltip on some fields
### Bug fixes ### Bug fixes

View File

@ -2,7 +2,7 @@ import { NgModule } from '@angular/core'
import { ConfigComponent, EditCustomConfigComponent } from '@app/+admin/config' import { ConfigComponent, EditCustomConfigComponent } from '@app/+admin/config'
import { ConfigService } from '@app/+admin/config/shared/config.service' import { ConfigService } from '@app/+admin/config/shared/config.service'
import { TabsModule } from 'ngx-bootstrap/tabs' import { TabsModule } from 'ngx-bootstrap/tabs'
import { DataTableModule } from 'primeng/components/datatable/datatable' import { TableModule } from 'primeng/table'
import { SharedModule } from '../shared' import { SharedModule } from '../shared'
import { AdminRoutingModule } from './admin-routing.module' import { AdminRoutingModule } from './admin-routing.module'
import { AdminComponent } from './admin.component' import { AdminComponent } from './admin.component'
@ -19,7 +19,7 @@ import { VideoBlacklistComponent, VideoBlacklistListComponent } from './video-bl
imports: [ imports: [
AdminRoutingModule, AdminRoutingModule,
TabsModule.forRoot(), TabsModule.forRoot(),
DataTableModule, TableModule,
SharedModule SharedModule
], ],

View File

@ -1,11 +1,26 @@
<p-dataTable <p-table
[value]="followers" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" [value]="followers" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
sortField="createdAt" (onLazyLoad)="loadLazy($event)" [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)"
> >
<p-column field="id" header="ID" [style]="{ width: '60px' }"></p-column> <ng-template pTemplate="header">
<p-column field="score" header="Score"></p-column> <tr>
<p-column field="follower.name" header="Name"></p-column> <th style="width: 60px">ID</th>
<p-column field="follower.host" header="Host"></p-column> <th>Score</th>
<p-column field="state" header="State"></p-column> <th>Name</th>
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column> <th>Host</th>
</p-dataTable> <th>State</th>
<th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-follow>
<tr>
<td>{{ follow.id }}</td>
<td>{{ follow.score }}</td>
<td>{{ follow.follower.name }}</td>
<td>{{ follow.follower.host }}</td>
<td>{{ follow.state }}</td>
<td>{{ follow.createdAt }}</td>
</tr>
</ng-template>
</p-table>

View File

@ -1,4 +1,4 @@
import { Component } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { NotificationsService } from 'angular2-notifications' import { NotificationsService } from 'angular2-notifications'
import { SortMeta } from 'primeng/primeng' import { SortMeta } from 'primeng/primeng'
@ -11,7 +11,7 @@ import { FollowService } from '../shared'
templateUrl: './followers-list.component.html', templateUrl: './followers-list.component.html',
styleUrls: [ './followers-list.component.scss' ] styleUrls: [ './followers-list.component.scss' ]
}) })
export class FollowersListComponent extends RestTable { export class FollowersListComponent extends RestTable implements OnInit {
followers: AccountFollow[] = [] followers: AccountFollow[] = []
totalRecords = 0 totalRecords = 0
rowsPerPage = 10 rowsPerPage = 10
@ -25,6 +25,10 @@ export class FollowersListComponent extends RestTable {
super() super()
} }
ngOnInit () {
this.loadSort()
}
protected loadData () { protected loadData () {
this.followService.getFollowers(this.pagination, this.sort) this.followService.getFollowers(this.pagination, this.sort)
.subscribe( .subscribe(

View File

@ -1,14 +1,26 @@
<p-dataTable <p-table
[value]="following" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" [value]="following" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
sortField="createdAt" (onLazyLoad)="loadLazy($event)" [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)"
> >
<p-column field="id" header="ID" [style]="{ width: '60px' }"></p-column> <ng-template pTemplate="header">
<p-column field="following.host" header="Host"></p-column> <tr>
<p-column field="state" header="State"></p-column> <th style="width: 60px">ID</th>
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column> <th>Host</th>
<p-column styleClass="action-cell"> <th>State</th>
<ng-template pTemplate="body" let-following="rowData"> <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
<my-delete-button (click)="removeFollowing(following)"></my-delete-button> <th></th>
</ng-template> </tr>
</p-column> </ng-template>
</p-dataTable>
<ng-template pTemplate="body" let-follow>
<tr>
<td>{{ follow.id }}</td>
<td>{{ follow.following.host }}</td>
<td>{{ follow.state }}</td>
<td>{{ follow.createdAt }}</td>
<td class="action-cell">
<my-delete-button (click)="removeFollowing(follow)"></my-delete-button>
</td>
</tr>
</ng-template>
</p-table>

View File

@ -1,4 +1,4 @@
import { Component } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { NotificationsService } from 'angular2-notifications' import { NotificationsService } from 'angular2-notifications'
import { SortMeta } from 'primeng/primeng' import { SortMeta } from 'primeng/primeng'
import { AccountFollow } from '../../../../../../shared/models/actors/follow.model' import { AccountFollow } from '../../../../../../shared/models/actors/follow.model'
@ -10,7 +10,7 @@ import { FollowService } from '../shared'
selector: 'my-followers-list', selector: 'my-followers-list',
templateUrl: './following-list.component.html' templateUrl: './following-list.component.html'
}) })
export class FollowingListComponent extends RestTable { export class FollowingListComponent extends RestTable implements OnInit {
following: AccountFollow[] = [] following: AccountFollow[] = []
totalRecords = 0 totalRecords = 0
rowsPerPage = 10 rowsPerPage = 10
@ -25,6 +25,10 @@ export class FollowingListComponent extends RestTable {
super() super()
} }
ngOnInit () {
this.loadSort()
}
async removeFollowing (follow: AccountFollow) { async removeFollowing (follow: AccountFollow) {
const res = await this.confirmService.confirm(`Do you really want to unfollow ${follow.following.host}?`, 'Unfollow') const res = await this.confirmService.confirm(`Do you really want to unfollow ${follow.following.host}?`, 'Unfollow')
if (res === false) return if (res === false) return

View File

@ -8,20 +8,42 @@
</div> </div>
</div> </div>
<p-table
[value]="jobs" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" dataKey="id"
<p-dataTable sortField="createdAt" (onLazyLoad)="loadLazy($event)"
[value]="jobs" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
sortField="createdAt" (onLazyLoad)="loadLazy($event)" [scrollable]="true" [virtualScroll]="true" [scrollHeight]="scrollHeight"
> >
<p-column field="id" header="ID" [style]="{ width: '60px' }"></p-column> <ng-template pTemplate="header">
<p-column field="type" header="Type" [style]="{ width: '210px' }"></p-column> <tr>
<p-column field="state" header="State" [style]="{ width: '130px' }"></p-column> <th style="width: 27px"></th>
<p-column header="Payload"> <th style="width: 60px">ID</th>
<ng-template pTemplate="body" let-job="rowData"> <th style="width: 210px">Type</th>
<pre>{{ job.data }}</pre> <th style="width: 130px">State</th>
</ng-template> <th style="width: 250px" pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
</p-column> <th style="width: 250px">Updated</th>
<p-column field="createdAt" header="Created date" [sortable]="true" [style]="{ width: '250px' }"></p-column> </tr>
<p-column field="updatedAt" header="Updated date" [style]="{ width: '250px' }"></p-column> </ng-template>
</p-dataTable>
<ng-template pTemplate="body" let-expanded="expanded" let-job>
<tr>
<td>
<span class="expander" [pRowToggler]="job">
<i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i>
</span>
</td>
<td>{{ job.id }}</td>
<td>{{ job.type }}</td>
<td>{{ job.state }}</td>
<td>{{ job.createdAt }}</td>
<td>{{ job.updatedAt }}</td>
</tr>
</ng-template>
<ng-template pTemplate="rowexpansion" let-job>
<tr>
<td colspan="6">
<pre>{{ job.data }}</pre>
</td>
</tr>
</ng-template>
</p-table>

View File

@ -14,11 +14,13 @@ import { RestExtractor } from '../../../shared/rest/rest-extractor.service'
styleUrls: [ './jobs-list.component.scss' ] styleUrls: [ './jobs-list.component.scss' ]
}) })
export class JobsListComponent extends RestTable implements OnInit { export class JobsListComponent extends RestTable implements OnInit {
private static JOB_STATE_LOCAL_STORAGE_STATE = 'jobs-list-state'
jobState: JobState = 'inactive' jobState: JobState = 'inactive'
jobStates: JobState[] = [ 'active', 'complete', 'failed', 'inactive', 'delayed' ] jobStates: JobState[] = [ 'active', 'complete', 'failed', 'inactive', 'delayed' ]
jobs: Job[] = [] jobs: Job[] = []
totalRecords = 0 totalRecords: number
rowsPerPage = 20 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 }
scrollHeight = '' scrollHeight = ''
@ -32,12 +34,16 @@ export class JobsListComponent extends RestTable implements OnInit {
} }
ngOnInit () { ngOnInit () {
// 270 -> headers + footer... // 380 -> headers + footer...
this.scrollHeight = (viewportHeight() - 380) + 'px' this.scrollHeight = (viewportHeight() - 380) + 'px'
this.loadJobState()
this.loadSort()
} }
onJobStateChanged () { onJobStateChanged () {
this.loadData() this.loadData()
this.saveJobState()
} }
protected loadData () { protected loadData () {
@ -52,4 +58,14 @@ export class JobsListComponent extends RestTable implements OnInit {
err => this.notificationsService.error('Error', err.message) err => this.notificationsService.error('Error', err.message)
) )
} }
private loadJobState () {
const result = localStorage.getItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE)
if (result) this.jobState = result as JobState
}
private saveJobState () {
localStorage.setItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE, this.jobState)
}
} }

View File

@ -7,20 +7,32 @@
</a> </a>
</div> </div>
<p-dataTable <p-table
[value]="users" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" [value]="users" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
sortField="id" (onLazyLoad)="loadLazy($event)" [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)"
> >
<p-column field="id" header="ID" [sortable]="true" [style]="{ width: '60px' }"></p-column> <ng-template pTemplate="header">
<p-column field="username" header="Username" [sortable]="true"></p-column> <tr>
<p-column field="email" header="Email"></p-column> <th pSortableColumn="username">Username <p-sortIcon field="username"></p-sortIcon></th>
<p-column field="videoQuota" header="Video quota"></p-column> <th>Email</th>
<p-column field="roleLabel" header="Role"></p-column> <th>Video quota</th>
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column> <th>Role</th>
<p-column styleClass="action-cell"> <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
<ng-template pTemplate="body" let-user="rowData"> <th></th>
<my-edit-button [routerLink]="getRouterUserEditLink(user)"></my-edit-button> </tr>
<my-delete-button (click)="removeUser(user)"></my-delete-button> </ng-template>
</ng-template>
</p-column> <ng-template pTemplate="body" let-user>
</p-dataTable> <tr>
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
<td>{{ user.videoQuota }}</td>
<td>{{ user.roleLabel }}</td>
<td>{{ user.createdAt }}</td>
<td class="action-cell">
<my-edit-button [routerLink]="getRouterUserEditLink(user)"></my-edit-button>
<my-delete-button (click)="removeUser(user)"></my-delete-button>
</td>
</tr>
</ng-template>
</p-table>

View File

@ -1,4 +1,4 @@
import { Component } from '@angular/core' import { Component, OnInit } 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'
@ -12,11 +12,11 @@ import { UserService } from '../shared'
templateUrl: './user-list.component.html', templateUrl: './user-list.component.html',
styleUrls: [ './user-list.component.scss' ] styleUrls: [ './user-list.component.scss' ]
}) })
export class UserListComponent extends RestTable { export class UserListComponent extends RestTable implements OnInit {
users: User[] = [] users: User[] = []
totalRecords = 0 totalRecords = 0
rowsPerPage = 10 rowsPerPage = 10
sort: SortMeta = { field: 'id', order: 1 } sort: SortMeta = { field: 'createdAt', order: 1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 } pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
constructor ( constructor (
@ -27,6 +27,10 @@ export class UserListComponent extends RestTable {
super() super()
} }
ngOnInit () {
this.loadSort()
}
async removeUser (user: User) { async removeUser (user: User) {
if (user.username === 'root') { if (user.username === 'root') {
this.notificationsService.error('Error', 'You cannot delete root.') this.notificationsService.error('Error', 'You cannot delete root.')

View File

@ -2,18 +2,27 @@
<div class="admin-sub-title">Video abuses list</div> <div class="admin-sub-title">Video abuses list</div>
</div> </div>
<p-dataTable <p-table
[value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" [value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
sortField="id" (onLazyLoad)="loadLazy($event)" [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)"
> >
<p-column field="id" header="ID" [sortable]="true" [style]="{ width: '60px' }"></p-column> <ng-template pTemplate="header">
<p-column field="reason" header="Reason"></p-column> <tr>
<p-column field="reporterServerHost" header="Reporter server host"></p-column> <th>Reason</th>
<p-column field="reporterUsername" header="Reporter username"></p-column> <th>Reporter</th>
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column> <th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
<p-column header="Video"> <th>Video</th>
<ng-template pTemplate="body" let-videoAbuse="rowData"> </tr>
<a [routerLink]="getRouterVideoLink(videoAbuse.videoId)" title="Go to the video">{{ videoAbuse.videoName }}</a> </ng-template>
</ng-template>
</p-column> <ng-template pTemplate="body" let-videoAbuse>
</p-dataTable> <tr>
<td>{{ videoAbuse.reason }}</td>
<td>{{ videoAbuse.reporterServerHost + '@' + videoAbuse.reporterUsername }}</td>
<td>{{ videoAbuse.createdAt }}</td>
<td>
<a [routerLink]="getRouterVideoLink(videoAbuse.videoUUID)" title="Go to the video">{{ videoAbuse.videoName }}</a>
</td>
</tr>
</ng-template>
</p-table>

View File

@ -15,7 +15,7 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
videoAbuses: VideoAbuse[] = [] videoAbuses: VideoAbuse[] = []
totalRecords = 0 totalRecords = 0
rowsPerPage = 10 rowsPerPage = 10
sort: SortMeta = { field: 'id', order: 1 } sort: SortMeta = { field: 'createdAt', order: 1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 } pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
constructor ( constructor (
@ -26,11 +26,11 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
} }
ngOnInit () { ngOnInit () {
this.loadData() this.loadSort()
} }
getRouterVideoLink (videoId: number) { getRouterVideoLink (videoUUID: string) {
return [ '/videos', videoId ] return [ '/videos', videoUUID ]
} }
protected loadData () { protected loadData () {

View File

@ -1,23 +1,35 @@
<div class="row"> <div class="admin-sub-header">
<div class="content-padding"> <div class="admin-sub-title">Blacklisted videos</div>
<h3>Blacklisted videos</h3>
<p-dataTable
[value]="blacklist" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
sortField="id" (onLazyLoad)="loadLazy($event)"
>
<p-column field="id" header="ID" [sortable]="true"></p-column>
<p-column field="name" header="Name" [sortable]="true"></p-column>
<p-column field="description" header="Description"></p-column>
<p-column field="views" header="Views" [sortable]="true"></p-column>
<p-column field="nsfw" header="NSFW"></p-column>
<p-column field="uuid" header="UUID" [sortable]="true"></p-column>
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
<p-column header="Delete" styleClass="action-cell">
<ng-template pTemplate="body" let-entry="rowData">
<my-delete-button (click)="removeVideoFromBlacklist(entry)"></my-delete-button>
</ng-template>
</p-column>
</p-dataTable>
</div>
</div> </div>
<p-table
[value]="blacklist" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)"
>
<ng-template pTemplate="header">
<tr>
<th pSortableColumn="name">Name <p-sortIcon field="name"></p-sortIcon></th>
<th>Description</th>
<th pSortableColumn="views">Views <p-sortIcon field="views"></p-sortIcon></th>
<th>NSFW</th>
<th>UUID</th>
<th pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
<th></th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-videoBlacklist>
<tr>
<td>{{ videoBlacklist.name }}</td>
<td>{{ videoBlacklist.description }}</td>
<td>{{ videoBlacklist.views }}</td>
<td>{{ videoBlacklist.nsfw }}</td>
<td>{{ videoBlacklist.uuid }}</td>
<td>{{ videoBlacklist.createdAt }}</td>
<td class="action-cell">
<my-delete-button label="Unblacklist" (click)="removeVideoFromBlacklist(videoBlacklist)"></my-delete-button>
</td>
</tr>
</ng-template>
</p-table>

View File

@ -16,7 +16,7 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit {
blacklist: BlacklistedVideo[] = [] blacklist: BlacklistedVideo[] = []
totalRecords = 0 totalRecords = 0
rowsPerPage = 10 rowsPerPage = 10
sort: SortMeta = { field: 'id', order: 1 } sort: SortMeta = { field: 'createdAt', order: 1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 } pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
constructor ( constructor (
@ -28,13 +28,13 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit {
} }
ngOnInit () { ngOnInit () {
this.loadData() this.loadSort()
} }
async removeVideoFromBlacklist (entry: BlacklistedVideo) { async removeVideoFromBlacklist (entry: BlacklistedVideo) {
const confirmMessage = 'Do you really want to remove this video from the blacklist ? It will be available again in the video list.' const confirmMessage = 'Do you really want to remove this video from the blacklist ? It will be available again in the videos list.'
const res = await this.confirmService.confirm(confirmMessage, 'Remove') const res = await this.confirmService.confirm(confirmMessage, 'Unblacklist')
if (res === false) return if (res === false) return
this.videoBlacklistService.removeVideoFromBlacklist(entry.videoId).subscribe( this.videoBlacklistService.removeVideoFromBlacklist(entry.videoId).subscribe(

View File

@ -1,4 +1,4 @@
<span class="action-button action-button-delete" > <span class="action-button action-button-delete" >
<span class="icon icon-delete-grey"></span> <span class="icon icon-delete-grey"></span>
Delete {{ label }}
</span> </span>

View File

@ -1,4 +1,4 @@
import { Component } from '@angular/core' import { Component, Input } from '@angular/core'
@Component({ @Component({
selector: 'my-delete-button', selector: 'my-delete-button',
@ -7,4 +7,5 @@ import { Component } from '@angular/core'
}) })
export class DeleteButtonComponent { export class DeleteButtonComponent {
@Input() label = 'Delete'
} }

View File

@ -4,13 +4,28 @@ import { SortMeta } from 'primeng/components/common/sortmeta'
import { RestPagination } from './rest-pagination' import { RestPagination } from './rest-pagination'
export abstract class RestTable { export abstract class RestTable {
abstract totalRecords: number abstract totalRecords: number
abstract rowsPerPage: number abstract rowsPerPage: number
abstract sort: SortMeta abstract sort: SortMeta
abstract pagination: RestPagination abstract pagination: RestPagination
private sortLocalStorageKey = 'rest-table-sort-' + this.constructor.name
protected abstract loadData (): void protected abstract loadData (): void
loadSort () {
const result = localStorage.getItem(this.sortLocalStorageKey)
if (result) {
try {
this.sort = JSON.parse(result)
} catch (err) {
console.error('Cannot load sort of local storage key ' + this.sortLocalStorageKey, err)
}
}
}
loadLazy (event: LazyLoadEvent) { loadLazy (event: LazyLoadEvent) {
this.sort = { this.sort = {
order: event.sortOrder, order: event.sortOrder,
@ -23,6 +38,11 @@ export abstract class RestTable {
} }
this.loadData() this.loadData()
this.saveSort()
}
saveSort () {
localStorage.setItem(this.sortLocalStorageKey, JSON.stringify(this.sort))
} }
} }

View File

@ -131,21 +131,9 @@ label {
} }
// ngprime data table customizations // ngprime data table customizations
p-datatable { p-table {
font-size: 15px !important; font-size: 15px !important;
.ui-datatable-scrollable-header {
background-color: #fff !important;
}
.ui-widget-content {
border: none !important;
}
.ui-datatable-virtual-table {
border-top: none !important;
}
td { td {
border: 1px solid #E5E5E5 !important; border: 1px solid #E5E5E5 !important;
padding-left: 15px !important; padding-left: 15px !important;
@ -157,23 +145,33 @@ p-datatable {
tr { tr {
background-color: #fff !important; background-color: #fff !important;
height: 46px; height: 46px;
}
&:hover { .ui-table-tbody {
background-color: #f0f0f0 !important; tr {
} &:hover {
background-color: #f0f0f0 !important;
}
&:not(:hover) { &:not(:hover) {
.action-cell * { .action-cell * {
display: none !important; display: none !important;
}
}
&:first-child td {
border-top: none !important;
}
&:last-child td {
border-bottom: none !important;
} }
} }
&:first-child td { .expander {
border-top: none !important; cursor: pointer;
} position: relative;
top: 1px;
&:last-child td {
border-bottom: none !important;
} }
} }
@ -195,7 +193,7 @@ p-datatable {
} }
} }
&.ui-state-active { &.ui-state-highlight {
background-color: #fff !important; background-color: #fff !important;
.fa { .fa {