Skip to content

Commit 0175eab

Browse files
committed
Fix browser unsaved changes with custom guard
1 parent ca75fb5 commit 0175eab

File tree

7 files changed

+77
-32
lines changed

7 files changed

+77
-32
lines changed

src-ui/messages.xlf

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -179,21 +179,21 @@
179179
<source>Decrement hours</source>
180180
<context-group purpose="location">
181181
<context context-type="sourcefile">node_modules/src/timepicker/timepicker.ts</context>
182-
<context context-type="linenumber">240,243</context>
182+
<context context-type="linenumber">239,240</context>
183183
</context-group>
184184
</trans-unit>
185185
<trans-unit id="ngb.timepicker.increment-minutes" datatype="html">
186186
<source>Increment minutes</source>
187187
<context-group purpose="location">
188188
<context context-type="sourcefile">node_modules/src/timepicker/timepicker.ts</context>
189-
<context context-type="linenumber">268</context>
189+
<context context-type="linenumber">264,268</context>
190190
</context-group>
191191
</trans-unit>
192192
<trans-unit id="ngb.timepicker.decrement-minutes" datatype="html">
193193
<source>Decrement minutes</source>
194194
<context-group purpose="location">
195195
<context context-type="sourcefile">node_modules/src/timepicker/timepicker.ts</context>
196-
<context context-type="linenumber">288,289</context>
196+
<context context-type="linenumber">287,289</context>
197197
</context-group>
198198
</trans-unit>
199199
<trans-unit id="ngb.timepicker.SS" datatype="html">
@@ -1648,7 +1648,7 @@
16481648
<source>Confirm delete</source>
16491649
<context-group purpose="location">
16501650
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
1651-
<context context-type="linenumber">439</context>
1651+
<context context-type="linenumber">442</context>
16521652
</context-group>
16531653
<context-group purpose="location">
16541654
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
@@ -1659,35 +1659,35 @@
16591659
<source>Do you really want to delete document &quot;<x id="PH" equiv-text="this.document.title"/>&quot;?</source>
16601660
<context-group purpose="location">
16611661
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
1662-
<context context-type="linenumber">440</context>
1662+
<context context-type="linenumber">443</context>
16631663
</context-group>
16641664
</trans-unit>
16651665
<trans-unit id="6691075929777935948" datatype="html">
16661666
<source>The files for this document will be deleted permanently. This operation cannot be undone.</source>
16671667
<context-group purpose="location">
16681668
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
1669-
<context context-type="linenumber">441</context>
1669+
<context context-type="linenumber">444</context>
16701670
</context-group>
16711671
</trans-unit>
16721672
<trans-unit id="719892092227206532" datatype="html">
16731673
<source>Delete document</source>
16741674
<context-group purpose="location">
16751675
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
1676-
<context context-type="linenumber">443</context>
1676+
<context context-type="linenumber">446</context>
16771677
</context-group>
16781678
</trans-unit>
16791679
<trans-unit id="1844801255494293730" datatype="html">
16801680
<source>Error deleting document: <x id="PH" equiv-text="JSON.stringify(error)"/></source>
16811681
<context-group purpose="location">
16821682
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
1683-
<context context-type="linenumber">459</context>
1683+
<context context-type="linenumber">462</context>
16841684
</context-group>
16851685
</trans-unit>
16861686
<trans-unit id="7362691899087997122" datatype="html">
16871687
<source>Redo OCR confirm</source>
16881688
<context-group purpose="location">
16891689
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
1690-
<context context-type="linenumber">479</context>
1690+
<context context-type="linenumber">482</context>
16911691
</context-group>
16921692
<context-group purpose="location">
16931693
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -1698,14 +1698,14 @@
16981698
<source>This operation will permanently redo OCR for this document.</source>
16991699
<context-group purpose="location">
17001700
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
1701-
<context context-type="linenumber">480</context>
1701+
<context context-type="linenumber">483</context>
17021702
</context-group>
17031703
</trans-unit>
17041704
<trans-unit id="5641451190833696892" datatype="html">
17051705
<source>This operation cannot be undone.</source>
17061706
<context-group purpose="location">
17071707
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
1708-
<context context-type="linenumber">481</context>
1708+
<context context-type="linenumber">484</context>
17091709
</context-group>
17101710
<context-group purpose="location">
17111711
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -1720,7 +1720,7 @@
17201720
<source>Proceed</source>
17211721
<context-group purpose="location">
17221722
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
1723-
<context context-type="linenumber">483</context>
1723+
<context context-type="linenumber">486</context>
17241724
</context-group>
17251725
<context-group purpose="location">
17261726
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -1731,7 +1731,7 @@
17311731
<source>Redo OCR operation will begin in the background.</source>
17321732
<context-group purpose="location">
17331733
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
1734-
<context context-type="linenumber">491</context>
1734+
<context context-type="linenumber">494</context>
17351735
</context-group>
17361736
</trans-unit>
17371737
<trans-unit id="8008978164775353960" datatype="html">
@@ -1740,7 +1740,7 @@
17401740
)"/></source>
17411741
<context-group purpose="location">
17421742
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
1743-
<context context-type="linenumber">502,504</context>
1743+
<context context-type="linenumber">505,507</context>
17441744
</context-group>
17451745
</trans-unit>
17461746
<trans-unit id="6857598786757174736" datatype="html">
@@ -3200,6 +3200,13 @@
32003200
<context context-type="linenumber">39</context>
32013201
</context-group>
32023202
</trans-unit>
3203+
<trans-unit id="5948496158474272829" datatype="html">
3204+
<source>Warning: You have unsaved changes to your document(s).</source>
3205+
<context-group purpose="location">
3206+
<context context-type="sourcefile">src/app/guards/dirty-doc.guard.ts</context>
3207+
<context context-type="linenumber">18</context>
3208+
</context-group>
3209+
</trans-unit>
32033210
<trans-unit id="159901853873315050" datatype="html">
32043211
<source>Unsaved Changes</source>
32053212
<context-group purpose="location">
@@ -3208,11 +3215,11 @@
32083215
</context-group>
32093216
<context-group purpose="location">
32103217
<context context-type="sourcefile">src/app/services/open-documents.service.ts</context>
3211-
<context context-type="linenumber">111</context>
3218+
<context context-type="linenumber">116</context>
32123219
</context-group>
32133220
<context-group purpose="location">
32143221
<context context-type="sourcefile">src/app/services/open-documents.service.ts</context>
3215-
<context context-type="linenumber">138</context>
3222+
<context context-type="linenumber">143</context>
32163223
</context-group>
32173224
</trans-unit>
32183225
<trans-unit id="2573823578527613511" datatype="html">
@@ -3223,7 +3230,7 @@
32233230
</context-group>
32243231
<context-group purpose="location">
32253232
<context context-type="sourcefile">src/app/services/open-documents.service.ts</context>
3226-
<context context-type="linenumber">139</context>
3233+
<context context-type="linenumber">144</context>
32273234
</context-group>
32283235
</trans-unit>
32293236
<trans-unit id="3305084982600522070" datatype="html">
@@ -3360,35 +3367,35 @@
33603367
<source>You have unsaved changes to the document</source>
33613368
<context-group purpose="location">
33623369
<context context-type="sourcefile">src/app/services/open-documents.service.ts</context>
3363-
<context context-type="linenumber">113</context>
3370+
<context context-type="linenumber">118</context>
33643371
</context-group>
33653372
</trans-unit>
33663373
<trans-unit id="2089045849587358256" datatype="html">
33673374
<source>Are you sure you want to close this document?</source>
33683375
<context-group purpose="location">
33693376
<context context-type="sourcefile">src/app/services/open-documents.service.ts</context>
3370-
<context context-type="linenumber">117</context>
3377+
<context context-type="linenumber">122</context>
33713378
</context-group>
33723379
</trans-unit>
33733380
<trans-unit id="2885986061416655600" datatype="html">
33743381
<source>Close document</source>
33753382
<context-group purpose="location">
33763383
<context context-type="sourcefile">src/app/services/open-documents.service.ts</context>
3377-
<context context-type="linenumber">119</context>
3384+
<context context-type="linenumber">124</context>
33783385
</context-group>
33793386
</trans-unit>
33803387
<trans-unit id="6755718693176327396" datatype="html">
33813388
<source>Are you sure you want to close all documents?</source>
33823389
<context-group purpose="location">
33833390
<context context-type="sourcefile">src/app/services/open-documents.service.ts</context>
3384-
<context context-type="linenumber">140</context>
3391+
<context context-type="linenumber">145</context>
33853392
</context-group>
33863393
</trans-unit>
33873394
<trans-unit id="4215561719980781894" datatype="html">
33883395
<source>Close documents</source>
33893396
<context-group purpose="location">
33903397
<context context-type="sourcefile">src/app/services/open-documents.service.ts</context>
3391-
<context context-type="linenumber">142</context>
3398+
<context context-type="linenumber">147</context>
33923399
</context-group>
33933400
</trans-unit>
33943401
<trans-unit id="3553216189604488439" datatype="html">

