]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Basic option selection feature-retry-consume
authorshamoon <4887959+shamoon@users.noreply.github.com>
Fri, 8 Nov 2024 08:23:42 +0000 (00:23 -0800)
committershamoon <4887959+shamoon@users.noreply.github.com>
Sat, 9 Nov 2024 04:36:58 +0000 (20:36 -0800)
src-ui/src/app/components/admin/tasks/tasks.component.html
src-ui/src/app/components/admin/tasks/tasks.component.scss
src-ui/src/app/components/admin/tasks/tasks.component.spec.ts
src-ui/src/app/components/admin/tasks/tasks.component.ts
src-ui/src/app/services/tasks.service.spec.ts
src-ui/src/app/services/tasks.service.ts
src/documents/serialisers.py
src/documents/views.py

index 39f3aebbf33480f42610f7a27f3cc578abd6dbb1..4ea9747cd708cd42a4954797670363de8c975dec 100644 (file)
@@ -82,9 +82,7 @@
           <td scope="row">
             <div class="btn-group" role="group">
               @if (task.status === PaperlessTaskStatus.Failed) {
-                <button class="btn btn-sm btn-outline-primary" (click)="retryTask(task); $event.stopPropagation();" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.PaperlessTask }">
-                  <i-bs name="arrow-repeat"></i-bs>&nbsp;<ng-container i18n>Retry</ng-container>
-                </button>
+                <ng-container *ngTemplateOutlet="retryDropdown; context: { task: task }"></ng-container>
               }
               <button class="btn btn-sm btn-outline-secondary" (click)="dismissTask(task); $event.stopPropagation();" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.PaperlessTask }">
                 <i-bs name="check"></i-bs>&nbsp;<ng-container i18n>Dismiss</ng-container>
   </li>
 </ul>
 <div [ngbNavOutlet]="nav"></div>
+
+<ng-template #retryDropdown let-task="task">
+  <div ngbDropdown>
+    <button class="btn btn-sm btn-outline-primary" (click)="$event.stopImmediatePropagation()" ngbDropdownToggle>
+      <i-bs name="arrow-repeat"></i-bs>&nbsp;<ng-container i18n>Retry</ng-container>
+    </button>
+    <div ngbDropdownMenu class="shadow retry-dropdown">
+      <div class="p-2">
+        <ul class="list-group list-group-flush">
+            <li class="list-group-item small" i18n>
+              <pngx-input-check [(ngModel)]="retryClean" i18n-title title="Attempt to clean pdf"></pngx-input-check>
+            </li>
+        </ul>
+        <div class="d-flex justify-content-end">
+          <button class="btn btn-sm btn-outline-primary" (click)="retryTask(task); $event.stopPropagation();">
+            <ng-container i18n>Proceed</ng-container>
+          </button>
+        </div>
+      </div>
+    </div>
+  </div>
+</ng-template>
index 60f8f22976883ed79ae49a3fa688414bf3cdc554..1c0cbfc379b8300a400c96f7f1950fe862e8aecb 100644 (file)
@@ -26,3 +26,7 @@ pre {
         max-width: 150px;
     }
 }
+
+.retry-dropdown {
+    width: 300px;
+}
index 435e95ac6194920ceb902ba4fd46c0582bb4ca7e..9e1d42e0185e6289ed2d729695269dbe1fb24766 100644 (file)
@@ -33,6 +33,7 @@ import { FormsModule } from '@angular/forms'
 import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
 import { ToastService } from 'src/app/services/toast.service'
 import { of, throwError } from 'rxjs'
