mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Enhancement: improve doc details close behavior (#8937)
This commit is contained in:
		| @@ -5,6 +5,7 @@ import { first, Subscription } from 'rxjs' | ||||
| import { ToastsComponent } from './components/common/toasts/toasts.component' | ||||
| import { FileDropComponent } from './components/file-drop/file-drop.component' | ||||
| import { SETTINGS_KEYS } from './data/ui-settings' | ||||
| import { ComponentRouterService } from './services/component-router.service' | ||||
| import { ConsumerStatusService } from './services/consumer-status.service' | ||||
| import { HotKeyService } from './services/hot-key.service' | ||||
| import { | ||||
| @@ -41,7 +42,8 @@ export class AppComponent implements OnInit, OnDestroy { | ||||
|     public tourService: TourService, | ||||
|     private renderer: Renderer2, | ||||
|     private permissionsService: PermissionsService, | ||||
|     private hotKeyService: HotKeyService | ||||
|     private hotKeyService: HotKeyService, | ||||
|     private componentRouterService: ComponentRouterService | ||||
|   ) { | ||||
|     let anyWindow = window as any | ||||
|     anyWindow.pdfWorkerSrc = 'assets/js/pdf.worker.min.mjs' | ||||
|   | ||||
| @@ -45,6 +45,7 @@ import { Tag } from 'src/app/data/tag' | ||||
| import { PermissionsGuard } from 'src/app/guards/permissions.guard' | ||||
| import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe' | ||||
| import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe' | ||||
| import { ComponentRouterService } from 'src/app/services/component-router.service' | ||||
| import { DocumentListViewService } from 'src/app/services/document-list-view.service' | ||||
| import { OpenDocumentsService } from 'src/app/services/open-documents.service' | ||||
| import { PermissionsService } from 'src/app/services/permissions.service' | ||||
| @@ -127,6 +128,7 @@ describe('DocumentDetailComponent', () => { | ||||
|   let settingsService: SettingsService | ||||
|   let customFieldsService: CustomFieldsService | ||||
|   let httpTestingController: HttpTestingController | ||||
|   let componentRouterService: ComponentRouterService | ||||
|  | ||||
|   let currentUserCan = true | ||||
|   let currentUserHasObjectPermissions = true | ||||
| @@ -264,6 +266,7 @@ describe('DocumentDetailComponent', () => { | ||||
|     customFieldsService = TestBed.inject(CustomFieldsService) | ||||
|     fixture = TestBed.createComponent(DocumentDetailComponent) | ||||
|     httpTestingController = TestBed.inject(HttpTestingController) | ||||
|     componentRouterService = TestBed.inject(ComponentRouterService) | ||||
|     component = fixture.componentInstance | ||||
|   }) | ||||
|  | ||||
| @@ -568,6 +571,16 @@ describe('DocumentDetailComponent', () => { | ||||
|     expect(navigateSpy).toHaveBeenCalledWith(['documents']) | ||||
|   }) | ||||
|  | ||||
|   it('should allow close and navigate to the last view if available', () => { | ||||
|     initNormally() | ||||
|     jest | ||||
|       .spyOn(componentRouterService, 'getComponentURLBefore') | ||||
|       .mockReturnValue('dashboard') | ||||
|     const navigateSpy = jest.spyOn(router, 'navigate') | ||||
|     component.close() | ||||
|     expect(navigateSpy).toHaveBeenCalledWith(['dashboard']) | ||||
|   }) | ||||
|  | ||||
|   it('should allow close and navigate to documents by default', () => { | ||||
|     initNormally() | ||||
|     jest | ||||
|   | ||||
| @@ -59,6 +59,7 @@ import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe' | ||||
| import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe' | ||||
| import { FileSizePipe } from 'src/app/pipes/file-size.pipe' | ||||
| import { SafeUrlPipe } from 'src/app/pipes/safeurl.pipe' | ||||
| import { ComponentRouterService } from 'src/app/services/component-router.service' | ||||
| import { DocumentListViewService } from 'src/app/services/document-list-view.service' | ||||
| import { HotKeyService } from 'src/app/services/hot-key.service' | ||||
| import { OpenDocumentsService } from 'src/app/services/open-documents.service' | ||||
| @@ -272,7 +273,8 @@ export class DocumentDetailComponent | ||||
|     private userService: UserService, | ||||
|     private customFieldsService: CustomFieldsService, | ||||
|     private http: HttpClient, | ||||
|     private hotKeyService: HotKeyService | ||||
|     private hotKeyService: HotKeyService, | ||||
|     private componentRouterService: ComponentRouterService | ||||
|   ) { | ||||
|     super() | ||||
|   } | ||||
| @@ -888,6 +890,10 @@ export class DocumentDetailComponent | ||||
|             'view', | ||||
|             this.documentListViewService.activeSavedViewId, | ||||
|           ]) | ||||
|         } else if (this.componentRouterService.getComponentURLBefore()) { | ||||
|           this.router.navigate([ | ||||
|             this.componentRouterService.getComponentURLBefore(), | ||||
|           ]) | ||||
|         } else { | ||||
|           this.router.navigate(['documents']) | ||||
|         } | ||||
|   | ||||
							
								
								
									
										102
									
								
								src-ui/src/app/services/component-router.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src-ui/src/app/services/component-router.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| import { TestBed } from '@angular/core/testing' | ||||
| import { ActivationStart, Router } from '@angular/router' | ||||
| import { Subject } from 'rxjs' | ||||
| import { ComponentRouterService } from './component-router.service' | ||||
|  | ||||
| describe('ComponentRouterService', () => { | ||||
|   let service: ComponentRouterService | ||||
|   let router: Router | ||||
|   let eventsSubject: Subject<any> | ||||
|  | ||||
|   beforeEach(() => { | ||||
|     eventsSubject = new Subject<any>() | ||||
|     TestBed.configureTestingModule({ | ||||
|       providers: [ | ||||
|         ComponentRouterService, | ||||
|         { | ||||
|           provide: Router, | ||||
|           useValue: { | ||||
|             events: eventsSubject.asObservable(), | ||||
|           }, | ||||
|         }, | ||||
|       ], | ||||
|     }) | ||||
|     service = TestBed.inject(ComponentRouterService) | ||||
|     router = TestBed.inject(Router) | ||||
|   }) | ||||
|  | ||||
|   it('should add to history and componentHistory on ActivationStart event', () => { | ||||
|     eventsSubject.next( | ||||
|       new ActivationStart({ | ||||
|         url: 'test-url', | ||||
|         component: { name: 'TestComponent' }, | ||||
|       } as any) | ||||
|     ) | ||||
|  | ||||
|     expect((service as any).history).toEqual(['test-url']) | ||||
|     expect((service as any).componentHistory).toEqual(['TestComponent']) | ||||
|   }) | ||||
|  | ||||
|   it('should not add duplicate component names to componentHistory', () => { | ||||
|     eventsSubject.next( | ||||
|       new ActivationStart({ | ||||
|         url: 'test-url-1', | ||||
|         component: { name: 'TestComponent' }, | ||||
|       } as any) | ||||
|     ) | ||||
|     eventsSubject.next( | ||||
|       new ActivationStart({ | ||||
|         url: 'test-url-2', | ||||
|         component: { name: 'TestComponent' }, | ||||
|       } as any) | ||||
|     ) | ||||
|  | ||||
|     expect((service as any).componentHistory.length).toBe(1) | ||||
|     expect((service as any).componentHistory).toEqual(['TestComponent']) | ||||
|   }) | ||||
|  | ||||
|   it('should return the URL of the component before the current one', () => { | ||||
|     eventsSubject.next( | ||||
|       new ActivationStart({ | ||||
|         url: 'test-url-1', | ||||
|         component: { name: 'TestComponent1' }, | ||||
|       } as any) | ||||
|     ) | ||||
|     eventsSubject.next( | ||||
|       new ActivationStart({ | ||||
|         url: 'test-url-2', | ||||
|         component: { name: 'TestComponent2' }, | ||||
|       } as any) | ||||
|     ) | ||||
|  | ||||
|     expect(service.getComponentURLBefore()).toBe('test-url-1') | ||||
|   }) | ||||
|  | ||||
|   it('should update the URL of the current component if the same component is loaded via a different URL', () => { | ||||
|     eventsSubject.next( | ||||
|       new ActivationStart({ | ||||
|         url: 'test-url-1', | ||||
|         component: { name: 'TestComponent' }, | ||||
|       } as any) | ||||
|     ) | ||||
|     eventsSubject.next( | ||||
|       new ActivationStart({ | ||||
|         url: 'test-url-2', | ||||
|         component: { name: 'TestComponent' }, | ||||
|       } as any) | ||||
|     ) | ||||
|  | ||||
|     expect((service as any).history).toEqual(['test-url-2']) | ||||
|   }) | ||||
|  | ||||
|   it('should return null if there is no previous component', () => { | ||||
|     eventsSubject.next( | ||||
|       new ActivationStart({ | ||||
|         url: 'test-url', | ||||
|         component: { name: 'TestComponent' }, | ||||
|       } as any) | ||||
|     ) | ||||
|  | ||||
|     expect(service.getComponentURLBefore()).toBeNull() | ||||
|   }) | ||||
| }) | ||||
							
								
								
									
										35
									
								
								src-ui/src/app/services/component-router.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src-ui/src/app/services/component-router.service.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| import { Injectable } from '@angular/core' | ||||
| import { ActivationStart, Event, Router } from '@angular/router' | ||||
| import { filter } from 'rxjs' | ||||
|  | ||||
| @Injectable({ | ||||
|   providedIn: 'root', | ||||
| }) | ||||
| export class ComponentRouterService { | ||||
|   private history: string[] = [] | ||||
|   private componentHistory: any[] = [] | ||||
|  | ||||
|   constructor(private router: Router) { | ||||
|     this.router.events | ||||
|       .pipe(filter((event: Event) => event instanceof ActivationStart)) | ||||
|       .subscribe((event: ActivationStart) => { | ||||
|         if ( | ||||
|           this.componentHistory[this.componentHistory.length - 1] !== | ||||
|           event.snapshot.component.name | ||||
|         ) { | ||||
|           this.history.push(event.snapshot.url.toString()) | ||||
|           this.componentHistory.push(event.snapshot.component.name) | ||||
|         } else { | ||||
|           // Update the URL of the current component in case the same component was loaded via a different URL | ||||
|           this.history[this.history.length - 1] = event.snapshot.url.toString() | ||||
|         } | ||||
|       }) | ||||
|   } | ||||
|  | ||||
|   public getComponentURLBefore(): any { | ||||
|     if (this.componentHistory.length > 1) { | ||||
|       return this.history[this.history.length - 2] | ||||
|     } | ||||
|     return null | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 shamoon
					shamoon