<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> <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> <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> <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>
max-width: 150px;
}
}
+
+.retry-dropdown {
+ width: 300px;
+}
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[] = [
{
IfPermissionsDirective,
CustomDatePipe,
ConfirmDialogComponent,
+ CheckComponent,
],
imports: [
NgbModule,
`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
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])
public autoRefreshInterval: any
+ public retryClean: boolean = false
+
get dismissButtonText(): string {
return this.selectedTasks.size > 0
? $localize`Dismiss selected`
}
retryTask(task: PaperlessTask) {
- this.tasksService.retryTask(task).subscribe({
+ this.tasksService.retryTask(task, this.retryClean).subscribe({
next: () => {
this.toastService.showInfo($localize`Retrying task...`)
},
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()
})
}
- 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),
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,
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
@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(