mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-31 02:27:10 -04:00 
			
		
		
		
	Settings navigation warning dialog
This commit is contained in:
		
							parent
							
								
									6c5f9bbabb
								
							
						
					
					
						commit
						b0fa0f2319
					
				| @ -11,6 +11,7 @@ import { SettingsComponent } from './components/manage/settings/settings.compone | |||||||
| import { TagListComponent } from './components/manage/tag-list/tag-list.component'; | import { TagListComponent } from './components/manage/tag-list/tag-list.component'; | ||||||
| import { NotFoundComponent } from './components/not-found/not-found.component'; | import { NotFoundComponent } from './components/not-found/not-found.component'; | ||||||
| import { SearchComponent } from './components/search/search.component'; | import { SearchComponent } from './components/search/search.component'; | ||||||
|  | import { FormDirtyGuard } from './guards/dirty-form.guard'; | ||||||
| 
 | 
 | ||||||
| const routes: Routes = [ | const routes: Routes = [ | ||||||
|   {path: '', redirectTo: 'dashboard', pathMatch: 'full'}, |   {path: '', redirectTo: 'dashboard', pathMatch: 'full'}, | ||||||
| @ -25,7 +26,7 @@ const routes: Routes = [ | |||||||
|     {path: 'documenttypes', component: DocumentTypeListComponent }, |     {path: 'documenttypes', component: DocumentTypeListComponent }, | ||||||
|     {path: 'correspondents', component: CorrespondentListComponent }, |     {path: 'correspondents', component: CorrespondentListComponent }, | ||||||
|     {path: 'logs', component: LogsComponent }, |     {path: 'logs', component: LogsComponent }, | ||||||
|     {path: 'settings', component: SettingsComponent }, |     {path: 'settings', component: SettingsComponent, canDeactivate: [FormDirtyGuard] }, | ||||||
|   ]}, |   ]}, | ||||||
| 
 | 
 | ||||||