+import { CheckComponent } from '../../common/input/check/check.component'
 
 const tasks: PaperlessTask[] = [
   {
@@ -128,6 +129,7 @@ describe('TasksComponent', () => {
         IfPermissionsDirective,
         CustomDatePipe,
         ConfirmDialogComponent,
+        CheckComponent,
       ],
       imports: [
         NgbModule,
@@ -177,8 +179,10 @@ describe('TasksComponent', () => {
       `Failed${currentTasksLength}`
     )
     expect(
-      fixture.debugElement.queryAll(By.css('table input[type="checkbox"]'))
-    ).toHaveLength(currentTasksLength + 1)
+      fixture.debugElement.queryAll(
+        By.css('table td > .form-check input[type="checkbox"]')
+      )
+    ).toHaveLength(currentTasksLength)
 
     currentTasksLength = tasks.filter(
       (t) => t.status === PaperlessTaskStatus.Complete
@@ -300,7 +304,7 @@ describe('TasksComponent', () => {
     const toastErrorSpy = jest.spyOn(toastService, 'showError')
     retrySpy.mockReturnValueOnce(of({ task_id: '123' }))
     component.retryTask(tasks[0])
-    expect(retrySpy).toHaveBeenCalledWith(tasks[0])
+    expect(retrySpy).toHaveBeenCalledWith(tasks[0], false)
     expect(toastInfoSpy).toHaveBeenCalledWith('Retrying task...')
     retrySpy.mockReturnValueOnce(throwError(() => new Error('test')))
     component.retryTask(tasks[0])
index 854c13142ae7cbe2e5f309d834919c4af613c260..ec4c75c944d6d1190e27ceb731626bc0d48f96d2 100644 (file)
@@ -28,6 +28,8 @@ export class TasksComponent
 
   public autoRefreshInterval: any
 
+  public retryClean: boolean = false
+
   get dismissButtonText(): string {
     return this.selectedTasks.size > 0
       ? $localize`Dismiss selected`
@@ -87,7 +89,7 @@ export class TasksComponent
   }
 
   retryTask(task: PaperlessTask) {
-    this.tasksService.retryTask(task).subscribe({
+    this.tasksService.retryTask(task, this.retryClean).subscribe({
       next: () => {
         this.toastService.showInfo($localize`Retrying task...`)
       },
index 60492bde0c034383141f60374916ce4f8c451013..0bd4ea8be1a6b477be85c465747615a375c950b3 100644 (file)
@@ -130,14 +130,14 @@ describe('TasksService', () => {
       date_created: new Date(),
     }
 
-    tasksService.retryTask(task).subscribe()
+    tasksService.retryTask(task, true).subscribe()
     const reloadSpy = jest.spyOn(tasksService, 'reload')
     const req = httpTestingController.expectOne(
       `${environment.apiBaseUrl}tasks/${task.id}/retry/`
     )
     expect(req.request.method).toEqual('POST')
     expect(req.request.body).toEqual({
-      task_id: task.id,
+      clean: true,
     })
     req.flush({ task_id: 12345 })
     expect(reloadSpy).toHaveBeenCalled()
index 52c8b1a3ef46ff22224c585b6dbcbda7cea90a65..9ccfb9ba804ec0afeaa8f99cdd5c9daac503565c 100644 (file)
@@ -73,10 +73,10 @@ export class TasksService {
       })
   }
 
-  public retryTask(task: PaperlessTask): Observable<any> {
+  public retryTask(task: PaperlessTask, clean: boolean): Observable<any> {
     return this.http
       .post(`${this.baseUrl}tasks/${task.id}/retry/`, {
-        task_id: task.id,
+        clean,
       })
       .pipe(
         takeUntil(this.unsubscribeNotifer),
index aeb901f81fae673449f20cffffd43ba8256793ca..6a830f2b5361ff12d7a1ad5e7b6f0fd8466d8c97 100644 (file)
@@ -1585,6 +1585,14 @@ class TasksViewSerializer(serializers.ModelSerializer):
         return result
 
 
+class RetryTaskSerializer(serializers.Serializer):
+    clean = serializers.BooleanField(
+        default=False,
+        write_only=True,
+        required=False,
+    )
+
+
 class AcknowledgeTasksViewSerializer(serializers.Serializer):
     tasks = serializers.ListField(
         required=True,
index 1f0b3ad982f75fb1e4a0f4b2f4ae0025e67e068d..4985971dad5a48540550e64ca04debf4254e24b5 100644 (file)
@@ -136,6 +136,7 @@ from documents.serialisers import DocumentListSerializer
 from documents.serialisers import DocumentSerializer
 from documents.serialisers import DocumentTypeSerializer
 from documents.serialisers import PostDocumentSerializer
+from documents.serialisers import RetryTaskSerializer
 from documents.serialisers import SavedViewSerializer
 from documents.serialisers import SearchResultSerializer
 from documents.serialisers import ShareLinkSerializer
@@ -1722,9 +1723,16 @@ class TasksViewSet(ReadOnlyModelViewSet):
     @action(methods=["post"], detail=True)
     def retry(self, request, pk=None):
         task = self.get_object()
+
+        serializer = RetryTaskSerializer(data=request.data)
+        serializer.is_valid(raise_exception=True)
+        clean = serializer.validated_data.get("clean")
+
         try:
-            new_task_id = retry_failed_file(task.task_id, True)
+            new_task_id = retry_failed_file(task.task_id, clean)
             return Response({"task_id": new_task_id})
+        except FileNotFoundError:
+            return HttpResponseBadRequest("Original file not found")
         except Exception as e:
             logger.warning(f"An error occurred retrying task: {e!s}")
             return HttpResponseBadRequest(