]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Add bulk actions on runner jobs
authorChocobozzz <me@florianbigard.com>
Fri, 19 May 2023 12:27:27 +0000 (14:27 +0200)
committerChocobozzz <me@florianbigard.com>
Fri, 19 May 2023 12:27:27 +0000 (14:27 +0200)
client/src/app/+admin/system/runners/runner-job-list/runner-job-list.component.html
client/src/app/+admin/system/runners/runner-job-list/runner-job-list.component.ts
client/src/app/+admin/system/runners/runner.service.ts

index 654b60ca9f339f0991301fd9353a63bec144ffcd..5356e0e03766977bc410f355c35ad9ff3233549b 100644 (file)
   [value]="runnerJobs" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [first]="pagination.start"
   [rowsPerPageOptions]="rowsPerPageOptions" [sortField]="sort.field" [sortOrder]="sort.order"
   [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"
   [expandedRowKeys]="expandedRows" dataKey="uuid"
 >
   <ng-template pTemplate="header">
     <tr>
+      <th style="width: 40px">
+        <p-tableHeaderCheckbox ariaLabel="Select all rows" i18n-ariaLabel></p-tableHeaderCheckbox>
+      </th>
       <th style="width: 40px"></th>
       <th style="width: 120px;"></th>
       <th i18n>UUID</th>
   </ng-template>
 
   <ng-template pTemplate="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">
         <my-advanced-input-filter class="me-2" (search)="onSearch($event)"></my-advanced-input-filter>
 
   </ng-template>
 
   <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">
         <my-table-expander-icon [expanded]="expanded"></my-table-expander-icon>
       </td>
index ea889f0f771a5ca01003bd6c96358264eb7cd522..8ba956eb8ef564f87b770bfb9c1e5aca65a934ea 100644 (file)
@@ -1,8 +1,9 @@
 import { SortMeta } from 'primeng/api'
 import { Component, OnInit } from '@angular/core'
 import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
+import { prepareIcu } from '@app/helpers'
 import { DropdownAction } from '@app/shared/shared-main'
-import { RunnerJob } from '@shared/models'
+import { RunnerJob, RunnerJobState } from '@shared/models'
 import { RunnerJobFormatted, RunnerService } from '../runner.service'
 
 @Component({
@@ -17,6 +18,7 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI
   pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
 
   actions: DropdownAction<RunnerJob>[][] = []
+  bulkActions: DropdownAction<RunnerJob[]>[][] = []
 
   constructor (
     private runnerService: RunnerService,
@@ -31,7 +33,18 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI
       [
         {
           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'
   }
 
-  async cancelJob (job: RunnerJob) {
-    const res = await this.confirmService.confirm(
-      $localize`Do you really want to cancel this job? Children won't be processed.`,
-      $localize`Cancel job`
-    )
+  async cancelJobs (jobs: RunnerJob[]) {
+    const message = prepareIcu(
+      $localize`Do you really want to cancel {count, plural, =1 {this job} other {{count} jobs}}? Children jobs will also be cancelled.`
+    )({ 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
 
-    this.runnerService.cancelJob(job)
+    this.runnerService.cancelJobs(jobs)
         .subscribe({
           next: () => {
             this.reloadData()
-            this.notifier.success($localize`Job cancelled.`)
+            this.notifier.success($localize`Job(s) cancelled.`)
           },
 
           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)
       })
   }
+
+  private canCancelJob (job: RunnerJob) {
+    return job.state.id === RunnerJobState.PENDING ||
+      job.state.id === RunnerJobState.PROCESSING ||
+      job.state.id === RunnerJobState.WAITING_FOR_PARENT_JOB
+  }
 }
index 05083318cd5b1690d8aab13e22b080fb33f270d0..392ec82bcae79b472c0530a8ad4395e1eabdc361 100644 (file)
@@ -1,10 +1,10 @@
 
 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 { Injectable } from '@angular/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 { Runner, RunnerJob, RunnerJobAdmin, RunnerRegistrationToken } from '@shared/models/runners'
 import { environment } from '../../../../environments/environment'
@@ -90,9 +90,15 @@ export class RunnerService {
     )
   }
 
-  cancelJob (job: RunnerJob) {
-    return this.authHttp.post(RunnerService.BASE_RUNNER_URL + '/jobs/' + job.uuid + '/cancel', {})
-      .pipe(catchError(res => this.restExtractor.handleError(res)))
+  cancelJobs (jobsArg: RunnerJob | RunnerJob[]) {
+    const jobs = arrayify(jobsArg)
+
+    return from(jobs)
+      .pipe(
+        concatMap(job => this.authHttp.post(RunnerService.BASE_RUNNER_URL + '/jobs/' + job.uuid + '/cancel', {})),
+        toArray(),
+        catchError(err => this.restExtractor.handleError(err))
+      )
   }
 
   // ---------------------------------------------------------------------------