jobs/logs view select and empty state visual improvements

pull/3198/head
Rigel Kent 2020-08-27 17:27:37 +02:00 committed by Rigel Kent
parent cd372e840b
commit 7f0d856169
10 changed files with 106 additions and 52 deletions

View File

@ -1,6 +1,6 @@
<!-- If you have a question, please read the FAQ.md first -->
<!-- If you report a security issue, please refrain from filling an issue and refer to SECURITY.md for the disclosure procedure. -->
<!-- If you report a bug, please fill the form -->
<!-- If you have a question, please read FAQ.md first -->
<!-- If you report a security issue, please refrain from filling an issue, refer to SECURITY.md and follow the disclosure procedure it describes. -->
<!-- If you report a bug, please fill the following form -->
**What happened?**
@ -16,9 +16,9 @@
**Additional information**
* PeerTube version or URL:
* Browser name/version:
* PeerTube version and URL:
* Browser name and version:
* NodeJS version:
* Link to browser console log if useful:
* Link to server log if useful (journalctl or /var/www/peertube/storage/logs/):
* Link to server log if useful (`journalctl` or `/var/www/peertube/storage/logs/`):

View File

@ -20,7 +20,7 @@
<ng-template pTemplate="header">
<tr>
<th style="width: 150px;">Action</th> <!-- column for action buttons -->
<th style="width: 100%;" i18n>Account</th>
<th style="width: calc(100% - 300px);" i18n>Account</th>
<th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
</tr>
</ng-template>

View File

@ -10,45 +10,48 @@
<div class="select-filter-block">
<label for="jobState" i18n>Job state</label>
<div class="peertube-select-container">
<select id="jobState" name="jobState" [(ngModel)]="jobState" (ngModelChange)="onJobStateOrTypeChanged()" class="form-control">
<option *ngFor="let state of jobStates" [value]="state">{{ state }}</option>
</select>
</div>
<ng-select
class="select-job-state"
[(ngModel)]="jobState"
(ngModelChange)="onJobStateOrTypeChanged()"
[clearable]="false"
[searchable]="false"
>
<ng-option *ngFor="let state of jobStates" [value]="state">
<span class="badge" [ngClass]="getJobStateClass(state)">{{ state }}</span>
</ng-option>
</ng-select>
</div>
</div>
<p-table
[value]="jobs" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" dataKey="uniqId"
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" [first]="pagination.start"
[tableStyle]="{'table-layout':'auto'}" (onPage)="onPage($event)" [expandedRowKeys]="expandedRows"
[value]="jobs" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions"
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="uniqId" [first]="pagination.start"
[tableStyle]="{'table-layout':'auto'}" (onPage)="onPage($event)"
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} jobs"
(onPage)="onPage($event)" [expandedRowKeys]="expandedRows"
>
<ng-template pTemplate="header">
<tr>
<th style="width: 40px"></th>
<th style="width: 100%" class="job-id" i18n>ID</th>
<th style="width: calc(100% - 390px)" class="job-id" i18n>ID</th>
<th style="width: 200px" class="job-type" i18n>Type</th>
<th style="width: 150px" class="job-date" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
<th style="width: 150px" class="job-state" i18n>State</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-expanded="expanded" let-job>
<tr>
<td class="expand-cell">
<span class="expander" [pRowToggler]="job" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body">
<td class="expand-cell" [pRowToggler]="job" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body">
<span class="expander">
<i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i>
</span>
</td>
<td class="job-id" [title]="job.id">{{ job.id }}</td>
<td class="job-type">{{ job.type }}</td>
<td class="job-date">{{ job.createdAt | date: 'short' }}</td>
<td class="job-state" *ngIf="job.state === 'delayed'" class="text-muted"><span class="glyphicon glyphicon-repeat"></span> <span i18n>Delayed</span></td>
<td class="job-state" *ngIf="job.state === 'waiting'" class="text-warning"><span class="glyphicon glyphicon-hourglass"></span> <span i18n>Will start soon...</span></td>
<td class="job-state" *ngIf="job.state === 'active'" class="text-warning"><span class="glyphicon glyphicon-cog"></span> <span i18n>Running...</span></td>
<td class="job-state" *ngIf="job.state === 'completed'" class="text-success"><span class="glyphicon glyphicon-ok"></span> <span i18n>Finished</span></td>
<td class="job-state" *ngIf="job.state === 'failed'" class="text-danger"><span class="glyphicon glyphicon-remove"></span> <span i18n>Failed</span></td>
<td class="job-id" [pRowToggler]="job" [title]="job.id">{{ job.id }}</td>
<td class="job-type" [pRowToggler]="job">{{ job.type }}</td>
<td class="job-date" [pRowToggler]="job">{{ job.createdAt | date: 'short' }}</td>
</tr>
</ng-template>
@ -74,5 +77,18 @@
</td>
</tr>
</ng-template>
<ng-template pTemplate="emptymessage">
<tr>
<td colspan="4">
<div class="no-results">
<div class="d-block">
<ng-container *ngIf="jobType === 'all'" i18n>No <span class="badge" [ngClass]="getJobStateClass(jobState)">{{ jobState }}</span> jobs found.</ng-container>
<ng-container *ngIf="jobType !== 'all'" i18n>No <code>{{ jobType }}</code> jobs found that are <span class="badge" [ngClass]="getJobStateClass(jobState)">{{ jobState }}</span>.</ng-container>
</div>
</div>
</td>
</tr>
</ng-template>
</p-table>

View File