|   {path: '404', component: NotFoundComponent}, |   {path: '404', component: NotFoundComponent}, | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
|     <div class="modal-header"> |     <div class="modal-header"> | ||||||
|       <h4 class="modal-title" id="modal-basic-title">{{title}}</h4> |       <h4 class="modal-title" id="modal-basic-title">{{title}}</h4> | ||||||
|       <button type="button" class="close" aria-label="Close" (click)="cancelClicked()"> |       <button type="button" class="close" aria-label="Close" (click)="cancel()"> | ||||||
|         <span aria-hidden="true">×</span> |         <span aria-hidden="true">×</span> | ||||||
|       </button> |       </button> | ||||||
|     </div> |     </div> | ||||||
| @ -9,8 +9,8 @@ | |||||||
|       <p *ngIf="message">{{message}}</p> |       <p *ngIf="message">{{message}}</p> | ||||||
|     </div> |     </div> | ||||||
|     <div class="modal-footer"> |     <div class="modal-footer"> | ||||||
|       <button type="button" class="btn btn-outline-dark" (click)="cancelClicked()" [disabled]="!buttonsEnabled" i18n>Cancel</button> |       <button type="button" class="btn btn-outline-dark" (click)="cancel()" [disabled]="!buttonsEnabled" i18n>Cancel</button> | ||||||
|       <button type="button" class="btn" [class]="btnClass" (click)="confirmClicked.emit()" [disabled]="!confirmButtonEnabled || !buttonsEnabled"> |       <button type="button" class="btn" [class]="btnClass" (click)="confirm()" [disabled]="!confirmButtonEnabled || !buttonsEnabled"> | ||||||
|         {{btnCaption}} |         {{btnCaption}} | ||||||
|         <span *ngIf="!confirmButtonEnabled"> ({{seconds}})</span> |         <span *ngIf="!confirmButtonEnabled"> ({{seconds}})</span> | ||||||
|       </button> |       </button> | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; | import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; | ||||||
| import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; | import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; | ||||||
|  | import { Subject } from 'rxjs'; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-confirm-dialog', |   selector: 'app-confirm-dialog', | ||||||
| @ -8,8 +9,6 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; | |||||||
| }) | }) | ||||||
| export class ConfirmDialogComponent implements OnInit { | export class ConfirmDialogComponent implements OnInit { | ||||||
| 
 | 
 | ||||||
|   constructor(public activeModal: NgbActiveModal) { } |  | ||||||
| 
 |  | ||||||
|   @Output() |   @Output() | ||||||
|   public confirmClicked = new EventEmitter() |   public confirmClicked = new EventEmitter() | ||||||
| 
 | 
 | ||||||
| @ -34,6 +33,12 @@ export class ConfirmDialogComponent implements OnInit { | |||||||
|   confirmButtonEnabled = true |   confirmButtonEnabled = true | ||||||
|   seconds = 0 |   seconds = 0 | ||||||
| 
 | 
 | ||||||
|  |   subject: Subject<boolean> | ||||||
|  | 
 | ||||||
|  |   constructor(public activeModal: NgbActiveModal) { | ||||||
|  |     this.confirmClicked.asObservable() | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   delayConfirm(seconds: number) { |   delayConfirm(seconds: number) { | ||||||
|     this.confirmButtonEnabled = false |     this.confirmButtonEnabled = false | ||||||
|     this.seconds = seconds |     this.seconds = seconds | ||||||
| @ -49,7 +54,15 @@ export class ConfirmDialogComponent implements OnInit { | |||||||
|   ngOnInit(): void { |   ngOnInit(): void { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   cancelClicked() { |   cancel() { | ||||||
|  |     this.subject?.next(false) | ||||||
|  |     this.subject?.complete() | ||||||
|     this.activeModal.close() |     this.activeModal.close() | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   confirm() { | ||||||
|  |     this.subject?.next(true) | ||||||
|  |     this.subject?.complete() | ||||||
|  |     this.confirmClicked.emit() | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -32,9 +32,9 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent { | |||||||
| 
 | 
 | ||||||
|   savedViews: PaperlessSavedView[] |   savedViews: PaperlessSavedView[] | ||||||
| 
 | 
 | ||||||
|   store: BehaviorSubject<any>; |   store: BehaviorSubject<any> | ||||||
|   storeSub: Subscription; |   storeSub: Subscription | ||||||
|   isDirty$: Observable<boolean>; |   isDirty$: Observable<boolean> | ||||||
| 
 | 
 | ||||||
|   get computedDateLocale(): string { |   get computedDateLocale(): string { | ||||||
|     return this.settingsForm.value.dateLocale || this.settingsForm.value.displayLanguage |     return this.settingsForm.value.dateLocale || this.settingsForm.value.displayLanguage | ||||||
| @ -82,10 +82,10 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent { | |||||||
| 
 | 
 | ||||||
|       this.storeSub = this.store.asObservable().subscribe(state => { |       this.storeSub = this.store.asObservable().subscribe(state => { | ||||||
|         this.settingsForm.patchValue(state, { emitEvent: false }) |         this.settingsForm.patchValue(state, { emitEvent: false }) | ||||||
|       }); |       }) | ||||||
| 
 | 
 | ||||||
|       // Initialize dirtyCheck
 |       // Initialize dirtyCheck
 | ||||||
|       this.isDirty$ = dirtyCheck(this.settingsForm, this.store.asObservable()); |       this.isDirty$ = dirtyCheck(this.settingsForm, this.store.asObservable()) | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										29
									
								
								src-ui/src/app/guards/dirty-form.guard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src-ui/src/app/guards/dirty-form.guard.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | import { Injectable } from '@angular/core'; | ||||||
|  | import { DirtyCheckGuard } from '@ngneat/dirty-check-forms'; | ||||||
|  | import { Observable, Subject } from 'rxjs'; | ||||||
|  | import { map } from 'rxjs/operators'; | ||||||
|  | import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; | ||||||
|  | import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component'; | ||||||
|  | 
 | ||||||
|  | @Injectable({ providedIn: 'root' }) | ||||||
|  | export class FormDirtyGuard extends DirtyCheckGuard { | ||||||
|  |   constructor(private modalService: NgbModal) { | ||||||
|  |     super(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   confirmChanges(): Observable<boolean> { | ||||||
|  |     let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) | ||||||
|  |     modal.componentInstance.title = $localize`Confirm` | ||||||
|  |     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`Ok` | ||||||
|  |     modal.componentInstance.confirmClicked.subscribe(() => { | ||||||
|  |       modal.componentInstance.buttonsEnabled = false | ||||||
|  |       modal.close() | ||||||
|  |     }) | ||||||
|  |     const subject = new Subject<boolean>() | ||||||
|  |     modal.componentInstance.subject = subject | ||||||
|  |     return subject.asObservable() | ||||||
|  |   } | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user