Design admin data tables
This commit is contained in:
parent
04e0fc4888
commit
cd83ea1b90
|
@ -1,18 +1,20 @@
|
||||||
<div class="row">
|
<div class="admin-sub-header">
|
||||||
<div class="content-padding">
|
<div class="admin-sub-title">Jobs list</div>
|
||||||
<h3>Jobs list</h3>
|
</div>
|
||||||
|
|
||||||
<p-dataTable
|
<p-dataTable
|
||||||
[value]="jobs" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
|
[value]="jobs" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
|
||||||
sortField="createdAt" (onLazyLoad)="loadLazy($event)"
|
sortField="createdAt" (onLazyLoad)="loadLazy($event)" [scrollable]="true" [virtualScroll]="true" [scrollHeight]="scrollHeight"
|
||||||
>
|
>
|
||||||
<p-column field="id" header="ID"></p-column>
|
<p-column field="id" header="ID" [style]="{ width: '40px' }"></p-column>
|
||||||
<p-column field="category" header="Category"></p-column>
|
<p-column field="category" header="Category" [style]="{ width: '100px' }"></p-column>
|
||||||
<p-column field="handlerName" header="Handler name"></p-column>
|
<p-column field="handlerName" header="Handler name" [style]="{ width: '150px' }"></p-column>
|
||||||
<p-column field="handlerInputData" header="Input data"></p-column>
|
<p-column header="Input data">
|
||||||
<p-column field="state" header="State"></p-column>
|
<ng-template pTemplate="body" let-job="rowData">
|
||||||
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
|
<pre>{{ job.handlerInputData }}</pre>
|
||||||
<p-column field="updatedAt" header="Updated date"></p-column>
|
</ng-template>
|
||||||
|
</p-column>
|
||||||
|
<p-column field="state" header="State" [style]="{ width: '100px' }"></p-column>
|
||||||
|
<p-column field="createdAt" header="Created date" [sortable]="true" [style]="{ width: '250px' }"></p-column>
|
||||||
|
<p-column field="updatedAt" header="Updated date" [style]="{ width: '250px' }"></p-column>
|
||||||
</p-dataTable>
|
</p-dataTable>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
pre {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
|
@ -1,22 +1,24 @@
|
||||||
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 { Job } from '../../../../../../shared/index'
|
import { Job } from '../../../../../../shared/index'
|
||||||
import { RestPagination, RestTable } from '../../../shared'
|
import { RestPagination, RestTable } from '../../../shared'
|
||||||
|
import { viewportHeight } from '../../../shared/misc/utils'
|
||||||
import { JobService } from '../shared'
|
import { JobService } from '../shared'
|
||||||
import { RestExtractor } from '../../../shared/rest/rest-extractor.service'
|
import { RestExtractor } from '../../../shared/rest/rest-extractor.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-jobs-list',
|
selector: 'my-jobs-list',
|
||||||
templateUrl: './jobs-list.component.html',
|
templateUrl: './jobs-list.component.html',
|
||||||
styleUrls: [ ]
|
styleUrls: [ './jobs-list.component.scss' ]
|
||||||
})
|
})
|
||||||
export class JobsListComponent extends RestTable {
|
export class JobsListComponent extends RestTable implements OnInit {
|
||||||
jobs: Job[] = []
|
jobs: Job[] = []
|
||||||
totalRecords = 0
|
totalRecords = 0
|
||||||
rowsPerPage = 10
|
rowsPerPage = 20
|
||||||
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 = ''
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
|
@ -26,10 +28,14 @@ export class JobsListComponent extends RestTable {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
// 270 -> headers + footer...
|
||||||
|
this.scrollHeight = (viewportHeight() - 380) + 'px'
|
||||||
|
}
|
||||||
|
|
||||||
protected loadData () {
|
protected loadData () {
|
||||||
this.jobsService
|
this.jobsService
|
||||||
.getJobs(this.pagination, this.sort)
|
.getJobs(this.pagination, this.sort)
|
||||||
.map(res => this.restExtractor.applyToResultListData(res, this.formatJob.bind(this)))
|
|
||||||
.subscribe(
|
.subscribe(
|
||||||
resultList => {
|
resultList => {
|
||||||
this.jobs = resultList.data
|
this.jobs = resultList.data
|
||||||
|
@ -39,12 +45,4 @@ export class JobsListComponent extends RestTable {
|
||||||
err => this.notificationsService.error('Error', err.message)
|
err => this.notificationsService.error('Error', err.message)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private formatJob (job: Job) {
|
|
||||||
const handlerInputData = JSON.stringify(job.handlerInputData)
|
|
||||||
|
|
||||||
return Object.assign(job, {
|
|
||||||
handlerInputData
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,13 @@ export class JobService {
|
||||||
|
|
||||||
return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL, { params })
|
return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL, { params })
|
||||||
.map(res => this.restExtractor.convertResultListDateToHuman(res))
|
.map(res => this.restExtractor.convertResultListDateToHuman(res))
|
||||||
|
.map(res => this.restExtractor.applyToResultListData(res, this.prettyPrintData))
|
||||||
.catch(err => this.restExtractor.handleError(err))
|
.catch(err => this.restExtractor.handleError(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private prettyPrintData (obj: Job) {
|
||||||
|
const handlerInputData = JSON.stringify(obj.handlerInputData, null, 2)
|
||||||
|
|
||||||
|
return Object.assign(obj, { handlerInputData })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="sub-header">
|
<div class="admin-sub-header">
|
||||||
<div class="admin-sub-title">Users list</div>
|
<div class="admin-sub-title">Users list</div>
|
||||||
|
|
||||||
<a class="add-button" routerLink="/admin/users/add">
|
<a class="add-button" routerLink="/admin/users/add">
|
||||||
|
@ -17,16 +17,10 @@
|
||||||
<p-column field="videoQuota" header="Video quota"></p-column>
|
<p-column field="videoQuota" header="Video quota"></p-column>
|
||||||
<p-column field="roleLabel" header="Role"></p-column>
|
<p-column field="roleLabel" header="Role"></p-column>
|
||||||
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
|
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
|
||||||
<p-column header="Edit" styleClass="action-cell">
|
<p-column styleClass="action-cell">
|
||||||
<ng-template pTemplate="body" let-user="rowData">
|
<ng-template pTemplate="body" let-user="rowData">
|
||||||
<a [routerLink]="getRouterUserEditLink(user)" title="Edit this user">
|
<my-edit-button [routerLink]="getRouterUserEditLink(user)"></my-edit-button>
|
||||||
<span class="glyphicon glyphicon-pencil glyphicon-black"></span>
|
<my-delete-button (click)="removeUser(user)"></my-delete-button>
|
||||||
</a>
|
|
||||||
</ng-template>
|
|
||||||
</p-column>
|
|
||||||
<p-column header="Delete" styleClass="action-cell">
|
|
||||||
<ng-template pTemplate="body" let-user="rowData">
|
|
||||||
<span (click)="removeUser(user)" class="glyphicon glyphicon-remove glyphicon-black" title="Remove this user"></span>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-column>
|
</p-column>
|
||||||
</p-dataTable>
|
</p-dataTable>
|
||||||
|
|
|
@ -1,12 +1,3 @@
|
||||||
.sub-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
|
|
||||||
.admin-sub-title {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-button {
|
.add-button {
|
||||||
@include peertube-button-link;
|
@include peertube-button-link;
|
||||||
@include orange-button;
|
@include orange-button;
|
||||||
|
@ -18,4 +9,3 @@
|
||||||
background-image: url('../../../../assets/images/admin/add.svg');
|
background-image: url('../../../../assets/images/admin/add.svg');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -30,15 +30,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-template [ngIf]="isInSelectionMode() === false">
|
<ng-template [ngIf]="isInSelectionMode() === false">
|
||||||
<span class="action-button action-button-delete" (click)="deleteVideo(video)">
|
<my-delete-button (click)="deleteVideo(video)"></my-delete-button>
|
||||||
<span class="icon icon-delete-grey"></span>
|
|
||||||
Delete
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<a class="action-button" [routerLink]="[ '/videos', 'edit', video.uuid ]">
|
<my-edit-button [routerLink]="[ '/videos', 'edit', video.uuid ]"></my-edit-button>
|
||||||
<span class="icon icon-edit"></span>
|
|
||||||
Edit
|
|
||||||
</a>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,17 +6,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-button {
|
/deep/ .action-button {
|
||||||
@include peertube-button-link;
|
|
||||||
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: $font-semibold;
|
|
||||||
color: #585858;
|
|
||||||
background-color: #E5E5E5;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #EFEFEF;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.action-button-delete {
|
&.action-button-delete {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
@ -32,21 +22,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
@include icon(21px);
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
top: -2px;
|
|
||||||
|
|
||||||
&.icon-edit {
|
|
||||||
background-image: url('../../../assets/images/global/edit.svg');
|
|
||||||
}
|
|
||||||
|
|
||||||
&.icon-delete-grey {
|
|
||||||
background-image: url('../../../assets/images/account/delete-grey.svg');
|
|
||||||
}
|
|
||||||
|
|
||||||
&.icon-delete-white {
|
&.icon-delete-white {
|
||||||
background-image: url('../../../assets/images/account/delete-white.svg');
|
background-image: url('../../../assets/images/global/delete-white.svg');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
.action-button {
|
||||||
|
@include peertube-button-link;
|
||||||
|
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: $font-semibold;
|
||||||
|
color: #585858;
|
||||||
|
background-color: #E5E5E5;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #EFEFEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
@include icon(21px);
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
top: -2px;
|
||||||
|
|
||||||
|
&.icon-edit {
|
||||||
|
background-image: url('../../../assets/images/global/edit.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-delete-grey {
|
||||||
|
background-image: url('../../../assets/images/global/delete-grey.svg');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<span class="action-button action-button-delete" >
|
||||||
|
<span class="icon icon-delete-grey"></span>
|
||||||
|
Delete
|
||||||
|
</span>
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { Component } from '@angular/core'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-delete-button',
|
||||||
|
styleUrls: [ './button.component.scss' ],
|
||||||
|
templateUrl: './delete-button.component.html'
|
||||||
|
})
|
||||||
|
|
||||||
|
export class DeleteButtonComponent {
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<a class="action-button" [routerLink]="routerLink">
|
||||||
|
<span class="icon icon-edit"></span>
|
||||||
|
Edit
|
||||||
|
</a>
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { Component, Input } from '@angular/core'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-edit-button',
|
||||||
|
styleUrls: [ './button.component.scss' ],
|
||||||
|
templateUrl: './edit-button.component.html'
|
||||||
|
})
|
||||||
|
|
||||||
|
export class EditButtonComponent {
|
||||||
|
@Input() routerLink = []
|
||||||
|
}
|
|
@ -13,6 +13,11 @@ function getParameterByName (name: string, url: string) {
|
||||||
return decodeURIComponent(results[2].replace(/\+/g, ' '))
|
return decodeURIComponent(results[2].replace(/\+/g, ' '))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function viewportHeight () {
|
||||||
|
return Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
viewportHeight,
|
||||||
getParameterByName
|
getParameterByName
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ import { SharedModule as PrimeSharedModule } from 'primeng/components/common/sha
|
||||||
import { DataTableModule } from 'primeng/components/datatable/datatable'
|
import { DataTableModule } from 'primeng/components/datatable/datatable'
|
||||||
|
|
||||||
import { AUTH_INTERCEPTOR_PROVIDER } from './auth'
|
import { AUTH_INTERCEPTOR_PROVIDER } from './auth'
|
||||||
|
import { DeleteButtonComponent } from './misc/delete-button.component'
|
||||||
|
import { EditButtonComponent } from './misc/edit-button.component'
|
||||||
import { FromNowPipe } from './misc/from-now.pipe'
|
import { FromNowPipe } from './misc/from-now.pipe'
|
||||||
import { LoaderComponent } from './misc/loader.component'
|
import { LoaderComponent } from './misc/loader.component'
|
||||||
import { NumberFormatterPipe } from './misc/number-formatter.pipe'
|
import { NumberFormatterPipe } from './misc/number-formatter.pipe'
|
||||||
|
@ -44,6 +46,8 @@ import { VideoService } from './video/video.service'
|
||||||
LoaderComponent,
|
LoaderComponent,
|
||||||
VideoThumbnailComponent,
|
VideoThumbnailComponent,
|
||||||
VideoMiniatureComponent,
|
VideoMiniatureComponent,
|
||||||
|
DeleteButtonComponent,
|
||||||
|
EditButtonComponent,
|
||||||
NumberFormatterPipe,
|
NumberFormatterPipe,
|
||||||
FromNowPipe
|
FromNowPipe
|
||||||
],
|
],
|
||||||
|
@ -66,6 +70,8 @@ import { VideoService } from './video/video.service'
|
||||||
LoaderComponent,
|
LoaderComponent,
|
||||||
VideoThumbnailComponent,
|
VideoThumbnailComponent,
|
||||||
VideoMiniatureComponent,
|
VideoMiniatureComponent,
|
||||||
|
DeleteButtonComponent,
|
||||||
|
EditButtonComponent,
|
||||||
|
|
||||||
NumberFormatterPipe,
|
NumberFormatterPipe,
|
||||||
FromNowPipe
|
FromNowPipe
|
||||||
|
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
@ -92,6 +92,16 @@ label {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-sub-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
|
||||||
|
.admin-sub-title {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.admin-sub-title {
|
.admin-sub-title {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -139,11 +149,96 @@ label {
|
||||||
|
|
||||||
// ngprime data table customizations
|
// ngprime data table customizations
|
||||||
p-datatable {
|
p-datatable {
|
||||||
.action-cell {
|
font-size: 15px !important;
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
.glyphicon {
|
.ui-datatable-scrollable-header {
|
||||||
cursor: pointer;
|
background-color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-widget-content {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-datatable-virtual-table {
|
||||||
|
border-top: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
border: 1px solid #E5E5E5 !important;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
background-color: #fff !important;
|
||||||
|
height: 46px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #f0f0f0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:hover) {
|
||||||
|
.action-cell * {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child td {
|
||||||
|
border-top: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
border: none !important;
|
||||||
|
border-bottom: 1px solid #f0f0f0 !important;
|
||||||
|
text-align: left !important;
|
||||||
|
padding: 5px 0 5px 15px !important;
|
||||||
|
font-weight: $font-semibold !important;
|
||||||
|
color: #000 !important;
|
||||||
|
|
||||||
|
&.ui-state-active, &.ui-sortable-column:hover {
|
||||||
|
background-color: #f0f0f0 !important;
|
||||||
|
border: 1px solid #f0f0f0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-cell {
|
||||||
|
width: 250px !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
p-paginator {
|
||||||
|
overflow: hidden;
|
||||||
|
display: block;
|
||||||
|
padding-top: 2px;
|
||||||
|
border: 1px solid #f0f0f0 !important;
|
||||||
|
border-top: none !important;
|
||||||
|
|
||||||
|
.ui-paginator-bottom {
|
||||||
|
position: relative;
|
||||||
|
border: none !important;
|
||||||
|
border-top: 1px solid #f0f0f0 !important;
|
||||||
|
box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.16);
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #000 !important;
|
||||||
|
font-weight: $font-semibold !important;
|
||||||
|
margin-right: 20px !important;
|
||||||
|
outline: 0 !important;
|
||||||
|
border-radius: 3px !important;
|
||||||
|
padding: 5px 2px !important;
|
||||||
|
|
||||||
|
&.ui-state-active {
|
||||||
|
&, &:hover, &:active, &:focus {
|
||||||
|
color: #fff !important;
|
||||||
|
background-color: $orange-color !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue