Browse Source

jobs/logs view select and empty state visual improvements

Rigel Kent 3 years ago
parent
commit
7f0d856169

+ 6 - 6
.github/ISSUE_TEMPLATE.md

@@ -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/`):

+ 1 - 1
client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html

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

+ 36 - 20
client/src/app/+admin/system/jobs/jobs.component.html

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

+ 8 - 4
client/src/app/+admin/system/jobs/jobs.component.scss

@@ -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;
+}

+ 15 - 0
client/src/app/+admin/system/jobs/jobs.component.ts

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

+ 24 - 11
client/src/app/+admin/system/logs/logs.component.html

@@ -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>
-
-  <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)]="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>
+
+  <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>

+ 4 - 1
client/src/app/+admin/system/logs/logs.component.scss

@@ -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;

+ 11 - 8
client/src/app/+admin/system/logs/logs.component.ts

@@ -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`
       }
     ]
 

+ 1 - 1
client/src/app/shared/shared-moderation/account-blocklist.component.html

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

+ 1 - 1
client/src/app/shared/shared-moderation/server-blocklist.component.html

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