mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 03:16:10 -06:00 
			
		
		
		
	Enhancement: file task filtering (#8421)
This commit is contained in:
		@@ -1880,6 +1880,10 @@
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">36</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">30</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">35</context>
 | 
			
		||||
@@ -2037,7 +2041,7 @@
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">68</context>
 | 
			
		||||
          <context context-type="linenumber">124</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="2134950584701094962" datatype="html">
 | 
			
		||||
@@ -2089,60 +2093,74 @@
 | 
			
		||||
          <context context-type="linenumber">147,149</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="4880728824338713664" datatype="html">
 | 
			
		||||
        <source>Filter by</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">157</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="2525230676386818985" datatype="html">
 | 
			
		||||
        <source>Result</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">31</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="5404910960991552159" datatype="html">
 | 
			
		||||
        <source>Dismiss selected</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">31</context>
 | 
			
		||||
          <context context-type="linenumber">77</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="8829078752502782653" datatype="html">
 | 
			
		||||
        <source>Dismiss all</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">32</context>
 | 
			
		||||
          <context context-type="linenumber">78</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="1323591410517879795" datatype="html">
 | 
			
		||||
        <source>Confirm Dismiss All</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">65</context>
 | 
			
		||||
          <context context-type="linenumber">121</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="4157200209636243740" datatype="html">
 | 
			
		||||
        <source>Dismiss all <x id="PH" equiv-text="tasks.size"/> tasks?</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">66</context>
 | 
			
		||||
          <context context-type="linenumber">122</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="9011556615675272238" datatype="html">
 | 
			
		||||
        <source>queued</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">135</context>
 | 
			
		||||
          <context context-type="linenumber">207</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="6415892379431855826" datatype="html">
 | 
			
		||||
        <source>started</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">137</context>
 | 
			
		||||
          <context context-type="linenumber">209</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="7510279840486540181" datatype="html">
 | 
			
		||||
        <source>completed</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">139</context>
 | 
			
		||||
          <context context-type="linenumber">211</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="4083337005045748464" datatype="html">
 | 
			
		||||
        <source>failed</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">141</context>
 | 
			
		||||
          <context context-type="linenumber">213</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="3418677553313974490" datatype="html">
 | 
			
		||||
 
 | 
			
		||||
@@ -118,13 +118,13 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</ng-template>
 | 
			
		||||
 | 
			
		||||
<ul ngbNav #nav="ngbNav" [(activeId)]="activeTab" class="nav-tabs" (hidden)="duringTabChange($event)">
 | 
			
		||||
<ul ngbNav #nav="ngbNav" [(activeId)]="activeTab" class="nav-tabs" (hidden)="duringTabChange()" (navChange)="beforeTabChange()">
 | 
			
		||||
  <li ngbNavItem="failed">
 | 
			
		||||
    <a ngbNavLink i18n>Failed@if (tasksService.failedFileTasks.length > 0) {
 | 
			
		||||
      <span class="badge bg-danger ms-2">{{tasksService.failedFileTasks.length}}</span>
 | 
			
		||||
    }</a>
 | 
			
		||||
    <ng-template ngbNavContent>
 | 
			
		||||
      <ng-container [ngTemplateOutlet]="tasksTemplate" [ngTemplateOutletContext]="{tasks:tasksService.failedFileTasks}"></ng-container>
 | 
			
		||||
      <ng-container [ngTemplateOutlet]="tasksTemplate" [ngTemplateOutletContext]="{tasks:currentTasks}"></ng-container>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
  </li>
 | 
			
		||||
  <li ngbNavItem="completed">
 | 
			
		||||
@@ -132,7 +132,7 @@
 | 
			
		||||
      <span class="badge bg-secondary ms-2">{{tasksService.completedFileTasks.length}}</span>
 | 
			
		||||
    }</a>
 | 
			
		||||
    <ng-template ngbNavContent>
 | 
			
		||||
      <ng-container [ngTemplateOutlet]="tasksTemplate" [ngTemplateOutletContext]="{tasks:tasksService.completedFileTasks}"></ng-container>
 | 
			
		||||
      <ng-container [ngTemplateOutlet]="tasksTemplate" [ngTemplateOutletContext]="{tasks:currentTasks}"></ng-container>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
  </li>
 | 
			
		||||
  <li ngbNavItem="started">
 | 
			
		||||
