mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Merge pull request #1369 from paperless-ngx/fix/browser-unsaved-changes
Fix: Correct browser unsaved changes warning
This commit is contained in:
@@ -14,12 +14,14 @@ import { DocumentAsnComponent } from './components/document-asn/document-asn.com
|
||||
import { DirtyFormGuard } from './guards/dirty-form.guard'
|
||||
import { StoragePathListComponent } from './components/manage/storage-path-list/storage-path-list.component'
|
||||
import { TasksComponent } from './components/manage/tasks/tasks.component'
|
||||
import { DirtyDocGuard } from './guards/dirty-doc.guard'
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
|
||||
{
|
||||
path: '',
|
||||
component: AppFrameComponent,
|
||||
canDeactivate: [DirtyDocGuard],
|
||||
children: [
|
||||
{ path: 'dashboard', component: DashboardComponent },
|
||||
{ path: 'documents', component: DocumentListComponent },
|
||||
|
@@ -67,6 +67,7 @@ import { ApiVersionInterceptor } from './interceptors/api-version.interceptor'
|
||||
import { ColorSliderModule } from 'ngx-color/slider'
|
||||
import { ColorComponent } from './components/common/input/color/color.component'
|
||||
import { DocumentAsnComponent } from './components/document-asn/document-asn.component'
|
||||
import { DirtyDocGuard } from './guards/dirty-doc.guard'
|
||||
|
||||
import localeBe from '@angular/common/locales/be'
|
||||
import localeCs from '@angular/common/locales/cs'
|
||||
@@ -209,6 +210,7 @@ function initializeApp(settings: SettingsService) {
|
||||
DocumentTitlePipe,
|
||||
{ provide: NgbDateAdapter, useClass: ISODateAdapter },
|
||||
{ provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter },
|
||||
DirtyDocGuard,
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { Component, HostListener } from '@angular/core'
|
||||
import { FormControl } from '@angular/forms'
|
||||
import { ActivatedRoute, Router, Params } from '@angular/router'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { from, Observable } from 'rxjs'
|
||||
import {
|
||||
debounceTime,
|
||||
@@ -23,13 +23,14 @@ import {
|
||||
} from 'src/app/services/rest/remote-version.service'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { TasksService } from 'src/app/services/tasks.service'
|
||||
import { ComponentCanDeactivate } from 'src/app/guards/dirty-doc.guard'
|
||||
|
||||
@Component({
|
||||
selector: 'app-app-frame',
|
||||
templateUrl: './app-frame.component.html',
|
||||
styleUrls: ['./app-frame.component.scss'],
|
||||
})
|
||||
export class AppFrameComponent {
|
||||
export class AppFrameComponent implements ComponentCanDeactivate {
|
||||
constructor(
|
||||
public router: Router,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
@@ -64,6 +65,11 @@ export class AppFrameComponent {
|
||||
return this.openDocumentsService.getOpenDocuments()
|
||||
}
|
||||
|
||||
@HostListener('window:beforeunload')
|
||||
canDeactivate(): Observable<boolean> | boolean {
|
||||
return !this.openDocumentsService.hasDirty()
|
||||
}
|
||||
|
||||
searchAutoComplete = (text$: Observable<string>) =>
|
||||
text$.pipe(
|
||||
debounceTime(200),
|
||||
|
@@ -206,7 +206,7 @@ export class DocumentDetailComponent
|
||||
this.store.getValue().title !==
|
||||
this.documentForm.get('title').value
|
||||
) {
|
||||
this.openDocumentService.setDirty(doc.id, true)
|
||||
this.openDocumentService.setDirty(doc, true)
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -228,12 +228,15 @@ export class DocumentDetailComponent
|
||||
this.store.asObservable()
|
||||
)
|
||||
|
||||
return this.isDirty$.pipe(map((dirty) => ({ doc, dirty })))
|
||||
return this.isDirty$.pipe(
|
||||
takeUntil(this.unsubscribeNotifier),
|
||||
map((dirty) => ({ doc, dirty }))
|
||||
)
|
||||
})
|
||||
)
|
||||
.subscribe({
|
||||
next: ({ doc, dirty }) => {
|
||||
this.openDocumentService.setDirty(doc.id, dirty)
|
||||
this.openDocumentService.setDirty(doc, dirty)
|
||||
},
|
||||
error: (error) => {
|
||||
this.router.navigate(['404'])
|
||||
@@ -349,7 +352,7 @@ export class DocumentDetailComponent
|
||||
Object.assign(this.document, doc)
|
||||
this.title = doc.title
|
||||
this.documentForm.patchValue(doc)
|
||||
this.openDocumentService.setDirty(doc.id, false)
|
||||
this.openDocumentService.setDirty(doc, false)
|
||||
},
|
||||
error: () => {
|
||||
this.router.navigate(['404'])
|
||||
|
20
src-ui/src/app/guards/dirty-doc.guard.ts
Normal file
20
src-ui/src/app/guards/dirty-doc.guard.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { CanDeactivate } from '@angular/router'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { Observable } from 'rxjs'
|
||||
|
||||
export interface ComponentCanDeactivate {
|
||||
canDeactivate: () => boolean | Observable<boolean>
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class DirtyDocGuard implements CanDeactivate<ComponentCanDeactivate> {
|
||||
canDeactivate(
|
||||
component: ComponentCanDeactivate
|
||||
): boolean | Observable<boolean> {
|
||||
return component.canDeactivate()
|
||||
? true
|
||||
: confirm(
|
||||
$localize`Warning: You have unsaved changes to your document(s).`
|
||||
)
|
||||
}
|
||||
}
|
@@ -92,9 +92,14 @@ export class OpenDocumentsService {
|
||||
}
|
||||
}
|
||||
|
||||
setDirty(documentId: number, dirty: boolean) {
|
||||
if (dirty) this.dirtyDocuments.add(documentId)
|
||||
else this.dirtyDocuments.delete(documentId)
|
||||
setDirty(doc: PaperlessDocument, dirty: boolean) {
|
||||
if (!this.openDocuments.find((d) => d.id == doc.id)) return
|
||||
if (dirty) this.dirtyDocuments.add(doc.id)
|
||||
else this.dirtyDocuments.delete(doc.id)
|
||||
}
|
||||
|
||||
hasDirty(): boolean {
|
||||
return this.dirtyDocuments.size > 0
|
||||
}
|
||||
|
||||
closeDocument(doc: PaperlessDocument): Observable<boolean> {
|
||||
|
Reference in New Issue
Block a user