src-ui/src/app/app-routing.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ import { DocumentAsnComponent } from './components/document-asn/document-asn.com
1414
import { DirtyFormGuard } from './guards/dirty-form.guard'
1515
import { StoragePathListComponent } from './components/manage/storage-path-list/storage-path-list.component'
1616
import { TasksComponent } from './components/manage/tasks/tasks.component'
17+
import { DirtyDocGuard } from './guards/dirty-doc.guard'
1718

1819
const routes: Routes = [
1920
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
2021
{
2122
path: '',
2223
component: AppFrameComponent,
24+
canDeactivate: [DirtyDocGuard],
2325
children: [
2426
{ path: 'dashboard', component: DashboardComponent },
2527
{ path: 'documents', component: DocumentListComponent },

src-ui/src/app/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ import { ApiVersionInterceptor } from './interceptors/api-version.interceptor'
6767
import { ColorSliderModule } from 'ngx-color/slider'
6868
import { ColorComponent } from './components/common/input/color/color.component'
6969
import { DocumentAsnComponent } from './components/document-asn/document-asn.component'
70+
import { DirtyDocGuard } from './guards/dirty-doc.guard'
7071

7172
import localeBe from '@angular/common/locales/be'
7273
import localeCs from '@angular/common/locales/cs'
@@ -209,6 +210,7 @@ function initializeApp(settings: SettingsService) {
209210
DocumentTitlePipe,
210211
{ provide: NgbDateAdapter, useClass: ISODateAdapter },
211212
{ provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter },
213+
DirtyDocGuard,
212214
],
213215
bootstrap: [AppComponent],
214216
})

src-ui/src/app/components/app-frame/app-frame.component.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Component } from '@angular/core'
1+
import { Component, HostListener } from '@angular/core'
22
import { FormControl } from '@angular/forms'
3-
import { ActivatedRoute, Router, Params } from '@angular/router'
3+
import { ActivatedRoute, Router } from '@angular/router'
44
import { from, Observable } from 'rxjs'
55
import {
66
debounceTime,
@@ -23,13 +23,14 @@ import {
2323
} from 'src/app/services/rest/remote-version.service'
2424
import { SettingsService } from 'src/app/services/settings.service'
2525
import { TasksService } from 'src/app/services/tasks.service'
26+
import { ComponentCanDeactivate } from 'src/app/guards/dirty-doc.guard'
2627

2728
@Component({
2829
selector: 'app-app-frame',
2930
templateUrl: './app-frame.component.html',
3031
styleUrls: ['./app-frame.component.scss'],
3132
})
32-
export class AppFrameComponent {
33+
export class AppFrameComponent implements ComponentCanDeactivate {
3334
constructor(
3435
public router: Router,
3536
private activatedRoute: ActivatedRoute,
@@ -64,6 +65,11 @@ export class AppFrameComponent {
6465
return this.openDocumentsService.getOpenDocuments()
6566
}
6667

68+
@HostListener('window:beforeunload')
69+
canDeactivate(): Observable<boolean> | boolean {
70+
return !this.openDocumentsService.hasDirty()
71+
}
72+
6773
searchAutoComplete = (text$: Observable<string>) =>
6874
text$.pipe(
6975
debounceTime(200),

src-ui/src/app/components/document-detail/document-detail.component.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ export class DocumentDetailComponent
206206
this.store.getValue().title !==
207207
this.documentForm.get('title').value
208208
) {
209-
this.openDocumentService.setDirty(doc.id, true)
209+
this.openDocumentService.setDirty(doc, true)
210210
}
211211
},
212212
})
@@ -228,12 +228,15 @@ export class DocumentDetailComponent
228228
this.store.asObservable()
229229
)
230230

