mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	cleanup subscriptions
This commit is contained in:
		| @@ -1,8 +1,8 @@ | |||||||
| import { Component, OnDestroy } from '@angular/core'; | import { Component } from '@angular/core'; | ||||||
| import { FormControl } from '@angular/forms'; | import { FormControl } from '@angular/forms'; | ||||||
| import { ActivatedRoute, Router, Params } from '@angular/router'; | import { ActivatedRoute, Router, Params } from '@angular/router'; | ||||||
| import { from, Observable, Subscription, BehaviorSubject } from 'rxjs'; | import { from, Observable, Subscription, BehaviorSubject } from 'rxjs'; | ||||||
| import { debounceTime, distinctUntilChanged, map, switchMap } from 'rxjs/operators'; | import { debounceTime, distinctUntilChanged, map, switchMap, first } from 'rxjs/operators'; | ||||||
| import { PaperlessDocument } from 'src/app/data/paperless-document'; | import { PaperlessDocument } from 'src/app/data/paperless-document'; | ||||||
| import { OpenDocumentsService } from 'src/app/services/open-documents.service'; | import { OpenDocumentsService } from 'src/app/services/open-documents.service'; | ||||||
| import { SavedViewService } from 'src/app/services/rest/saved-view.service'; | import { SavedViewService } from 'src/app/services/rest/saved-view.service'; | ||||||
| @@ -18,7 +18,7 @@ import { FILTER_FULLTEXT_QUERY } from 'src/app/data/filter-rule-type'; | |||||||
|   templateUrl: './app-frame.component.html', |   templateUrl: './app-frame.component.html', | ||||||
|   styleUrls: ['./app-frame.component.scss'] |   styleUrls: ['./app-frame.component.scss'] | ||||||
| }) | }) | ||||||
| export class AppFrameComponent implements OnDestroy { | export class AppFrameComponent { | ||||||
|  |  | ||||||
|   constructor ( |   constructor ( | ||||||
|     public router: Router, |     public router: Router, | ||||||
| @@ -40,8 +40,6 @@ export class AppFrameComponent implements OnDestroy { | |||||||
|  |  | ||||||
|   searchField = new FormControl('') |   searchField = new FormControl('') | ||||||
|  |  | ||||||
|   closeAllSub: Subscription |  | ||||||
|  |  | ||||||
|   get openDocuments(): PaperlessDocument[] { |   get openDocuments(): PaperlessDocument[] { | ||||||
|     return this.openDocumentsService.getOpenDocuments() |     return this.openDocumentsService.getOpenDocuments() | ||||||
|   } |   } | ||||||
| @@ -81,21 +79,23 @@ export class AppFrameComponent implements OnDestroy { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   closeDocument(d: PaperlessDocument) { |   closeDocument(d: PaperlessDocument) { | ||||||
|     this.closeMenu() |     this.openDocumentsService.closeDocument(d).pipe(first()).subscribe(confirmed => { | ||||||
|     this.openDocumentsService.closeDocument(d) |       if (confirmed) { | ||||||
|  |         this.closeMenu() | ||||||
|     let route = this.activatedRoute.snapshot |         let route = this.activatedRoute.snapshot | ||||||
|     while (route.firstChild) { |         while (route.firstChild) { | ||||||
|       route = route.firstChild |           route = route.firstChild | ||||||
|     } |         } | ||||||
|     if (route.component == DocumentDetailComponent && route.params['id'] == d.id) { |         if (route.component == DocumentDetailComponent && route.params['id'] == d.id) { | ||||||
|       this.router.navigate([""]) |           this.router.navigate([""]) | ||||||
|     } |         } | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   closeAll() { |   closeAll() { | ||||||
|     // user may need to confirm losing unsaved changes |     // user may need to confirm losing unsaved changes | ||||||
|     this.closeAllSub = this.openDocumentsService.closeAll().subscribe(confirmed => { |     this.openDocumentsService.closeAll().pipe(first()).subscribe(confirmed => { | ||||||
|       if (confirmed) { |       if (confirmed) { | ||||||
|         this.closeMenu() |         this.closeMenu() | ||||||
|  |  | ||||||
| @@ -111,10 +111,6 @@ export class AppFrameComponent implements OnDestroy { | |||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   ngOnDestroy() { |  | ||||||
|     this.closeAllSub && this.closeAllSub.unsubscribe(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   get displayName() { |   get displayName() { | ||||||
|     // TODO: taken from dashboard component, is this the best way to pass around username? |     // TODO: taken from dashboard component, is this the best way to pass around username? | ||||||
|     let tagFullName = this.meta.getTag('name=full_name') |     let tagFullName = this.meta.getTag('name=full_name') | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ | |||||||
|         </svg> <span class="d-none d-lg-inline" i18n>More like this</span> |         </svg> <span class="d-none d-lg-inline" i18n>More like this</span> | ||||||
|     </button> |     </button> | ||||||
|  |  | ||||||
|     <button type="button" class="btn btn-sm btn-outline-primary" (click)="maybeClose()"> |     <button type="button" class="btn btn-sm btn-outline-primary" (click)="close()"> | ||||||
|         <svg class="buttonicon" fill="currentColor"> |         <svg class="buttonicon" fill="currentColor"> | ||||||
|             <use xlink:href="assets/bootstrap-icons.svg#x" /> |             <use xlink:href="assets/bootstrap-icons.svg#x" /> | ||||||
|         </svg> <span class="d-none d-lg-inline" i18n>Close</span> |         </svg> <span class="d-none d-lg-inline" i18n>Close</span> | ||||||
|   | |||||||
| @@ -110,7 +110,7 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen | |||||||
|     this.correspondentService.listAll().pipe(first()).subscribe(result => this.correspondents = result.results) |     this.correspondentService.listAll().pipe(first()).subscribe(result => this.correspondents = result.results) | ||||||
|     this.documentTypeService.listAll().pipe(first()).subscribe(result => this.documentTypes = result.results) |     this.documentTypeService.listAll().pipe(first()).subscribe(result => this.documentTypes = result.results) | ||||||
|  |  | ||||||
|     this.route.paramMap.pipe(first()).subscribe(paramMap => { |     this.route.paramMap.pipe(takeUntil(this.unsubscribeNotifier)).subscribe(paramMap => { | ||||||
|       this.documentId = +paramMap.get('id') |       this.documentId = +paramMap.get('id') | ||||||
|       this.previewUrl = this.documentsService.getPreviewUrl(this.documentId) |       this.previewUrl = this.documentsService.getPreviewUrl(this.documentId) | ||||||
|       this.downloadUrl = this.documentsService.getDownloadUrl(this.documentId) |       this.downloadUrl = this.documentsService.getDownloadUrl(this.documentId) | ||||||
| @@ -133,7 +133,7 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen | |||||||
|  |  | ||||||
|         this.isDirty$ = dirtyCheck(this.documentForm, this.store.asObservable()) |         this.isDirty$ = dirtyCheck(this.documentForm, this.store.asObservable()) | ||||||
|         this.isDirty$.pipe(takeUntil(this.unsubscribeNotifier)).subscribe(dirty => { |         this.isDirty$.pipe(takeUntil(this.unsubscribeNotifier)).subscribe(dirty => { | ||||||
|           this.openDocumentService.setDirty(this.document.id, dirty) |           this.openDocumentService.setDirty(this.documentId, dirty) | ||||||
|         }) |         }) | ||||||
|  |  | ||||||
|         if (!this.openDocumentService.getOpenDocument(this.documentId)) { |         if (!this.openDocumentService.getOpenDocument(this.documentId)) { | ||||||
| @@ -216,12 +216,15 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen | |||||||
|     this.store.next(this.documentForm.value) |     this.store.next(this.documentForm.value) | ||||||
|     this.documentsService.update(this.document).pipe(first()).subscribe(result => { |     this.documentsService.update(this.document).pipe(first()).subscribe(result => { | ||||||
|       this.error = null |       this.error = null | ||||||
|       this.documentListViewService.getNext(this.document.id).pipe(first()).subscribe(nextDocId => { |       this.documentListViewService.getNext(this.documentId).pipe(first()).subscribe(nextDocId => { | ||||||
|         this.networkActive = false |         this.networkActive = false | ||||||
|         if (nextDocId) { |         if (nextDocId) { | ||||||
|           this.openDocumentService.closeDocument(this.document) |           this.openDocumentService.closeDocument(this.document, true).pipe(first()).subscribe(closed => { | ||||||
|           this.router.navigate(['documents', nextDocId]) |             if (closed) { | ||||||
|           this.titleInput.focus() |               this.router.navigate(['documents', nextDocId]) | ||||||
|  |               this.titleInput.focus() | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|         } |         } | ||||||
|       }, error => { |       }, error => { | ||||||
|         this.networkActive = false |         this.networkActive = false | ||||||
| @@ -232,35 +235,17 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen | |||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   maybeClose() { |   close() { | ||||||
|     this.isDirty$.pipe(takeUntil(this.unsubscribeNotifier)).subscribe(dirty => { |     this.openDocumentService.closeDocument(this.document).pipe(first()).subscribe(closed => { | ||||||
|       if (dirty) { |       if (!closed) return; | ||||||
|         let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) |       if (this.documentListViewService.activeSavedViewId) { | ||||||
|         modal.componentInstance.title = $localize`Unsaved Changes` |         this.router.navigate(['view', this.documentListViewService.activeSavedViewId]) | ||||||
|         modal.componentInstance.messageBold = $localize`You have unsaved changes.` |  | ||||||
|         modal.componentInstance.message = $localize`Are you sure you want to leave?` |  | ||||||
|         modal.componentInstance.btnClass = "btn-warning" |  | ||||||
|         modal.componentInstance.btnCaption = $localize`Leave page` |  | ||||||
|         modal.componentInstance.confirmClicked.pipe(first()).subscribe(() => { |  | ||||||
|           modal.componentInstance.buttonsEnabled = false |  | ||||||
|           modal.close() |  | ||||||
|           this.close() |  | ||||||
|         }) |  | ||||||
|       } else { |       } else { | ||||||
|         this.close() |         this.router.navigate(['documents']) | ||||||
|       } |       } | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   close() { |  | ||||||
|     this.openDocumentService.closeDocument(this.document) |  | ||||||
|     if (this.documentListViewService.activeSavedViewId) { |  | ||||||
|       this.router.navigate(['view', this.documentListViewService.activeSavedViewId]) |  | ||||||
|     } else { |  | ||||||
|       this.router.navigate(['documents']) |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   delete() { |   delete() { | ||||||
|     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) |     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) | ||||||
|     modal.componentInstance.title = $localize`Confirm delete` |     modal.componentInstance.title = $localize`Confirm delete` | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ export class DirtyFormGuard extends DirtyCheckGuard { | |||||||
|       modal.close() |       modal.close() | ||||||
|     }) |     }) | ||||||
|     const subject = new Subject<boolean>() |     const subject = new Subject<boolean>() | ||||||
|     modal.componentInstance.subject = subject |     modal.componentInstance.confirmSubject = subject | ||||||
|     return subject.asObservable() |     return subject.asObservable() | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import { DocumentService } from './rest/document.service'; | |||||||
| import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; | import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; | ||||||
| import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component'; | import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component'; | ||||||
| import { Observable, Subject, of } from 'rxjs'; | import { Observable, Subject, of } from 'rxjs'; | ||||||
| import { take } from 'rxjs/operators'; | import { first } from 'rxjs/operators'; | ||||||
|  |  | ||||||
| @Injectable({ | @Injectable({ | ||||||
|   providedIn: 'root' |   providedIn: 'root' | ||||||
| @@ -63,11 +63,30 @@ export class OpenDocumentsService { | |||||||
|     else this.dirtyDocuments.delete(documentId) |     else this.dirtyDocuments.delete(documentId) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   closeDocument(doc: PaperlessDocument) { |   closeDocument(doc: PaperlessDocument, force: boolean = false): Observable<boolean> { | ||||||
|     let index = this.openDocuments.findIndex(d => d.id == doc.id) |     let index = this.openDocuments.findIndex(d => d.id == doc.id) | ||||||
|     if (index > -1) { |     if (index == -1) return of(true); | ||||||
|  |     if (force || !this.dirtyDocuments.has(doc.id)) { | ||||||
|       this.openDocuments.splice(index, 1) |       this.openDocuments.splice(index, 1) | ||||||
|       this.save() |       this.save() | ||||||
|  |       return of(true) | ||||||
|  |     } else { | ||||||
|  |       let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) | ||||||
|  |       modal.componentInstance.title = $localize`Unsaved Changes` | ||||||
|  |       modal.componentInstance.messageBold = $localize`You have unsaved changes.` | ||||||
|  |       modal.componentInstance.message = $localize`Are you sure you want to close this document?` | ||||||
|  |       modal.componentInstance.btnClass = "btn-warning" | ||||||
|  |       modal.componentInstance.btnCaption = $localize`Close document` | ||||||
|  |       modal.componentInstance.confirmClicked.pipe(first()).subscribe(() => { | ||||||
|  |         modal.componentInstance.buttonsEnabled = false | ||||||
|  |         modal.close() | ||||||
|  |         this.openDocuments.splice(index, 1) | ||||||
|  |         this.dirtyDocuments.delete(doc.id) | ||||||
|  |         this.save() | ||||||
|  |       }) | ||||||
|  |       const subject = new Subject<boolean>() | ||||||
|  |       modal.componentInstance.confirmSubject = subject | ||||||
|  |       return subject.asObservable() | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -79,14 +98,14 @@ export class OpenDocumentsService { | |||||||
|       modal.componentInstance.message = $localize`Are you sure you want to close all documents?` |       modal.componentInstance.message = $localize`Are you sure you want to close all documents?` | ||||||
|       modal.componentInstance.btnClass = "btn-warning" |       modal.componentInstance.btnClass = "btn-warning" | ||||||
|       modal.componentInstance.btnCaption = $localize`Close documents` |       modal.componentInstance.btnCaption = $localize`Close documents` | ||||||
|       modal.componentInstance.confirmClicked.pipe(take(1)).subscribe(() => { |       modal.componentInstance.confirmClicked.pipe(first()).subscribe(() => { | ||||||
|         modal.componentInstance.buttonsEnabled = false |         modal.componentInstance.buttonsEnabled = false | ||||||
|         modal.close() |         modal.close() | ||||||
|         this.openDocuments.splice(0, this.openDocuments.length) |         this.openDocuments.splice(0, this.openDocuments.length) | ||||||
|         this.save() |         this.save() | ||||||
|       }) |       }) | ||||||
|       const subject = new Subject<boolean>() |       const subject = new Subject<boolean>() | ||||||
|       modal.componentInstance.subject = subject |       modal.componentInstance.confirmSubject = subject | ||||||
|       return subject.asObservable() |       return subject.asObservable() | ||||||
|     } else { |     } else { | ||||||
|       this.openDocuments.splice(0, this.openDocuments.length) |       this.openDocuments.splice(0, this.openDocuments.length) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Michael Shamoon
					Michael Shamoon