@@ -140,7 +140,7 @@
 | 
			
		||||
      <span class="badge bg-secondary ms-2">{{tasksService.startedFileTasks.length}}</span>
 | 
			
		||||
    }</a>
 | 
			
		||||
    <ng-template ngbNavContent>
 | 
			
		||||
      <ng-container [ngTemplateOutlet]="tasksTemplate" [ngTemplateOutletContext]="{tasks:tasksService.startedFileTasks}"></ng-container>
 | 
			
		||||
      <ng-container [ngTemplateOutlet]="tasksTemplate" [ngTemplateOutletContext]="{tasks:currentTasks}"></ng-container>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
  </li>
 | 
			
		||||
  <li ngbNavItem="queued">
 | 
			
		||||
@@ -148,8 +148,35 @@
 | 
			
		||||
      <span class="badge bg-secondary ms-2">{{tasksService.queuedFileTasks.length}}</span>
 | 
			
		||||
    }</a>
 | 
			
		||||
    <ng-template ngbNavContent>
 | 
			
		||||
      <ng-container [ngTemplateOutlet]="tasksTemplate" [ngTemplateOutletContext]="{tasks:tasksService.queuedFileTasks}"></ng-container>
 | 
			
		||||
      <ng-container [ngTemplateOutlet]="tasksTemplate" [ngTemplateOutletContext]="{tasks:currentTasks}"></ng-container>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
  </li>
 | 
			
		||||
  <li class="ms-auto">
 | 
			
		||||
    <div class="form-inline d-flex align-items-center">
 | 
			
		||||
      <div class="input-group input-group-sm flex-fill w-auto flex-nowrap">
 | 
			
		||||
        <span class="input-group-text text-muted" i18n>Filter by</span>
 | 
			
		||||
        @if (filterTargets.length > 1) {
 | 
			
		||||
          <div ngbDropdown>
 | 
			
		||||
            <button class="btn btn-sm btn-outline-primary" ngbDropdownToggle>{{filterTargetName}}</button>
 | 
			
		||||
            <div class="dropdown-menu shadow" ngbDropdownMenu>
 | 
			
		||||
              @for (t of filterTargets; track t.id) {
 | 
			
		||||
                <button ngbDropdownItem [class.active]="filterTargetID === t.id" (click)="filterTargetID = t.id">{{t.name}}</button>
 | 
			
		||||
              }
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        } @else {
 | 
			
		||||
          <span class="input-group-text">{{filterTargetName}}</span>
 | 
			
		||||
        }
 | 
			
		||||
        @if (filterText?.length) {
 | 
			
		||||
          <button class="btn btn-link btn-sm px-2 position-absolute top-0 end-0 z-10" (click)="resetFilter()">
 | 
			
		||||
            <i-bs width="1em" height="1em" name="x"></i-bs>
 | 
			
		||||
          </button>
 | 
			
		||||
        }
 | 
			
		||||
        <input #filterInput class="form-control form-control-sm" type="text"
 | 
			
		||||
          (keyup)="filterInputKeyup($event)"
 | 
			
		||||
          [(ngModel)]="filterText">
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </li>
 | 
			
		||||
</ul>
 | 
			
		||||
<div [ngbNavOutlet]="nav"></div>
 | 
			
		||||
 
 | 
			
		||||
