Basic option selection

This commit is contained in:
shamoon 2024-11-08 00:23:42 -08:00
parent 62b470f691
commit ec12e71487
No known key found for this signature in database
8 changed files with 58 additions and 12 deletions

View File

@ -82,9 +82,7 @@
<td scope="row"> <td scope="row">
<div class="btn-group" role="group"> <div class="btn-group" role="group">
@if (task.status === PaperlessTaskStatus.Failed) { @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 }"> <ng-container *ngTemplateOutlet="retryDropdown; context: { task: task }"></ng-container>
<i-bs name="arrow-repeat"></i-bs>&nbsp;<ng-container i18n>Retry</ng-container>
</button>
} }
<button class="btn btn-sm btn-outline-secondary" (click)="dismissTask(task); $event.stopPropagation();" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.PaperlessTask }"> <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> <i-bs name="check"></i-bs>&nbsp;<ng-container i18n>Dismiss</ng-container>
@ -158,3 +156,25 @@
</li> </li>
</ul> </ul>
<div [ngbNavOutlet]="nav"></div> <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>

View File

@ -26,3 +26,7 @@ pre {
max-width: 150px; max-width: 150px;
} }
} }
.retry-dropdown {
width: 300px;
}

View File

@ -33,6 +33,7 @@ import { FormsModule } from '@angular/forms'
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http' import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
import { ToastService } from 'src/app/services/toast.service' import { ToastService } from 'src/app/services/toast.service'
import { of, throwError } from 'rxjs' import { of, throwError } from 'rxjs'
import { CheckComponent } from '../../common/input/check/check.component'
const tasks: PaperlessTask[] = [ const tasks: PaperlessTask[] = [
{ {
@ -128,6 +129,7 @@ describe('TasksComponent', () => {
IfPermissionsDirective, IfPermissionsDirective,
CustomDatePipe, CustomDatePipe,
ConfirmDialogComponent, ConfirmDialogComponent,
CheckComponent,
], ],
imports: [ imports: [
NgbModule, NgbModule,
@ -177,8 +179,10 @@ describe('TasksComponent', () => {
`Failed${currentTasksLength}` `Failed${currentTasksLength}`
) )
expect( expect(
fixture.debugElement.queryAll(By.css('table input[type="checkbox"]')) fixture.debugElement.queryAll(
).toHaveLength(currentTasksLength + 1) By.css('table td > .form-check input[type="checkbox"]')
)
).toHaveLength(currentTasksLength)
currentTasksLength = tasks.filter( currentTasksLength = tasks.filter(
(t) => t.status === PaperlessTaskStatus.Complete (t) => t.status === PaperlessTaskStatus.Complete
@ -300,7 +304,7 @@ describe('TasksComponent', () => {
const toastErrorSpy = jest.spyOn(toastService, 'showError') const toastErrorSpy = jest.spyOn(toastService, 'showError')
retrySpy.mockReturnValueOnce(of({ task_id: '123' })) retrySpy.mockReturnValueOnce(of({ task_id: '123' }))
component.retryTask(tasks[0]) component.retryTask(tasks[0])
expect(retrySpy).toHaveBeenCalledWith(tasks[0]) expect(retrySpy).toHaveBeenCalledWith(tasks[0], false)
expect(toastInfoSpy).toHaveBeenCalledWith('Retrying task...') expect(toastInfoSpy).toHaveBeenCalledWith('Retrying task...')
retrySpy.mockReturnValueOnce(throwError(() => new Error('test'))) retrySpy.mockReturnValueOnce(throwError(() => new Error('test')))
component.retryTask(tasks[0]) component.retryTask(tasks[0])

View File

@ -28,6 +28,8 @@ export class TasksComponent
public autoRefreshInterval: any public autoRefreshInterval: any
public retryClean: boolean = false
get dismissButtonText(): string { get dismissButtonText(): string {
return this.selectedTasks.size > 0 return this.selectedTasks.size > 0
? $localize`Dismiss selected` ? $localize`Dismiss selected`
@ -87,7 +89,7 @@ export class TasksComponent
} }
retryTask(task: PaperlessTask) { retryTask(task: PaperlessTask) {
this.tasksService.retryTask(task).subscribe({ this.tasksService.retryTask(task, this.retryClean).subscribe({
next: () => { next: () => {
this.toastService.showInfo($localize`Retrying task...`) this.toastService.showInfo($localize`Retrying task...`)
}, },

View File

@ -130,14 +130,14 @@ describe('TasksService', () => {
date_created: new Date(), date_created: new Date(),
} }
tasksService.retryTask(task).subscribe() tasksService.retryTask(task, true).subscribe()
const reloadSpy = jest.spyOn(tasksService, 'reload') const reloadSpy = jest.spyOn(tasksService, 'reload')
const req = httpTestingController.expectOne( const req = httpTestingController.expectOne(
`${environment.apiBaseUrl}tasks/${task.id}/retry/` `${environment.apiBaseUrl}tasks/${task.id}/retry/`
) )
expect(req.request.method).toEqual('POST') expect(req.request.method).toEqual('POST')
expect(req.request.body).toEqual({ expect(req.request.body).toEqual({
task_id: task.id, clean: true,
}) })
req.flush({ task_id: 12345 }) req.flush({ task_id: 12345 })
expect(reloadSpy).toHaveBeenCalled() expect(reloadSpy).toHaveBeenCalled()

View 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 return this.http
.post(`${this.baseUrl}tasks/${task.id}/retry/`, { .post(`${this.baseUrl}tasks/${task.id}/retry/`, {
task_id: task.id, clean,
}) })
.pipe( .pipe(
takeUntil(this.unsubscribeNotifer), takeUntil(this.unsubscribeNotifer),

View File

@ -1585,6 +1585,14 @@ class TasksViewSerializer(serializers.ModelSerializer):
return result return result
class RetryTaskSerializer(serializers.Serializer):
clean = serializers.BooleanField(
default=False,
write_only=True,
required=False,
)
class AcknowledgeTasksViewSerializer(serializers.Serializer): class AcknowledgeTasksViewSerializer(serializers.Serializer):
tasks = serializers.ListField( tasks = serializers.ListField(
required=True, required=True,

View File

@ -136,6 +136,7 @@ from documents.serialisers import DocumentListSerializer
from documents.serialisers import DocumentSerializer from documents.serialisers import DocumentSerializer
from documents.serialisers import DocumentTypeSerializer from documents.serialisers import DocumentTypeSerializer
from documents.serialisers import PostDocumentSerializer from documents.serialisers import PostDocumentSerializer
from documents.serialisers import RetryTaskSerializer
from documents.serialisers import SavedViewSerializer from documents.serialisers import SavedViewSerializer
from documents.serialisers import SearchResultSerializer from documents.serialisers import SearchResultSerializer
from documents.serialisers import ShareLinkSerializer from documents.serialisers import ShareLinkSerializer
@ -1722,9 +1723,16 @@ class TasksViewSet(ReadOnlyModelViewSet):
@action(methods=["post"], detail=True) @action(methods=["post"], detail=True)
def retry(self, request, pk=None): def retry(self, request, pk=None):
task = self.get_object() task = self.get_object()
serializer = RetryTaskSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
clean = serializer.validated_data.get("clean")
try: 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}) return Response({"task_id": new_task_id})
except FileNotFoundError:
return HttpResponseBadRequest("Original file not found")
except Exception as e: except Exception as e:
logger.warning(f"An error occurred retrying task: {e!s}") logger.warning(f"An error occurred retrying task: {e!s}")
return HttpResponseBadRequest( return HttpResponseBadRequest(