1
0
Fork 0

Improve runner jobs UX

Use badges with same colors for type/runner
Adds processed/finished information
This commit is contained in:
Chocobozzz 2024-03-25 11:22:05 +01:00
parent be19d9be34
commit d4a09f9ce2
No known key found for this signature in database
GPG key ID: 583A612D890159BE
7 changed files with 97 additions and 22 deletions

View file

@ -53,7 +53,8 @@
<th scope="col" style="width: 200px" class="job-priority" i18n>Priority <small>(1 = highest priority)</small></th>
<th scope="col" style="width: 200px" class="job-state" i18n *ngIf="jobState === 'all'">State</th>
<th scope="col" style="width: 100px" class="job-progress" i18n *ngIf="hasGlobalProgress()">Progress</th>
<th scope="col" style="width: 150px" class="job-date" i18n [ngbTooltip]="sortTooltip" container="body" pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
<th scope="col" style="width: 200px" class="job-date" i18n [ngbTooltip]="sortTooltip" container="body" pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
<th scope="col" style="width: 230px;" i18n>Processed/Finished</th>
</tr>
</ng-template>
@ -64,11 +65,15 @@
</td>
<td class="job-id c-hand" [pRowToggler]="job" [title]="job.id">{{ job.id }}</td>
<td class="job-type c-hand" [pRowToggler]="job">{{ job.type }}</td>
<td class="job-type c-hand" [pRowToggler]="job">
<span class="pt-badge ellipsis" [ngClass]="getRandomJobTypeBadge(job.type)">{{ job.type }}</span>
</td>
<td class="job-priority c-hand" [pRowToggler]="job">{{ job.priority }}</td>
<td class="job-state c-hand" [pRowToggler]="job" *ngIf="jobState === 'all'">
<span class="pt-badge" [ngClass]="getJobStateClass(job.state)">{{ job.state }}</span>
<span class="pt-badge ellipsis" [ngClass]="getJobStateClass(job.state)">{{ job.state }}</span>
</td>
<td *ngIf="hasGlobalProgress()" class="job-progress c-hand" [pRowToggler]="job">
@ -76,6 +81,11 @@
</td>
<td class="job-date c-hand" [pRowToggler]="job">{{ job.createdAt }}</td>
<td class="fs-7">
<div>{{ job.processedOn }}</div>
<div>{{ job.finishedOn}}</div>
</td>
</tr>
</ng-template>

View file

@ -27,7 +27,7 @@
}
.job-date {
width: 170px !important;
width: 200px !important;
}
}

View file

