diff options
3 files changed, 58 insertions, 16 deletions
diff --git a/client/src/app/+admin/system/runners/runner-job-list/runner-job-list.component.html b/client/src/app/+admin/system/runners/runner-job-list/runner-job-list.component.html index 654b60ca9..5356e0e03 100644 --- a/client/src/app/+admin/system/runners/runner-job-list/runner-job-list.component.html +++ b/client/src/app/+admin/system/runners/runner-job-list/runner-job-list.component.html | |||
@@ -14,12 +14,15 @@ | |||
14 | [value]="runnerJobs" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start" | 14 | [value]="runnerJobs" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start" |
15 | [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order" | 15 | [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order" |
16 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | 16 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" |
17 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 17 | [(selection)]="selectedRows" [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
18 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} runner jobs" | 18 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} runner jobs" |
19 | [expandedRowKeys]="expandedRows" dataKey="uuid" | 19 | [expandedRowKeys]="expandedRows" dataKey="uuid" |
20 | > | 20 | > |
21 | <ng-template pTemplate="header"> | 21 | <ng-template pTemplate="header"> |
22 | <tr> | 22 | <tr> |
23 | <th style="width: 40px"> | ||
24 | <p-tableHeaderCheckbox ariaLabel="Select all rows" i18n-ariaLabel></p-tableHeaderCheckbox> | ||
25 | </th> | ||
23 | <th style="width: 40px"></th> | 26 | <th style="width: 40px"></th> |
24 | <th style="width: 120px;"></th> | 27 | <th style="width: 120px;"></th> |
25 | <th i18n>UUID</th> | 28 | <th i18n>UUID</th> |
@@ -33,7 +36,16 @@ | |||
33 | </ng-template> | 36 | </ng-template> |
34 | 37 | ||
35 | <ng-template pTemplate="caption"> | 38 | <ng-template pTemplate="caption"> |
39 | |||
36 | <div class="caption"> | 40 | <div class="caption"> |
41 | <div class="left-buttons"> | ||
42 | <my-action-dropdown | ||
43 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" | ||
44 | [actions]="bulkActions" [entry]="selectedRows" | ||
45 | > | ||
46 | </my-action-dropdown> | ||
47 | </div> | ||
48 | |||
37 | <div class="ms-auto d-flex"> | 49 | <div class="ms-auto d-flex"> |
38 | <my-advanced-input-filter class="me-2" (search)="onSearch($event)"></my-advanced-input-filter> | 50 | <my-advanced-input-filter class="me-2" (search)="onSearch($event)"></my-advanced-input-filter> |
39 | 51 | ||
@@ -43,7 +55,11 @@ | |||
43 | </ng-template> | 55 | </ng-template> |
44 | 56 | ||
45 | <ng-template pTemplate="body" let-expanded="expanded" let-runnerJob> | 57 | <ng-template pTemplate="body" let-expanded="expanded" let-runnerJob> |
46 | <tr> | 58 | <tr [pSelectableRow]="runnerJob"> |
59 | <td class="checkbox-cell"> | ||
60 | <p-tableCheckbox [value]="runnerJob" ariaLabel="Select this row" i18n-ariaLabel></p-tableCheckbox> | ||
61 | </td> | ||
62 | |||
47 | <td class="expand-cell" [pRowToggler]="runnerJob"> | 63 | <td class="expand-cell" [pRowToggler]="runnerJob"> |
48 | <my-table-expander-icon [expanded]="expanded"></my-table-expander-icon> | 64 | <my-table-expander-icon [expanded]="expanded"></my-table-expander-icon> |
49 | </td> | 65 | </td> |
diff --git a/client/src/app/+admin/system/runners/runner-job-list/runner-job-list.component.ts b/client/src/app/+admin/system/runners/runner-job-list/runner-job-list.component.ts index ea889f0f7..8ba956eb8 100644 --- a/client/src/app/+admin/system/runners/runner-job-list/runner-job-list.component.ts +++ b/client/src/app/+admin/system/runners/runner-job-list/runner-job-list.component.ts | |||
@@ -1,8 +1,9 @@ | |||
1 | import { SortMeta } from 'primeng/api' | 1 | import { SortMeta } from 'primeng/api' |
2 | import { Component, OnInit } from '@angular/core' | 2 | import { Component, OnInit } from '@angular/core' |
3 | import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' | 3 | import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' |
4 | import { prepareIcu } from '@app/helpers' | ||
4 | import { DropdownAction } from '@app/shared/shared-main' | 5 | import { DropdownAction } from '@app/shared/shared-main' |
5 | import { RunnerJob } from '@shared/models' | 6 | import { RunnerJob, RunnerJobState } from '@shared/models' |
6 | import { RunnerJobFormatted, RunnerService } from '../runner.service' | 7 | import { RunnerJobFormatted, RunnerService } from '../runner.service' |
7 | 8 | ||
8 | @Component({ | 9 | @Component({ |
@@ -17,6 +18,7 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI | |||
17 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 18 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
18 | 19 | ||
19 | actions: DropdownAction<RunnerJob>[][] = [] | 20 | actions: DropdownAction<RunnerJob>[][] = [] |
21 | bulkActions: DropdownAction<RunnerJob[]>[][] = [] | ||
20 | 22 | ||
21 | constructor ( | 23 | constructor ( |
22 | private runnerService: RunnerService, | 24 | private runnerService: RunnerService, |
@@ -31,7 +33,18 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI | |||
31 | [ | 33 | [ |
32 | { | 34 | { |
33 | label: $localize`Cancel this job`, | 35 | label: $localize`Cancel this job`, |
34 | handler: job => this.cancelJob(job) | 36 | handler: job => this.cancelJobs([ job ]), |
37 | isDisplayed: job => this.canCancelJob(job) | ||
38 | } | ||
39 | ] | ||
40 | ] | ||
41 | |||
42 | this.bulkActions = [ | ||
43 | [ | ||
44 | { | ||
45 | label: $localize`Cancel`, | ||
46 | handler: jobs => this.cancelJobs(jobs), | ||
47 | isDisplayed: jobs => jobs.every(j => this.canCancelJob(j)) | ||
35 | } | 48 | } |
36 | ] | 49 | ] |
37 | ] | 50 | ] |
@@ -43,19 +56,20 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI | |||
43 | return 'RunnerJobListComponent' | 56 | return 'RunnerJobListComponent' |
44 | } | 57 | } |
45 | 58 | ||
46 | async cancelJob (job: RunnerJob) { | 59 | async cancelJobs (jobs: RunnerJob[]) { |
47 | const res = await this.confirmService.confirm( | 60 | const message = prepareIcu( |
48 | $localize`Do you really want to cancel this job? Children won't be processed.`, | 61 | $localize`Do you really want to cancel {count, plural, =1 {this job} other {{count} jobs}}? Children jobs will also be cancelled.` |
49 | $localize`Cancel job` | 62 | )({ count: jobs.length }, $localize`Do you really want to cancel these jobs? Children jobs will also be cancelled.`) |
50 | ) | 63 | |
64 | const res = await this.confirmService.confirm(message, $localize`Cancel`) | ||
51 | 65 | ||
52 | if (res === false) return | 66 | if (res === false) return |
53 | 67 | ||
54 | this.runnerService.cancelJob(job) | 68 | this.runnerService.cancelJobs(jobs) |
55 | .subscribe({ | 69 | .subscribe({ |
56 | next: () => { | 70 | next: () => { |
57 | this.reloadData() | 71 | this.reloadData() |
58 | this.notifier.success($localize`Job cancelled.`) | 72 | this.notifier.success($localize`Job(s) cancelled.`) |
59 | }, | 73 | }, |
60 | 74 | ||
61 | error: err => this.notifier.error(err.message) | 75 | error: err => this.notifier.error(err.message) |
@@ -73,4 +87,10 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI | |||
73 | error: err => this.notifier.error(err.message) | 87 | error: err => this.notifier.error(err.message) |
74 | }) | 88 | }) |
75 | } | 89 | } |
90 | |||
91 | private canCancelJob (job: RunnerJob) { | ||
92 | return job.state.id === RunnerJobState.PENDING || | ||
93 | job.state.id === RunnerJobState.PROCESSING || | ||
94 | job.state.id === RunnerJobState.WAITING_FOR_PARENT_JOB | ||
95 | } | ||
76 | } | 96 | } |
diff --git a/client/src/app/+admin/system/runners/runner.service.ts b/client/src/app/+admin/system/runners/runner.service.ts index 05083318c..392ec82bc 100644 --- a/client/src/app/+admin/system/runners/runner.service.ts +++ b/client/src/app/+admin/system/runners/runner.service.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | 1 | ||
2 | import { SortMeta } from 'primeng/api' | 2 | import { SortMeta } from 'primeng/api' |
3 | import { catchError, forkJoin, map } from 'rxjs' | 3 | import { catchError, concatMap, forkJoin, from, map, toArray } from 'rxjs' |
4 | import { HttpClient, HttpParams } from '@angular/common/http' | 4 | import { HttpClient, HttpParams } from '@angular/common/http' |
5 | import { Injectable } from '@angular/core' | 5 | import { Injectable } from '@angular/core' |
6 | import { RestExtractor, RestPagination, RestService, ServerService } from '@app/core' | 6 | import { RestExtractor, RestPagination, RestService, ServerService } from '@app/core' |
7 | import { peertubeTranslate } from '@shared/core-utils' | 7 | import { arrayify, peertubeTranslate } from '@shared/core-utils' |
8 | import { ResultList } from '@shared/models/common' | 8 | import { ResultList } from '@shared/models/common' |
9 | import { Runner, RunnerJob, RunnerJobAdmin, RunnerRegistrationToken } from '@shared/models/runners' | 9 | import { Runner, RunnerJob, RunnerJobAdmin, RunnerRegistrationToken } from '@shared/models/runners' |
10 | import { environment } from '../../../../environments/environment' | 10 | import { environment } from '../../../../environments/environment' |
@@ -90,9 +90,15 @@ export class RunnerService { | |||
90 | ) | 90 | ) |
91 | } | 91 | } |
92 | 92 | ||
93 | cancelJob (job: RunnerJob) { | 93 | cancelJobs (jobsArg: RunnerJob | RunnerJob[]) { |
94 | return this.authHttp.post(RunnerService.BASE_RUNNER_URL + '/jobs/' + job.uuid + '/cancel', {}) | 94 | const jobs = arrayify(jobsArg) |
95 | .pipe(catchError(res => this.restExtractor.handleError(res))) | 95 | |
96 | return from(jobs) | ||
97 | .pipe( | ||
98 | concatMap(job => this.authHttp.post(RunnerService.BASE_RUNNER_URL + '/jobs/' + job.uuid + '/cancel', {})), | ||
99 | toArray(), | ||
100 | catchError(err => this.restExtractor.handleError(err)) | ||
101 | ) | ||
96 | } | 102 | } |
97 | 103 | ||
98 | // --------------------------------------------------------------------------- | 104 | // --------------------------------------------------------------------------- |