mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Frontend better handle slow backend requests
This commit is contained in:
@@ -2,16 +2,23 @@
|
||||
|
||||
</app-page-header>
|
||||
|
||||
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="activeLog" (activeIdChange)="reloadLogs()" class="nav-tabs">
|
||||
<li *ngFor="let logFile of logFiles" [ngbNavItem]="logFile">
|
||||
<a ngbNavLink>{{logFile}}.log</a>
|
||||
</li>
|
||||
<div *ngIf="isLoading && !logFiles.length" class="pb-2">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
||||
<ng-container i18n>Loading...</ng-container>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
|
||||
<div class="bg-dark p-3 text-light font-monospace log-container" #logContainer>
|
||||
<div *ngIf="isLoading && logFiles.length">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
||||
<ng-container i18n>Loading...</ng-container>
|
||||
</div>
|
||||
<p
|
||||
class="m-0 p-0 log-entry-{{getLogLevel(log)}}"
|
||||
*ngFor="let log of logs">{{log}}</p>
|
||||
|
@@ -4,7 +4,9 @@ import {
|
||||
OnInit,
|
||||
AfterViewChecked,
|
||||
ViewChild,
|
||||
OnDestroy,
|
||||
} from '@angular/core'
|
||||
import { Subject, takeUntil } from 'rxjs'
|
||||
import { LogService } from 'src/app/services/rest/log.service'
|
||||
|
||||
@Component({
|
||||
@@ -12,40 +14,60 @@ import { LogService } from 'src/app/services/rest/log.service'
|
||||
templateUrl: './logs.component.html',
|
||||
styleUrls: ['./logs.component.scss'],
|
||||
})
|
||||
export class LogsComponent implements OnInit, AfterViewChecked {
|
||||
export class LogsComponent implements OnInit, AfterViewChecked, OnDestroy {
|
||||
constructor(private logService: LogService) {}
|
||||
|
||||
logs: string[] = []
|
||||
public logs: string[] = []
|
||||
|
||||
logFiles: string[] = []
|
||||
public logFiles: string[] = []
|
||||
|
||||
activeLog: string
|
||||
public activeLog: string
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
public isLoading: boolean = false
|
||||
|
||||
@ViewChild('logContainer') logContainer: ElementRef
|
||||
|
||||
ngOnInit(): void {
|
||||
this.logService.list().subscribe((result) => {
|
||||
this.logFiles = result
|
||||
if (this.logFiles.length > 0) {
|
||||
this.activeLog = this.logFiles[0]
|
||||
this.reloadLogs()
|
||||
}
|
||||
})
|
||||
this.isLoading = true
|
||||
this.logService
|
||||
.list()
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((result) => {
|
||||
this.logFiles = result
|
||||
this.isLoading = false
|
||||
if (this.logFiles.length > 0) {
|
||||
this.activeLog = this.logFiles[0]
|
||||
this.reloadLogs()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
ngAfterViewChecked() {
|
||||
this.scrollToBottom()
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeNotifier.next(true)
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
|
||||
reloadLogs() {
|
||||
this.logService.get(this.activeLog).subscribe({
|
||||
next: (result) => {
|
||||
this.logs = result
|
||||
},
|
||||
error: () => {
|
||||
this.logs = []
|
||||
},
|
||||
})
|
||||
this.isLoading = true
|
||||
this.logService
|
||||
.get(this.activeLog)
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe({
|
||||
next: (result) => {
|
||||
this.logs = result
|
||||
this.isLoading = false
|
||||
},
|
||||
error: () => {
|
||||
this.logs = []
|
||||
this.isLoading = false
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
getLogLevel(log: string) {
|
||||
|
@@ -24,6 +24,12 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngIf="isLoading">
|
||||
<td colspan="5">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
||||
<ng-container i18n>Loading...</ng-container>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngFor="let object of data">
|
||||
<td scope="row">{{ object.name }}</td>
|
||||
<td scope="row" class="d-none d-sm-table-cell">{{ getMatching(object) }}</td>
|
||||
@@ -69,7 +75,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="d-flex">
|
||||
<div class="d-flex" *ngIf="!isLoading">
|
||||
<div i18n *ngIf="collectionSize > 0">{collectionSize, plural, =1 {One {{typeName}}} other {{{collectionSize || 0}} total {{typeNamePlural}}}}</div>
|
||||
<ngb-pagination *ngIf="collectionSize > 20" class="ms-auto" [pageSize]="25" [collectionSize]="collectionSize" [(page)]="page" [maxSize]="5" (pageChange)="reloadData()" size="sm" aria-label="Pagination"></ngb-pagination>
|
||||
</div>
|
||||
|
@@ -7,7 +7,7 @@ import {
|
||||
} from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { Subject, Subscription } from 'rxjs'
|
||||
import { debounceTime, distinctUntilChanged } from 'rxjs/operators'
|
||||
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'
|
||||
import {
|
||||
MatchingModel,
|
||||
MATCHING_ALGORITHMS,
|
||||
@@ -76,8 +76,10 @@ export abstract class ManagementListComponent<T extends ObjectWithId>
|
||||
public sortField: string
|
||||
public sortReverse: boolean
|
||||
|
||||
public isLoading: boolean = false
|
||||
|
||||
private nameFilterDebounce: Subject<string>
|
||||
private subscription: Subscription
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
private _nameFilter: string
|
||||
|
||||
ngOnInit(): void {
|
||||
@@ -85,8 +87,12 @@ export abstract class ManagementListComponent<T extends ObjectWithId>
|
||||
|
||||
this.nameFilterDebounce = new Subject<string>()
|
||||
|
||||
this.subscription = this.nameFilterDebounce
|
||||
.pipe(debounceTime(400), distinctUntilChanged())
|
||||
this.nameFilterDebounce
|
||||
.pipe(
|
||||
takeUntil(this.unsubscribeNotifier),
|
||||
debounceTime(400),
|
||||
distinctUntilChanged()
|
||||
)
|
||||
.subscribe((title) => {
|
||||
this._nameFilter = title
|
||||
this.page = 1
|
||||
@@ -95,7 +101,8 @@ export abstract class ManagementListComponent<T extends ObjectWithId>
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subscription.unsubscribe()
|
||||
this.unsubscribeNotifier.next(true)
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
|
||||
getMatching(o: MatchingModel) {
|
||||
@@ -119,6 +126,7 @@ export abstract class ManagementListComponent<T extends ObjectWithId>
|
||||
}
|
||||
|
||||
reloadData() {
|
||||
this.isLoading = true
|
||||
this.service
|
||||
.listFiltered(
|
||||
this.page,
|
||||
@@ -128,9 +136,11 @@ export abstract class ManagementListComponent<T extends ObjectWithId>
|
||||
this._nameFilter,
|
||||
true
|
||||
)
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((c) => {
|
||||
this.data = c.results
|
||||
this.collectionSize = c.count
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
@@ -192,19 +202,22 @@ export abstract class ManagementListComponent<T extends ObjectWithId>
|
||||
activeModal.componentInstance.btnCaption = $localize`Delete`
|
||||
activeModal.componentInstance.confirmClicked.subscribe(() => {
|
||||
activeModal.componentInstance.buttonsEnabled = false
|
||||
this.service.delete(object).subscribe({
|
||||
next: () => {
|
||||
activeModal.close()
|
||||
this.reloadData()
|
||||
},
|
||||
error: (error) => {
|
||||
activeModal.componentInstance.buttonsEnabled = true
|
||||
this.toastService.showError(
|
||||
$localize`Error while deleting element`,
|
||||
error
|
||||
)
|
||||
},
|
||||
})
|
||||
this.service
|
||||
.delete(object)
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe({
|
||||
next: () => {
|
||||
activeModal.close()
|
||||
this.reloadData()
|
||||
},
|
||||
error: (error) => {
|
||||
activeModal.componentInstance.buttonsEnabled = true
|
||||
this.toastService.showError(
|
||||
$localize`Error while deleting element`,
|
||||
error
|
||||
)
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core'
|
||||
import { Router } from '@angular/router'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { Subject, first } from 'rxjs'
|
||||
import { first } 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'
|
||||
@@ -18,7 +18,6 @@ export class TasksComponent
|
||||
{
|
||||
public activeTab: string
|
||||
public selectedTasks: Set<number> = new Set()
|
||||
private unsubscribeNotifer = new Subject()
|
||||
public expandedTask: number
|
||||
|
||||
public pageSize: number = 25
|
||||
@@ -43,7 +42,7 @@ export class TasksComponent
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unsubscribeNotifer.next(true)
|
||||
this.tasksService.cancelPending()
|
||||
}
|
||||
|
||||
dismissTask(task: PaperlessTask) {
|
||||
|
Reference in New Issue
Block a user