Design admin data tables

This commit is contained in:
Chocobozzz 2017-12-08 14:34:17 +01:00
parent 04e0fc4888
commit cd83ea1b90
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
18 changed files with 216 additions and 89 deletions

View File

@ -1,18 +1,20 @@
<div class="row">
<div class="content-padding">
<h3>Jobs list</h3>
<p-dataTable
[value]="jobs" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
sortField="createdAt" (onLazyLoad)="loadLazy($event)"
>
<p-column field="id" header="ID"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="handlerName" header="Handler name"></p-column>
<p-column field="handlerInputData" header="Input data"></p-column>
<p-column field="state" header="State"></p-column>
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
<p-column field="updatedAt" header="Updated date"></p-column>
</p-dataTable>
</div>
<div class="admin-sub-header">
<div class="admin-sub-title">Jobs list</div>
</div>
<p-dataTable
[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: '40px' }"></p-column>
<p-column field="category" header="Category" [style]="{ width: '100px' }"></p-column>
<p-column field="handlerName" header="Handler name" [style]="{ width: '150px' }"></p-column>
<p-column header="Input data">
<ng-template pTemplate="body" let-job="rowData">
<pre>{{ job.handlerInputData }}</pre>
</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>

View File

@ -0,0 +1,3 @@
pre {
font-size: 13px;
}

View File

@ -1,22 +1,24 @@
import { Component } from '@angular/core'
import { Component, OnInit } from '@angular/core'
import { NotificationsService } from 'angular2-notifications'
import { SortMeta } from 'primeng/primeng'
import { Job } from '../../../../../../shared/index'
import { RestPagination, RestTable } from '../../../shared'
import { viewportHeight } from '../../../shared/misc/utils'
import { JobService } from '../shared'
import { RestExtractor } from '../../../shared/rest/rest-extractor.service'
@Component({
selector: 'my-jobs-list',
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[] = []
totalRecords = 0
rowsPerPage = 10
rowsPerPage = 20
sort: SortMeta = { field: 'createdAt', order: 1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
scrollHeight = ''
constructor (
private notificationsService: NotificationsService,
@ -26,10 +28,14 @@ export class JobsListComponent extends RestTable {
super()
}
ngOnInit () {
// 270 -> headers + footer...
this.scrollHeight = (viewportHeight() - 380) + 'px'
}
protected loadData () {
this.jobsService
.getJobs(this.pagination, this.sort)
.map(res => this.restExtractor.applyToResultListData(res, this.formatJob.bind(this)))
.subscribe(
resultList => {
this.jobs = resultList.data
@ -39,12 +45,4 @@ export class JobsListComponent extends RestTable {
err => this.notificationsService.error('Error', err.message)
)
}
private formatJob (job: Job) {
const handlerInputData = JSON.stringify(job.handlerInputData)
return Object.assign(job, {
handlerInputData
})
}
}

View File

@ -25,6 +25,13 @@ export class JobService {
return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL, { params })
.map(res => this.restExtractor.convertResultListDateToHuman(res))
.map(res => this.restExtractor.applyToResultListData(res, this.prettyPrintData))
.catch(err => this.restExtractor.handleError(err))
}
private prettyPrintData (obj: Job) {
const handlerInputData = JSON.stringify(obj.handlerInputData, null, 2)
return Object.assign(obj, { handlerInputData })
}
}

View File

@ -1,4 +1,4 @@
<div class="sub-header">
<div class="admin-sub-header">
<div class="admin-sub-title">Users list</div>
<a class="add-button" routerLink="/admin/users/add">
@ -17,16 +17,10 @@
<p-column field="videoQuota" header="Video quota"></p-column>
<p-column field="roleLabel" header="Role"></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">
<a [routerLink]="getRouterUserEditLink(user)" title="Edit this user">
<span class="glyphicon glyphicon-pencil glyphicon-black"></span>
</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>
<my-edit-button [routerLink]="getRouterUserEditLink(user)"></my-edit-button>
<my-delete-button (click)="removeUser(user)"></my-delete-button>
</ng-template>
</p-column>
</p-dataTable>

View File

@ -1,12 +1,3 @@
.sub-header {
display: flex;
align-items: center;
margin-bottom: 30px;
.admin-sub-title {
flex-grow: 1;
}
.add-button {
@include peertube-button-link;
@include orange-button;
@ -18,4 +9,3 @@
background-image: url('../../../../assets/images/admin/add.svg');
}
}
}

View File

@ -30,15 +30,9 @@
</div>
<ng-template [ngIf]="isInSelectionMode() === false">
<span class="action-button action-button-delete" (click)="deleteVideo(video)">
<span class="icon icon-delete-grey"></span>
Delete
</span>
<my-delete-button (click)="deleteVideo(video)"></my-delete-button>
<a class="action-button" [routerLink]="[ '/videos', 'edit', video.uuid ]">
<span class="icon icon-edit"></span>
Edit
</a>
<my-edit-button [routerLink]="[ '/videos', 'edit', video.uuid ]"></my-edit-button>
</ng-template>
</div>
</div>

View File

@ -6,17 +6,7 @@
}
}
.action-button {
@include peertube-button-link;
font-size: 15px;
font-weight: $font-semibold;
color: #585858;
background-color: #E5E5E5;
&:hover {
background-color: #EFEFEF;
}
/deep/ .action-button {
&.action-button-delete {
margin-right: 10px;
@ -32,21 +22,8 @@
}
.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 {
background-image: url('../../../assets/images/account/delete-white.svg');
background-image: url('../../../assets/images/global/delete-white.svg');
}
}
}

View File

@ -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');
}
}
}

View File

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

View File

@ -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 {
}

View File

@ -0,0 +1,4 @@
<a class="action-button" [routerLink]="routerLink">
<span class="icon icon-edit"></span>
Edit
</a>

View File

@ -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 = []
}

View File

@ -13,6 +13,11 @@ function getParameterByName (name: string, url: string) {
return decodeURIComponent(results[2].replace(/\+/g, ' '))
}
function viewportHeight () {
return Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
}
export {
viewportHeight,
getParameterByName
}

View File

@ -12,6 +12,8 @@ import { SharedModule as PrimeSharedModule } from 'primeng/components/common/sha
import { DataTableModule } from 'primeng/components/datatable/datatable'
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 { LoaderComponent } from './misc/loader.component'
import { NumberFormatterPipe } from './misc/number-formatter.pipe'
@ -44,6 +46,8 @@ import { VideoService } from './video/video.service'
LoaderComponent,
VideoThumbnailComponent,
VideoMiniatureComponent,
DeleteButtonComponent,
EditButtonComponent,
NumberFormatterPipe,
FromNowPipe
],
@ -66,6 +70,8 @@ import { VideoService } from './video/video.service'
LoaderComponent,
VideoThumbnailComponent,
VideoMiniatureComponent,
DeleteButtonComponent,
EditButtonComponent,
NumberFormatterPipe,
FromNowPipe

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -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 {
font-size: 20px;
font-weight: bold;
@ -139,11 +149,96 @@ label {
// ngprime data table customizations
p-datatable {
.action-cell {
text-align: center;
font-size: 15px !important;
.glyphicon {
cursor: pointer;
.ui-datatable-scrollable-header {
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;
}
}
}
}
}
}