@ -1,6 +1,10 @@
@import '_variables';
@import '_mixins';
.select-job-state {
min-width: 120px;
}
.job-id {
max-width: 30vw !important;
}
@ -13,10 +17,6 @@
width: 170px !important;
}
.job-state {
max-width: 60px;
}
.admin-sub-header {
flex-direction: row !important;
justify-content: flex-end;
@ -47,3 +47,7 @@ pre {
.job-error {
color: red;
}
.badge {
@include table-badge;
}

View File

@ -56,6 +56,21 @@ export class JobsComponent extends RestTable implements OnInit {
return 'JobsComponent'
}
getJobStateClass (state: JobStateClient) {
switch (state) {
case 'active':
return 'badge-blue'
case 'completed':
return 'badge-green'
case 'delayed':
return 'badge-brown'
case 'failed':
return 'badge-red'
case 'waiting':
return 'badge-yellow'
}
}
onJobStateOrTypeChanged () {
this.pagination.start = 0

View File

@ -5,17 +5,30 @@
</select>
</div>
<div class="peertube-select-container">
<select [(ngModel)]="startDate" (ngModelChange)="refresh()" class="form-control">
<option *ngFor="let timeChoice of timeChoices" [value]="timeChoice.id">{{ timeChoice.label }}</option>
</select>
</div>
<ng-select
[(ngModel)]="startDate"
(ngModelChange)="refresh()"
[clearable]="false"
[searchable]="false"
>
<ng-option *ngFor="let time of timeChoices" [value]="time.id">
{{ time.label }} ({{ time.id | date: time.dateFormat }} - <span i18n>now</span>)
</ng-option>
</ng-select>
<div class="peertube-select-container" *ngIf="!isAuditLog()">
<select [(ngModel)]="level" (ngModelChange)="refresh()" class="form-control">
<option *ngFor="let levelChoice of levelChoices" [value]="levelChoice.id">{{ levelChoice.label }}</option>
</select>
</div>
<ng-select
[(ngModel)]="level"
(ngModelChange)="refresh()"
[clearable]="false"
[searchable]="false"
>
<ng-option *ngFor="let levelChoice of levelChoices" [value]="levelChoice.id">
<ng-container *ngIf="levelChoice.id === 'debug'"><span style="font-size:80%;color:lightgray;vertical-align:text-top;">&#11044;</span> {{ levelChoice.label }}</ng-container>
<ng-container *ngIf="levelChoice.id === 'info'"><span style="font-size:80%;color:lightskyblue;vertical-align:text-top;">&#11044;</span> {{ levelChoice.label }}</ng-container>
<ng-container *ngIf="levelChoice.id === 'warn'"><span style="font-size:80%;color:orange;vertical-align:text-top;">&#11044;</span> {{ levelChoice.label }}</ng-container>
<ng-container *ngIf="levelChoice.id === 'error'"><span style="font-size:80%;color:red;vertical-align:text-top;">&#11044;</span> {{ levelChoice.label }}</ng-container>
</ng-option>
</ng-select>
<my-button i18n-label label="Refresh" icon="refresh" (click)="refresh()"></my-button>
</div>

View File

@ -52,7 +52,8 @@
}
my-button,
.peertube-select-container {
.peertube-select-container,
ng-select {
margin-left: 10px;
}
}
@ -62,6 +63,7 @@
flex-direction: column;
.peertube-select-container,
ng-select,
my-button {
width: 100% !important;
margin-left: 0px !important;
@ -80,6 +82,7 @@
flex-direction: column;
.peertube-select-container,
ng-select,
my-button {
width: 100% !important;
margin-left: 0px !important;

View File

@ -14,7 +14,7 @@ export class LogsComponent implements OnInit {
loading = false
logs: LogRow[] = []
timeChoices: { id: string, label: string }[] = []
timeChoices: { id: string, label: string, dateFormat: string }[] = []
levelChoices: { id: LogLevel, label: string }[] = []
logTypeChoices: { id: 'audit' | 'standard', label: string }[] = []
@ -76,15 +76,18 @@ export class LogsComponent implements OnInit {
this.timeChoices = [
{
id: lastWeek.toISOString(),
label: $localize`Last week`
label: $localize`Last week`,
dateFormat: 'shortDate'
},
{
id: lastDay.toISOString(),
label: $localize`Last day`
label: $localize`Last day`,
dateFormat: 'short'
},
{
id: lastHour.toISOString(),
label: $localize`Last hour`
label: $localize`Last hour`,
dateFormat: 'mediumTime'
}
]
@ -95,19 +98,19 @@ export class LogsComponent implements OnInit {
this.levelChoices = [
{
id: 'debug',
label: $localize`Debug`
label: $localize`debug`
},
{
id: 'info',
label: $localize`Info`
label: $localize`info`
},
{
id: 'warn',
label: $localize`Warning`
label: $localize`warning`
},
{
id: 'error',
label: $localize`Error`
label: $localize`error`
}
]

View File

@ -25,7 +25,7 @@
<ng-template pTemplate="header">
<tr>
<th style="width: 150px;">Action</th> <!-- column for action buttons -->
<th style="width: 100%;" i18n>Account</th>
<th style="width: calc(100% - 300px);" i18n>Account</th>
<th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
</tr>
</ng-template>

View File

@ -29,7 +29,7 @@
<ng-template pTemplate="header">
<tr>
<th style="width: 150px;">Action</th> <!-- column for action buttons -->
<th style="width: 100%;" i18n>Instance</th>
<th style="width: calc(100% - 300px);" i18n>Instance</th>
<th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
</tr>
</ng-template>