@@ -26,3 +26,14 @@ pre {
 | 
			
		||||
        max-width: 150px;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.input-group .dropdown .btn {
 | 
			
		||||
    border-top-right-radius: 0;
 | 
			
		||||
    border-bottom-right-radius: 0;
 | 
			
		||||
    border-top-left-radius: 0;
 | 
			
		||||
    border-bottom-left-radius: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.z-10 {
 | 
			
		||||
    z-index: 10;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ import { TasksService } from 'src/app/services/tasks.service'
 | 
			
		||||
import { environment } from 'src/environments/environment'
 | 
			
		||||
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
 | 
			
		||||
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
 | 
			
		||||
import { TasksComponent } from './tasks.component'
 | 
			
		||||
import { TasksComponent, TaskTab } from './tasks.component'
 | 
			
		||||
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
 | 
			
		||||
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
 | 
			
		||||
import { FormsModule } from '@angular/forms'
 | 
			
		||||
@@ -167,7 +167,7 @@ describe('TasksComponent', () => {
 | 
			
		||||
    let currentTasksLength = tasks.filter(
 | 
			
		||||
      (t) => t.status === PaperlessTaskStatus.Failed
 | 
			
		||||
    ).length
 | 
			
		||||
    component.activeTab = 'failed'
 | 
			
		||||
    component.activeTab = TaskTab.Failed
 | 
			
		||||
    fixture.detectChanges()
 | 
			
		||||
    expect(tabButtons[0].nativeElement.textContent).toEqual(
 | 
			
		||||
      `Failed${currentTasksLength}`
 | 
			
		||||
@@ -179,7 +179,7 @@ describe('TasksComponent', () => {
 | 
			
		||||
    currentTasksLength = tasks.filter(
 | 
			
		||||
      (t) => t.status === PaperlessTaskStatus.Complete
 | 
			
		||||
    ).length
 | 
			
		||||
    component.activeTab = 'completed'
 | 
			
		||||
    component.activeTab = TaskTab.Completed
 | 
			
		||||
    fixture.detectChanges()
 | 
			
		||||
    expect(tabButtons[1].nativeElement.textContent).toEqual(
 | 
			
		||||
      `Complete${currentTasksLength}`
 | 
			
		||||
@@ -188,7 +188,7 @@ describe('TasksComponent', () => {
 | 
			
		||||
    currentTasksLength = tasks.filter(
 | 
			
		||||
      (t) => t.status === PaperlessTaskStatus.Started
 | 
			
		||||
    ).length
 | 
			
		||||
    component.activeTab = 'started'
 | 
			
		||||
    component.activeTab = TaskTab.Started
 | 
			
		||||
    fixture.detectChanges()
 | 
			
		||||
    expect(tabButtons[2].nativeElement.textContent).toEqual(
 | 
			
		||||
      `Started${currentTasksLength}`
 | 
			
		||||
@@ -197,7 +197,7 @@ describe('TasksComponent', () => {
 | 
			
		||||
    currentTasksLength = tasks.filter(
 | 
			
		||||
      (t) => t.status === PaperlessTaskStatus.Pending
 | 
			
		||||
    ).length
 | 
			
		||||
    component.activeTab = 'queued'
 | 
			
		||||
    component.activeTab = TaskTab.Queued
 | 
			
		||||
    fixture.detectChanges()
 | 
			
		||||
    expect(tabButtons[3].nativeElement.textContent).toEqual(
 | 
			
		||||
      `Queued${currentTasksLength}`
 | 
			
		||||
@@ -206,7 +206,7 @@ describe('TasksComponent', () => {
 | 
			
		||||
 | 
			
		||||
  it('should to go page 1 between tab switch', () => {
 | 
			
		||||
    component.page = 10
 | 
			
		||||
    component.duringTabChange(2)
 | 
			
		||||
    component.duringTabChange()
 | 
			
		||||
    expect(component.page).toEqual(1)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
@@ -289,4 +289,53 @@ describe('TasksComponent', () => {
 | 
			
		||||
    jest.advanceTimersByTime(6000)
 | 
			
		||||
    expect(reloadSpy).toHaveBeenCalledTimes(2)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should filter tasks by file name', () => {
 | 
			
		||||
    const input = fixture.debugElement.query(By.css('ul input[type=text]'))
 | 
			
		||||
    input.nativeElement.value = '191092'
 | 
			
		||||
    input.nativeElement.dispatchEvent(new Event('input'))
 | 
			
		||||
    jest.advanceTimersByTime(150) // debounce time
 | 
			
		||||
    fixture.detectChanges()
 | 
			
		||||
    expect(component.filterText).toEqual('191092')
 | 
			
		||||
    expect(
 | 
			
		||||
      fixture.debugElement.queryAll(By.css('table tbody tr')).length
 | 
			
		||||
    ).toEqual(2) // 1 task x 2 lines
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should filter tasks by result', () => {
 | 
			
		||||
    component.activeTab = TaskTab.Failed
 | 
			
		||||
    fixture.detectChanges()
 | 
			
		||||
    component.filterTargetID = 1
 | 
			
		||||
    const input = fixture.debugElement.query(By.css('ul input[type=text]'))
 | 
			
		||||
    input.nativeElement.value = 'duplicate'
 | 
			
		||||
    input.nativeElement.dispatchEvent(new Event('input'))
 | 
			
		||||
    jest.advanceTimersByTime(150) // debounce time
 | 
			
		||||
    fixture.detectChanges()
 | 
			
		||||
    expect(component.filterText).toEqual('duplicate')
 | 
			
		||||
    expect(
 | 
			
		||||
      fixture.debugElement.queryAll(By.css('table tbody tr')).length
 | 
			
		||||
    ).toEqual(4) // 2 tasks x 2 lines
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should support keyboard events for filtering', () => {
 | 
			
		||||
    const input = fixture.debugElement.query(By.css('ul input[type=text]'))
 | 
			
		||||
    input.nativeElement.value = '191092'
 | 
			
		||||
    input.nativeElement.dispatchEvent(
 | 
			
		||||
      new KeyboardEvent('keyup', { key: 'Enter' })
 | 
			
		||||
    )
 | 
			
		||||
    expect(component.filterText).toEqual('191092') // no debounce needed
 | 
			
		||||
    input.nativeElement.dispatchEvent(
 | 
			
		||||
      new KeyboardEvent('keyup', { key: 'Escape' })
 | 
			
		||||
    )
 | 
			
		||||
    expect(component.filterText).toEqual('')
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should reset filter and target on tab switch', () => {
 | 
			
		||||
    component.filterText = '191092'
 | 
			
		||||
    component.filterTargetID = 1
 | 
			
		||||
    component.activeTab = TaskTab.Completed
 | 
			
		||||
    component.beforeTabChange()
 | 
			
		||||
    expect(component.filterText).toEqual('')
 | 
			
		||||
    expect(component.filterTargetID).toEqual(0)
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,36 @@
 | 
			
		||||
import { Component, OnInit, OnDestroy } from '@angular/core'
 | 
			
		||||
import { Router } from '@angular/router'
 | 
			
		||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
 | 
			
		||||
import { first } from 'rxjs'
 | 
			
		||||
import {
 | 
			
		||||
  debounceTime,
 | 
			
		||||
  distinctUntilChanged,
 | 
			
		||||
  filter,
 | 
			
		||||
  first,
 | 
			
		||||
  Subject,
 | 
			
		||||
  takeUntil,
 | 
			
		||||
} from 'rxjs'
 | 
			
		||||
import { PaperlessTask } from 'src/app/data/paperless-task'
 | 
			
		||||
import { TasksService } from 'src/app/services/tasks.service'
 | 
			
		||||
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
 | 
			
		||||
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
 | 
			
		||||
 | 
			
		||||
export enum TaskTab {
 | 
			
		||||
  Queued = 'queued',
 | 
			
		||||
  Started = 'started',
 | 
			
		||||
  Completed = 'completed',
 | 
			
		||||
  Failed = 'failed',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum TaskFilterTargetID {
 | 
			
		||||
  Name,
 | 
			
		||||
  Result,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const FILTER_TARGETS = [
 | 
			
		||||
  { id: TaskFilterTargetID.Name, name: $localize`Name` },
 | 
			
		||||
  { id: TaskFilterTargetID.Result, name: $localize`Result` },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'pngx-tasks',
 | 
			
		||||
  templateUrl: './tasks.component.html',
 | 
			
		||||
@@ -16,7 +40,7 @@ export class TasksComponent
 | 
			
		||||
  extends ComponentWithPermissions
 | 
			
		||||
  implements OnInit, OnDestroy
 | 
			
		||||
{
 | 
			
		||||
  public activeTab: string
 | 
			
		||||
  public activeTab: TaskTab
 | 
			
		||||
  public selectedTasks: Set<number> = new Set()
 | 
			
		||||
  public togggleAll: boolean = false
 | 
			
		||||
  public expandedTask: number
 | 
			
		||||
@@ -26,6 +50,28 @@ export class TasksComponent
 | 
			
		||||
 | 
			
		||||
  public autoRefreshInterval: any
 | 
			
		||||
 | 
			
		||||
  private _filterText: string = ''
 | 
			
		||||
  get filterText() {
 | 
			
		||||
    return this._filterText
 | 
			
		||||
  }
 | 
			
		||||
  set filterText(value: string) {
 | 
			
		||||
    this.filterDebounce.next(value)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public filterTargetID: TaskFilterTargetID = TaskFilterTargetID.Name
 | 
			
		||||
  public get filterTargetName(): string {
 | 
			
		||||
    return this.filterTargets.find((t) => t.id == this.filterTargetID).name
 | 
			
		||||
  }
 | 
			
		||||
  private filterDebounce: Subject<string> = new Subject<string>()
 | 
			
		||||
 | 
			
		||||
  public get filterTargets(): Array<{ id: number; name: string }> {
 | 
			
		||||
    return [TaskTab.Failed, TaskTab.Completed].includes(this.activeTab)
 | 
			
		||||
      ? FILTER_TARGETS
 | 
			
		||||
      : FILTER_TARGETS.slice(0, 1)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private unsubscribeNotifier: Subject<any> = new Subject()
 | 
			
		||||
 | 
			
		||||
  get dismissButtonText(): string {
 | 
			
		||||
    return this.selectedTasks.size > 0
 | 
			
		||||
      ? $localize`Dismiss selected`
 | 
			
		||||
@@ -43,11 +89,21 @@ export class TasksComponent
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.tasksService.reload()
 | 
			
		||||
    this.toggleAutoRefresh()
 | 
			
		||||
 | 
			
		||||
    this.filterDebounce
 | 
			
		||||
      .pipe(
 | 
			
		||||
        takeUntil(this.unsubscribeNotifier),
 | 
			
		||||
        debounceTime(100),
 | 
			
		||||
        distinctUntilChanged(),
 | 
			
		||||
        filter((query) => !query.length || query.length > 2)
 | 
			
		||||
      )
 | 
			
		||||
      .subscribe((query) => (this._filterText = query))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy() {
 | 
			
		||||
    this.tasksService.cancelPending()
 | 
			
		||||
    clearInterval(this.autoRefreshInterval)
 | 
			
		||||
    this.unsubscribeNotifier.next(this)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  dismissTask(task: PaperlessTask) {
 | 
			
		||||
@@ -96,19 +152,30 @@ export class TasksComponent
 | 
			
		||||
  get currentTasks(): PaperlessTask[] {
 | 
			
		||||
    let tasks: PaperlessTask[] = []
 | 
			
		||||
    switch (this.activeTab) {
 | 
			
		||||
      case 'queued':
 | 
			
		||||
      case TaskTab.Queued:
 | 
			
		||||
        tasks = this.tasksService.queuedFileTasks
 | 
			
		||||
        break
 | 
			
		||||
      case 'started':
 | 
			
		||||
      case TaskTab.Started:
 | 
			
		||||
        tasks = this.tasksService.startedFileTasks
 | 
			
		||||
        break
 | 
			
		||||
      case 'completed':
 | 
			
		||||
      case TaskTab.Completed:
 | 
			
		||||
        tasks = this.tasksService.completedFileTasks
 | 
			
		||||
        break
 | 
			
		||||
      case 'failed':
 | 
			
		||||
      case TaskTab.Failed:
 | 
			
		||||
        tasks = this.tasksService.failedFileTasks
 | 
			
		||||
        break
 | 
			
		||||
    }
 | 
			
		||||
    if (this._filterText.length) {
 | 
			
		||||
      tasks = tasks.filter((t) => {
 | 
			
		||||
        if (this.filterTargetID == TaskFilterTargetID.Name) {
 | 
			
		||||
          return t.task_file_name
 | 
			
		||||
            .toLowerCase()
 | 
			
		||||
            .includes(this._filterText.toLowerCase())
 | 
			
		||||
        } else if (this.filterTargetID == TaskFilterTargetID.Result) {
 | 
			
		||||
          return t.result.toLowerCase().includes(this._filterText.toLowerCase())
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
    return tasks
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -125,19 +192,24 @@ export class TasksComponent
 | 
			
		||||
    this.selectedTasks.clear()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  duringTabChange(navID: number) {
 | 
			
		||||
  duringTabChange() {
 | 
			
		||||
    this.page = 1
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  beforeTabChange() {
 | 
			
		||||
    this.resetFilter()
 | 
			
		||||
    this.filterTargetID = TaskFilterTargetID.Name
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get activeTabLocalized(): string {
 | 
			
		||||
    switch (this.activeTab) {
 | 
			
		||||
      case 'queued':
 | 
			
		||||
      case TaskTab.Queued:
 | 
			
		||||
        return $localize`queued`
 | 
			
		||||
      case 'started':
 | 
			
		||||
      case TaskTab.Started:
 | 
			
		||||
        return $localize`started`
 | 
			
		||||
      case 'completed':
 | 
			
		||||
      case TaskTab.Completed:
 | 
			
		||||
        return $localize`completed`
 | 
			
		||||
      case 'failed':
 | 
			
		||||
      case TaskTab.Failed:
 | 
			
		||||
        return $localize`failed`
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -152,4 +224,16 @@ export class TasksComponent
 | 
			
		||||
      }, 5000)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public resetFilter() {
 | 
			
		||||
    this._filterText = ''
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  filterInputKeyup(event: KeyboardEvent) {
 | 
			
		||||
    if (event.key == 'Enter') {
 | 
			
		||||
      this._filterText = (event.target as HTMLInputElement).value
 | 
			
		||||
    } else if (event.key === 'Escape') {
 | 
			
		||||
      this.resetFilter()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user