@ -144,6 +144,10 @@ export class JobsComponent extends RestTable implements OnInit {
this.reloadData()
}
getRandomJobTypeBadge (type: string) {
return this.getRandomBadge('type', type)
}
protected reloadDataInternal () {
let jobState = this.jobState as JobState
if (this.jobState === 'all') jobState = null

View file

@ -30,11 +30,12 @@
</th>
<th scope="col" i18n>UUID</th>
<th scope="col" i18n>Type</th>
<th scope="col" i18n [ngbTooltip]="sortTooltip" container="body" pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th>
<th scope="col" style="width: 150px" i18n [ngbTooltip]="sortTooltip" container="body" pSortableColumn="state">State <p-sortIcon field="state"></p-sortIcon></th>
<th scope="col" style="width: 100px" i18n [ngbTooltip]="sortTooltip" container="body" pSortableColumn="priority">Priority <p-sortIcon field="priority"></p-sortIcon></th>
<th scope="col" style="width: 100px" i18n [ngbTooltip]="sortTooltip" container="body" pSortableColumn="progress">Progress <p-sortIcon field="progress"></p-sortIcon></th>
<th scope="col" i18n>Runner</th>
<th scope="col" style="width: 100px;" i18n>Runner</th>
<th scope="col" style="width: 200px;" i18n [ngbTooltip]="sortTooltip" container="body" pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
<th scope="col" style="width: 230px;" i18n>Processed/Finished</th>
</tr>
</ng-template>
@ -75,18 +76,32 @@
</td>
<td>{{ runnerJob.uuid }}</td>
<td>{{ runnerJob.type }}</td>
<td>
<span class="pt-badge" [ngClass]="getStateBadgeColor(runnerJob)">{{ runnerJob.state.label }}</span>
<span class="pt-badge ellipsis" [ngClass]="getRandomRunnerTypeBadge(runnerJob.type)">{{ runnerJob.type }}</span>
</td>
<td>
<span class="pt-badge ellipsis" [ngClass]="getStateBadgeColor(runnerJob)">{{ runnerJob.state.label }}</span>
</td>
<td>{{ runnerJob.priority }}</td>
<td>
<ng-container *ngIf="runnerJob.progress">{{ runnerJob.progress }}%</ng-container>
</td>
<td>{{ runnerJob.runner?.name }}</td>
<td>
<div *ngIf="runnerJob.runner?.name" class="pt-badge" [ngClass]="getRandomRunnerNameBadge(runnerJob.runner.name)">
{{ runnerJob.runner.name }}
</div>
</td>
<td>{{ runnerJob.createdAt }}</td>
<td class="fs-7">
<div>{{ runnerJob.startedAt }}</div>
<div>{{ runnerJob.finishedAt}}</div>
</td>
</tr>
</ng-template>

View file

@ -1,19 +1,19 @@
import { SortMeta, SharedModule } from 'primeng/api'
import { NgClass, NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { RouterLink } from '@angular/router'
import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
import { formatICU } from '@app/helpers'
import { RunnerJob, RunnerJobState } from '@peertube/peertube-models'
import { RunnerJobFormatted, RunnerService } from '../runner.service'
import { AutoColspanDirective } from '../../../../shared/shared-main/angular/auto-colspan.directive'
import { TableExpanderIconComponent } from '../../../../shared/shared-tables/table-expander-icon.component'
import { ButtonComponent } from '../../../../shared/shared-main/buttons/button.component'
import { AdvancedInputFilter, AdvancedInputFilterComponent } from '../../../../shared/shared-forms/advanced-input-filter.component'
import { ActionDropdownComponent, DropdownAction } from '../../../../shared/shared-main/buttons/action-dropdown.component'
import { NgIf, NgClass } from '@angular/common'
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'
import { RunnerJob, RunnerJobState } from '@peertube/peertube-models'
import { SharedModule, SortMeta } from 'primeng/api'
import { TableModule } from 'primeng/table'
import { RouterLink } from '@angular/router'
import { AdvancedInputFilter, AdvancedInputFilterComponent } from '../../../../shared/shared-forms/advanced-input-filter.component'
import { GlobalIconComponent } from '../../../../shared/shared-icons/global-icon.component'
import { AutoColspanDirective } from '../../../../shared/shared-main/angular/auto-colspan.directive'
import { ActionDropdownComponent, DropdownAction } from '../../../../shared/shared-main/buttons/action-dropdown.component'
import { ButtonComponent } from '../../../../shared/shared-main/buttons/button.component'
import { TableExpanderIconComponent } from '../../../../shared/shared-tables/table-expander-icon.component'
import { RunnerJobFormatted, RunnerService } from '../runner.service'
@Component({
selector: 'my-runner-job-list',
@ -176,6 +176,14 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI
}
}
getRandomRunnerNameBadge (value: string) {
return this.getRandomBadge('runner', value)
}
getRandomRunnerTypeBadge (value: string) {
return this.getRandomBadge('type', value)
}
protected reloadDataInternal () {
this.runnerService.listRunnerJobs({ pagination: this.pagination, sort: this.sort, search: this.search })
.subscribe({

View file

@ -1,9 +1,9 @@
import debug from 'debug'
import { SortMeta } from 'primeng/api'
import { TableLazyLoadEvent } from 'primeng/table'
import { ActivatedRoute, Router } from '@angular/router'
import { logger } from '@root-helpers/logger'
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
import debug from 'debug'
import { SortMeta } from 'primeng/api'
import { TableLazyLoadEvent } from 'primeng/table'
import { RestPagination } from './rest-pagination'
const debugLogger = debug('peertube:tables:RestTable')
@ -27,6 +27,11 @@ export abstract class RestTable <T = unknown> {
protected route: ActivatedRoute
protected router: Router
// First string is badge column type
// Inner Map is value -> badge name
private valueToBadge = new Map<string, Map<string, string>>()
private badgesUsed = new Set<string>()
abstract getIdentifier (): string
initialize () {
@ -96,6 +101,38 @@ export abstract class RestTable <T = unknown> {
this.reloadDataInternal()
}
protected getRandomBadge (type: string, value: string): string {
if (!this.valueToBadge.has(type)) {
this.valueToBadge.set(type, new Map())
}
const badges = this.valueToBadge.get(type)
const badge = badges.get(value)
if (badge) return badge
const toTry = [
'badge-yellow',
'badge-purple',
'badge-blue',
'badge-brown',
'badge-green',
'badge-secondary'
]
for (const badge of toTry) {
if (!this.badgesUsed.has(badge)) {
this.badgesUsed.add(badge)
badges.set(value, badge)
return badge
}
}
// Reset, we used all available badges
this.badgesUsed.clear()
return this.getRandomBadge(type, value)
}
private getSortLocalStorageKey () {
return 'rest-table-sort-' + this.getIdentifier()
}

View file

@ -8,6 +8,7 @@
font-size: 75%;
font-weight: $font-semibold;
line-height: 1.1;
max-width: 100%;
&.badge-fs-normal {
font-size: 100%;