Basic option selection

This commit is contained in:
shamoon
2024-11-08 00:23:42 -08:00
parent 03c71c604f
commit b2bbc2c0ac
8 changed files with 59 additions and 12 deletions

View File

@@ -113,9 +113,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" class="me-1"></i-bs><ng-container i18n>Dismiss</ng-container>
@@ -189,3 +187,25 @@
</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>

View File

@@ -37,3 +37,7 @@ pre {
.z-10 {
z-index: 10;
}
.retry-dropdown {
width: 300px;
}

View File

@@ -32,6 +32,7 @@ import { TasksService } from 'src/app/services/tasks.service'
import { ToastService } from 'src/app/services/toast.service'
import { environment } from 'src/environments/environment'
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
import { CheckComponent } from '../../common/input/check/check.component'
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { TasksComponent, TaskTab } from './tasks.component'
@@ -138,6 +139,7 @@ describe('TasksComponent', () => {
PageHeaderComponent,
IfPermissionsDirective,
CustomDatePipe,
CheckComponent,
ConfirmDialogComponent,
],
providers: [
@@ -184,8 +186,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
@@ -396,7 +400,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])

View File

@@ -26,6 +26,7 @@ import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { TasksService } from 'src/app/services/tasks.service'
import { ToastService } from 'src/app/services/toast.service'
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
import { CheckComponent } from '../../common/input/check/check.component'
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
@@ -54,6 +55,7 @@ const FILTER_TARGETS = [
PageHeaderComponent,
IfPermissionsDirective,
CustomDatePipe,
CheckComponent,
SlicePipe,
FormsModule,
ReactiveFormsModule,
@@ -106,6 +108,8 @@ export class TasksComponent
: FILTER_TARGETS.slice(0, 1)
}
public retryClean: boolean = false
get dismissButtonText(): string {
return this.selectedTasks.size > 0
? $localize`Dismiss selected`
@@ -180,7 +184,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...`)
},

View File

@@ -159,14 +159,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()

View File

@@ -81,10 +81,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),

View File

@@ -2410,6 +2410,13 @@ class TasksViewSerializer(OwnedObjectSerializer):
duplicates = _get_viewable_duplicates(document, user)
return list(duplicates.values("id", "title", "deleted_at"))
class RetryTaskSerializer(serializers.Serializer):
clean = serializers.BooleanField(
default=False,
write_only=True,
required=False,
)
class RunTaskViewSerializer(serializers.Serializer[dict[str, Any]]):
task_name = serializers.ChoiceField(

View File

@@ -189,6 +189,7 @@ from documents.serialisers import NotesSerializer
from documents.serialisers import PostDocumentSerializer
from documents.serialisers import RemovePasswordDocumentsSerializer
from documents.serialisers import ReprocessDocumentsSerializer
from documents.serialisers import RetryTaskSerializer
from documents.serialisers import RotateDocumentsSerializer
from documents.serialisers import RunTaskViewSerializer
from documents.serialisers import SavedViewSerializer
@@ -3471,9 +3472,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(