1
0
Fork 0

Add bulk actions on runner jobs

This commit is contained in:
Chocobozzz 2023-05-19 14:27:27 +02:00
parent 01283e2066
commit 476ce1d7f4
No known key found for this signature in database
GPG key ID: 583A612D890159BE
3 changed files with 58 additions and 16 deletions

View file

@ -14,12 +14,15 @@
[value]="runnerJobs" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start" [value]="runnerJobs" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start"
[rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order" [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order"
[lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false"
[showCurrentPageReport]="true" i18n-currentPageReportTemplate [(selection)]="selectedRows" [showCurrentPageReport]="true" i18n-currentPageReportTemplate
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} runner jobs" currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} runner jobs"
[expandedRowKeys]="expandedRows" dataKey="uuid" [expandedRowKeys]="expandedRows" dataKey="uuid"
> >
<ng-template pTemplate="header"> <ng-template pTemplate="header">
<tr> <tr>
<th style="width: 40px">
<p-tableHeaderCheckbox ariaLabel="Select all rows" i18n-ariaLabel></p-tableHeaderCheckbox>
</th>
<th style="width: 40px"></th> <th style="width: 40px"></th>
<th style="width: 120px;"></th> <th style="width: 120px;"></th>
<th i18n>UUID</th> <th i18n>UUID</th>
@ -33,7 +36,16 @@
</ng-template> </ng-template>
<ng-template pTemplate="caption"> <ng-template pTemplate="caption">
<div class="caption"> <div class="caption">
<div class="left-buttons">
<my-action-dropdown
*ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange"
[actions]="bulkActions" [entry]="selectedRows"
>
</my-action-dropdown>
</div>
<div class="ms-auto d-flex"> <div class="ms-auto d-flex">
<my-advanced-input-filter class="me-2" (search)="onSearch($event)"></my-advanced-input-filter> <my-advanced-input-filter class="me-2" (search)="onSearch($event)"></my-advanced-input-filter>
@ -43,7 +55,11 @@
</ng-template> </ng-template>
<ng-template pTemplate="body" let-expanded="expanded" let-runnerJob> <ng-template pTemplate="body" let-expanded="expanded" let-runnerJob>
<tr> <tr [pSelectableRow]="runnerJob">
<td class="checkbox-cell">
<p-tableCheckbox [value]="runnerJob" ariaLabel="Select this row" i18n-ariaLabel></p-tableCheckbox>
</td>
<td class="expand-cell" [pRowToggler]="runnerJob"> <td class="expand-cell" [pRowToggler]="runnerJob">
<my-table-expander-icon [expanded]="expanded"></my-table-expander-icon> <my-table-expander-icon [expanded]="expanded"></my-table-expander-icon>
</td> </td>

View file

@ -1,8 +1,9 @@
import { SortMeta } from 'primeng/api' import { SortMeta } from 'primeng/api'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
import { prepareIcu } from '@app/helpers'
import { DropdownAction } from '@app/shared/shared-main' import { DropdownAction } from '@app/shared/shared-main'
import { RunnerJob } from '@shared/models' import { RunnerJob, RunnerJobState } from '@shared/models'
import { RunnerJobFormatted, RunnerService } from '../runner.service' import { RunnerJobFormatted, RunnerService } from '../runner.service'
@Component({ @Component({
@ -17,6 +18,7 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI
pagination: RestPagination = { count: this.rowsPerPage, start: 0 } pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
actions: DropdownAction<RunnerJob>[][] = [] actions: DropdownAction<RunnerJob>[][] = []
bulkActions: DropdownAction<RunnerJob[]>[][] = []
constructor ( constructor (
private runnerService: RunnerService, private runnerService: RunnerService,
@ -31,7 +33,18 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI
[ [
{ {
label: $localize`Cancel this job`, label: $localize`Cancel this job`,
handler: job => this.cancelJob(job) handler: job => this.cancelJobs([ job ]),
isDisplayed: job => this.canCancelJob(job)
}
]
]
this.bulkActions = [
[
{
label: $localize`Cancel`,
handler: jobs => this.cancelJobs(jobs),
isDisplayed: jobs => jobs.every(j => this.canCancelJob(j))
} }
] ]
] ]
@ -43,19 +56,20 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI
return 'RunnerJobListComponent' return 'RunnerJobListComponent'
} }
async cancelJob (job: RunnerJob) { async cancelJobs (jobs: RunnerJob[]) {
const res = await this.confirmService.confirm( const message = prepareIcu(
$localize`Do you really want to cancel this job? Children won't be processed.`, $localize`Do you really want to cancel {count, plural, =1 {this job} other {{count} jobs}}? Children jobs will also be cancelled.`
$localize`Cancel job` )({ count: jobs.length }, $localize`Do you really want to cancel these jobs? Children jobs will also be cancelled.`)
)
const res = await this.confirmService.confirm(message, $localize`Cancel`)
if (res === false) return if (res === false) return
this.runnerService.cancelJob(job) this.runnerService.cancelJobs(jobs)
.subscribe({ .subscribe({
next: () => { next: () => {
this.reloadData() this.reloadData()
this.notifier.success($localize`Job cancelled.`) this.notifier.success($localize`Job(s) cancelled.`)
}, },
error: err => this.notifier.error(err.message) error: err => this.notifier.error(err.message)
@ -73,4 +87,10 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI
error: err => this.notifier.error(err.message) error: err => this.notifier.error(err.message)
}) })
} }
private canCancelJob (job: RunnerJob) {
return job.state.id === RunnerJobState.PENDING ||
job.state.id === RunnerJobState.PROCESSING ||
job.state.id === RunnerJobState.WAITING_FOR_PARENT_JOB
}
} }

View file

@ -1,10 +1,10 @@
import { SortMeta } from 'primeng/api' import { SortMeta } from 'primeng/api'
import { catchError, forkJoin, map } from 'rxjs' import { catchError, concatMap, forkJoin, from, map, toArray } from 'rxjs'
import { HttpClient, HttpParams } from '@angular/common/http' import { HttpClient, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { RestExtractor, RestPagination, RestService, ServerService } from '@app/core' import { RestExtractor, RestPagination, RestService, ServerService } from '@app/core'
import { peertubeTranslate } from '@shared/core-utils' import { arrayify, peertubeTranslate } from '@shared/core-utils'
import { ResultList } from '@shared/models/common' import { ResultList } from '@shared/models/common'
import { Runner, RunnerJob, RunnerJobAdmin, RunnerRegistrationToken } from '@shared/models/runners' import { Runner, RunnerJob, RunnerJobAdmin, RunnerRegistrationToken } from '@shared/models/runners'
import { environment } from '../../../../environments/environment' import { environment } from '../../../../environments/environment'
@ -90,9 +90,15 @@ export class RunnerService {
) )
} }
cancelJob (job: RunnerJob) { cancelJobs (jobsArg: RunnerJob | RunnerJob[]) {
return this.authHttp.post(RunnerService.BASE_RUNNER_URL + '/jobs/' + job.uuid + '/cancel', {}) const jobs = arrayify(jobsArg)
.pipe(catchError(res => this.restExtractor.handleError(res)))
return from(jobs)
.pipe(
concatMap(job => this.authHttp.post(RunnerService.BASE_RUNNER_URL + '/jobs/' + job.uuid + '/cancel', {})),
toArray(),
catchError(err => this.restExtractor.handleError(err))
)
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------