231-
return this.isDirty$.pipe(map((dirty) => ({ doc, dirty })))
231+
return this.isDirty$.pipe(
232+
takeUntil(this.unsubscribeNotifier),
233+
map((dirty) => ({ doc, dirty }))
234+
)
232235
})
233236
)
234237
.subscribe({
235238
next: ({ doc, dirty }) => {
236-
this.openDocumentService.setDirty(doc.id, dirty)
239+
this.openDocumentService.setDirty(doc, dirty)
237240
},
238241
error: (error) => {
239242
this.router.navigate(['404'])
@@ -349,7 +352,7 @@ export class DocumentDetailComponent
349352
Object.assign(this.document, doc)
350353
this.title = doc.title
351354
this.documentForm.patchValue(doc)
352-
this.openDocumentService.setDirty(doc.id, false)
355+
this.openDocumentService.setDirty(doc, false)
353356
},
354357
error: () => {
355358
this.router.navigate(['404'])
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { CanDeactivate } from '@angular/router'
2+
import { Injectable } from '@angular/core'
3+
import { Observable } from 'rxjs'
4+
5+
export interface ComponentCanDeactivate {
6+
canDeactivate: () => boolean | Observable<boolean>
7+
}
8+
9+
@Injectable()
10+
export class DirtyDocGuard implements CanDeactivate<ComponentCanDeactivate> {
11+
canDeactivate(
12+
component: ComponentCanDeactivate
13+
): boolean | Observable<boolean> {
14+
return component.canDeactivate()
15+
? true
16+
: confirm(
17+
$localize`Warning: You have unsaved changes to your document(s).`
18+
)
19+
}
20+
}

src-ui/src/app/services/open-documents.service.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,14 @@ export class OpenDocumentsService {
9292
}
9393
}
9494

95-
setDirty(documentId: number, dirty: boolean) {
96-
if (dirty) this.dirtyDocuments.add(documentId)
97-
else this.dirtyDocuments.delete(documentId)
95+
setDirty(doc: PaperlessDocument, dirty: boolean) {
96+
if (!this.openDocuments.find((d) => d.id == doc.id)) return
97+
if (dirty) this.dirtyDocuments.add(doc.id)
98+
else this.dirtyDocuments.delete(doc.id)
99+
}
100+
101+
hasDirty(): boolean {
102+
return this.dirtyDocuments.size > 0
98103
}
99104

100105
closeDocument(doc: PaperlessDocument): Observable<boolean> {

0 commit comments

Comments
 (0)