mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Refactor document form handling and loading logic
This commit is contained in:
		| @@ -327,19 +327,145 @@ export class DocumentDetailComponent | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private mapDocToForm(doc: Document): any { | ||||||
|  |     return { | ||||||
|  |       ...doc, | ||||||
|  |       permissions_form: { owner: doc.owner, set_permissions: doc.permissions }, | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private mapFormToDoc(value: any): any { | ||||||
|  |     const docValues = { ...value } | ||||||
|  |     docValues['owner'] = value['permissions_form']?.owner | ||||||
|  |     docValues['set_permissions'] = value['permissions_form']?.set_permissions | ||||||
|  |     delete docValues['permissions_form'] | ||||||
|  |     return docValues | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private prepareForm(doc: Document): void { | ||||||
|  |     this.documentForm.reset(this.mapDocToForm(doc), { emitEvent: false }) | ||||||
|  |     if (!this.userCanEdit) { | ||||||
|  |       this.documentForm.disable({ emitEvent: false }) | ||||||
|  |     } else { | ||||||
|  |       this.documentForm.enable({ emitEvent: false }) | ||||||
|  |     } | ||||||
|  |     if (doc.__changedFields) { | ||||||
|  |       doc.__changedFields.forEach((field) => { | ||||||
|  |         if (field === 'owner' || field === 'set_permissions') { | ||||||
|  |           this.documentForm.get('permissions_form')?.markAsDirty() | ||||||
|  |         } else { | ||||||
|  |           this.documentForm.get(field)?.markAsDirty() | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private setupDirtyTracking( | ||||||
|  |     currentDocument: Document, | ||||||
|  |     originalDocument: Document | ||||||
|  |   ): void { | ||||||
|  |     this.store = new BehaviorSubject({ | ||||||
|  |       title: originalDocument.title, | ||||||
|  |       content: originalDocument.content, | ||||||
|  |       created: originalDocument.created, | ||||||
|  |       correspondent: originalDocument.correspondent, | ||||||
|  |       document_type: originalDocument.document_type, | ||||||
|  |       storage_path: originalDocument.storage_path, | ||||||
|  |       archive_serial_number: originalDocument.archive_serial_number, | ||||||
|  |       tags: [...originalDocument.tags], | ||||||
|  |       permissions_form: { | ||||||
|  |         owner: originalDocument.owner, | ||||||
|  |         set_permissions: originalDocument.permissions, | ||||||
|  |       }, | ||||||
|  |       custom_fields: [...originalDocument.custom_fields], | ||||||
|  |     }) | ||||||
|  |     this.isDirty$ = dirtyCheck(this.documentForm, this.store.asObservable()) | ||||||
|  |     this.isDirty$ | ||||||
|  |       .pipe( | ||||||
|  |         takeUntil(this.unsubscribeNotifier), | ||||||
|  |         takeUntil(this.docChangeNotifier) | ||||||
|  |       ) | ||||||
|  |       .subscribe((dirty) => | ||||||
|  |         this.openDocumentService.setDirty( | ||||||
|  |           currentDocument, | ||||||
|  |           dirty, | ||||||
|  |           this.getChangedFields() | ||||||
|  |         ) | ||||||
|  |       ) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private loadDocument(documentId: number): void { | ||||||
|  |     this.previewUrl = this.documentsService.getPreviewUrl(documentId) | ||||||
|  |     this.http.get(this.previewUrl, { responseType: 'text' }).subscribe({ | ||||||
|  |       next: (res) => (this.previewText = res.toString()), | ||||||
|  |       error: (err) => | ||||||
|  |         (this.previewText = $localize`An error occurred loading content: ${ | ||||||
|  |           err.message ?? err.toString() | ||||||
|  |         }`), | ||||||
|  |     }) | ||||||
|  |     this.thumbUrl = this.documentsService.getThumbUrl(documentId) | ||||||
|  |     this.documentsService | ||||||
|  |       .get(documentId) | ||||||
|  |       .pipe(first()) | ||||||
|  |       .subscribe({ | ||||||
|  |         next: (doc) => { | ||||||
|  |           if (!doc) { | ||||||
|  |             this.router.navigate(['404'], { replaceUrl: true }) | ||||||
|  |             return | ||||||
|  |           } | ||||||
|  |           this.documentId = doc.id | ||||||
|  |           this.suggestions = null | ||||||
|  |           const openDocument = this.openDocumentService.getOpenDocument( | ||||||
|  |             this.documentId | ||||||
|  |           ) | ||||||
|  |           const useDoc = openDocument || doc | ||||||
|  |           if (openDocument) { | ||||||
|  |             if ( | ||||||
|  |               new Date(doc.modified) > new Date(openDocument.modified) && | ||||||
|  |               !this.modalService.hasOpenModals() | ||||||
|  |             ) { | ||||||
|  |               const modal = this.modalService.open(ConfirmDialogComponent) | ||||||
|  |               modal.componentInstance.title = $localize`Document changes detected` | ||||||
|  |               modal.componentInstance.messageBold = $localize`The version of this document in your browser session appears older than the existing version.` | ||||||
|  |               modal.componentInstance.message = $localize`Saving the document here may overwrite other changes that were made. To restore the existing version, discard your changes or close the document.` | ||||||
|  |               modal.componentInstance.cancelBtnClass = 'visually-hidden' | ||||||
|  |               modal.componentInstance.btnCaption = $localize`Ok` | ||||||
|  |               modal.componentInstance.confirmClicked.subscribe(() => | ||||||
|  |                 modal.close() | ||||||
|  |               ) | ||||||
|  |             } | ||||||
|  |           } else { | ||||||
|  |             this.openDocumentService.openDocument(doc).pipe(first()).subscribe() | ||||||
|  |           } | ||||||
|  |           this.updateComponent(useDoc) | ||||||
|  |           this.titleSubject | ||||||
|  |             .pipe( | ||||||
|  |               debounceTime(1000), | ||||||
|  |               distinctUntilChanged(), | ||||||
|  |               takeUntil(this.docChangeNotifier), | ||||||
|  |               takeUntil(this.unsubscribeNotifier) | ||||||
|  |             ) | ||||||
|  |             .subscribe((titleValue) => { | ||||||
|  |               if (titleValue !== this.titleInput.value) return | ||||||
|  |               this.title = titleValue | ||||||
|  |               this.documentForm.patchValue({ title: titleValue }) | ||||||
|  |             }) | ||||||
|  |           this.setupDirtyTracking(useDoc, doc) | ||||||
|  |         }, | ||||||
|  |         error: () => | ||||||
|  |           this.router.navigate(['404'], { | ||||||
|  |             replaceUrl: true, | ||||||
|  |           }), | ||||||
|  |       }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|   ngOnInit(): void { |   ngOnInit(): void { | ||||||
|     this.setZoom(this.settings.get(SETTINGS_KEYS.PDF_VIEWER_ZOOM_SETTING)) |     this.setZoom(this.settings.get(SETTINGS_KEYS.PDF_VIEWER_ZOOM_SETTING)) | ||||||
|     this.documentForm.valueChanges |     this.documentForm.valueChanges | ||||||
|       .pipe(takeUntil(this.unsubscribeNotifier)) |       .pipe(takeUntil(this.unsubscribeNotifier)) | ||||||
|       .subscribe(() => { |       .subscribe((values) => { | ||||||
|         this.error = null |         this.error = null | ||||||
|         const docValues = Object.assign({}, this.documentForm.value) |         Object.assign(this.document, this.mapFormToDoc(values)) | ||||||
|         docValues['owner'] = |  | ||||||
|           this.documentForm.get('permissions_form').value['owner'] |  | ||||||
|         docValues['set_permissions'] = |  | ||||||
|           this.documentForm.get('permissions_form').value['set_permissions'] |  | ||||||
|         delete docValues['permissions_form'] |  | ||||||
|         Object.assign(this.document, docValues) |  | ||||||
|       }) |       }) | ||||||
|  |  | ||||||
|     if ( |     if ( | ||||||
| @@ -391,154 +517,17 @@ export class DocumentDetailComponent | |||||||
|  |  | ||||||
|     this.route.paramMap |     this.route.paramMap | ||||||
|       .pipe( |       .pipe( | ||||||
|         filter((paramMap) => { |         filter( | ||||||
|           // only init when changing docs & section is set |           (paramMap) => | ||||||
|           return ( |  | ||||||
|             +paramMap.get('id') !== this.documentId && |             +paramMap.get('id') !== this.documentId && | ||||||
|             paramMap.get('section')?.length > 0 |             paramMap.get('section')?.length > 0 | ||||||
|           ) |         ), | ||||||
|         }), |         takeUntil(this.unsubscribeNotifier) | ||||||
|         takeUntil(this.unsubscribeNotifier), |  | ||||||
|         switchMap((paramMap) => { |  | ||||||
|           const documentId = +paramMap.get('id') |  | ||||||
|           this.docChangeNotifier.next(documentId) |  | ||||||
|           // Dont wait to get the preview |  | ||||||
|           this.previewUrl = this.documentsService.getPreviewUrl(documentId) |  | ||||||
|           this.http.get(this.previewUrl, { responseType: 'text' }).subscribe({ |  | ||||||
|             next: (res) => { |  | ||||||
|               this.previewText = res.toString() |  | ||||||
|             }, |  | ||||||
|             error: (err) => { |  | ||||||
|               this.previewText = $localize`An error occurred loading content: ${ |  | ||||||
|                 err.message ?? err.toString() |  | ||||||
|               }` |  | ||||||
|             }, |  | ||||||
|           }) |  | ||||||
|           this.thumbUrl = this.documentsService.getThumbUrl(documentId) |  | ||||||
|           return this.documentsService.get(documentId) |  | ||||||
|         }) |  | ||||||
|       ) |       ) | ||||||
|       .pipe( |       .subscribe((paramMap) => { | ||||||
|         switchMap((doc) => { |         const documentId = +paramMap.get('id') | ||||||
|           this.documentId = doc.id |         this.docChangeNotifier.next(documentId) | ||||||
|           this.suggestions = null |         this.loadDocument(documentId) | ||||||
|           const openDocument = this.openDocumentService.getOpenDocument( |  | ||||||
|             this.documentId |  | ||||||
|           ) |  | ||||||
|  |  | ||||||
|           if (openDocument) { |  | ||||||
|             if ( |  | ||||||
|               new Date(doc.modified) > new Date(openDocument.modified) && |  | ||||||
|               !this.modalService.hasOpenModals() |  | ||||||
|             ) { |  | ||||||
|               let modal = this.modalService.open(ConfirmDialogComponent) |  | ||||||
|               modal.componentInstance.title = $localize`Document changes detected` |  | ||||||
|               modal.componentInstance.messageBold = $localize`The version of this document in your browser session appears older than the existing version.` |  | ||||||
|               modal.componentInstance.message = $localize`Saving the document here may overwrite other changes that were made. To restore the existing version, discard your changes or close the document.` |  | ||||||
|               modal.componentInstance.cancelBtnClass = 'visually-hidden' |  | ||||||
|               modal.componentInstance.btnCaption = $localize`Ok` |  | ||||||
|               modal.componentInstance.confirmClicked.subscribe(() => |  | ||||||
|                 modal.close() |  | ||||||
|               ) |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             // Prevent mutating stale form values into the next document: only sync if it still matches the active document. |  | ||||||
|             if ( |  | ||||||
|               this.documentForm.dirty && |  | ||||||
|               (this.document?.id === openDocument.id || !this.document) |  | ||||||
|             ) { |  | ||||||
|               Object.assign(openDocument, this.documentForm.value) |  | ||||||
|               openDocument['owner'] = |  | ||||||
|                 this.documentForm.get('permissions_form').value['owner'] |  | ||||||
|               openDocument['permissions'] = |  | ||||||
|                 this.documentForm.get('permissions_form').value[ |  | ||||||
|                   'set_permissions' |  | ||||||
|                 ] |  | ||||||
|               delete openDocument['permissions_form'] |  | ||||||
|             } |  | ||||||
|             if (openDocument.__changedFields) { |  | ||||||
|               openDocument.__changedFields.forEach((field) => { |  | ||||||
|                 if (field === 'owner' || field === 'set_permissions') { |  | ||||||
|                   this.documentForm.get('permissions_form').markAsDirty() |  | ||||||
|                 } else { |  | ||||||
|                   this.documentForm.get(field)?.markAsDirty() |  | ||||||
|                 } |  | ||||||
|               }) |  | ||||||
|             } |  | ||||||
|             this.updateComponent(openDocument) |  | ||||||
|           } else { |  | ||||||
|             this.openDocumentService.openDocument(doc) |  | ||||||
|             this.updateComponent(doc) |  | ||||||
|           } |  | ||||||
|  |  | ||||||
|           this.titleSubject |  | ||||||
|             .pipe( |  | ||||||
|               debounceTime(1000), |  | ||||||
|               distinctUntilChanged(), |  | ||||||
|               takeUntil(this.docChangeNotifier), |  | ||||||
|               takeUntil(this.unsubscribeNotifier) |  | ||||||
|             ) |  | ||||||
|             .subscribe({ |  | ||||||
|               next: (titleValue) => { |  | ||||||
|                 // In the rare case when the field changed just after debounced event was fired. |  | ||||||
|                 // We dont want to overwrite what's actually in the text field, so just return |  | ||||||
|                 if (titleValue !== this.titleInput.value) return |  | ||||||
|  |  | ||||||
|                 this.title = titleValue |  | ||||||
|                 this.documentForm.patchValue({ title: titleValue }) |  | ||||||
|               }, |  | ||||||
|               complete: () => { |  | ||||||
|                 // doc changed so we manually check dirty in case title was changed |  | ||||||
|                 if ( |  | ||||||
|                   this.store.getValue().title !== |  | ||||||
|                   this.documentForm.get('title').value |  | ||||||
|                 ) { |  | ||||||
|                   this.openDocumentService.setDirty( |  | ||||||
|                     doc, |  | ||||||
|                     true, |  | ||||||
|                     this.getChangedFields() |  | ||||||
|                   ) |  | ||||||
|                 } |  | ||||||
|               }, |  | ||||||
|             }) |  | ||||||
|  |  | ||||||
|           // Initialize dirtyCheck |  | ||||||
|           this.store = new BehaviorSubject({ |  | ||||||
|             title: doc.title, |  | ||||||
|             content: doc.content, |  | ||||||
|             created: doc.created, |  | ||||||
|             correspondent: doc.correspondent, |  | ||||||
|             document_type: doc.document_type, |  | ||||||
|             storage_path: doc.storage_path, |  | ||||||
|             archive_serial_number: doc.archive_serial_number, |  | ||||||
|             tags: [...doc.tags], |  | ||||||
|             permissions_form: { |  | ||||||
|               owner: doc.owner, |  | ||||||
|               set_permissions: doc.permissions, |  | ||||||
|             }, |  | ||||||
|             custom_fields: [...doc.custom_fields], |  | ||||||
|           }) |  | ||||||
|  |  | ||||||
|           this.isDirty$ = dirtyCheck( |  | ||||||
|             this.documentForm, |  | ||||||
|             this.store.asObservable() |  | ||||||
|           ) |  | ||||||
|  |  | ||||||
|           return this.isDirty$.pipe( |  | ||||||
|             takeUntil(this.unsubscribeNotifier), |  | ||||||
|             map((dirty) => ({ doc, dirty })) |  | ||||||
|           ) |  | ||||||
|         }) |  | ||||||
|       ) |  | ||||||
|       .subscribe({ |  | ||||||
|         next: ({ doc, dirty }) => { |  | ||||||
|           this.openDocumentService.setDirty(doc, dirty, this.getChangedFields()) |  | ||||||
|         }, |  | ||||||
|         error: (error) => { |  | ||||||
|           this.router.navigate(['404'], { |  | ||||||
|             replaceUrl: true, |  | ||||||
|           }) |  | ||||||
|         }, |  | ||||||
|       }) |       }) | ||||||
|  |  | ||||||
|     this.route.paramMap.subscribe((paramMap) => { |     this.route.paramMap.subscribe((paramMap) => { | ||||||
| @@ -682,19 +671,7 @@ export class DocumentDetailComponent | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|     this.title = this.documentTitlePipe.transform(doc.title) |     this.title = this.documentTitlePipe.transform(doc.title) | ||||||
|     const docFormValues = Object.assign({}, doc) |     this.prepareForm(doc) | ||||||
|     docFormValues['permissions_form'] = { |  | ||||||
|       owner: doc.owner, |  | ||||||
|       set_permissions: doc.permissions, |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     this.documentForm.patchValue(docFormValues, { emitEvent: false }) |  | ||||||
|     if (!this.userCanEdit) this.documentForm.disable() |  | ||||||
|     setTimeout(() => { |  | ||||||
|       // check again after a tick in case form was dirty |  | ||||||
|       if (!this.userCanEdit) this.documentForm.disable() |  | ||||||
|       else this.documentForm.enable() |  | ||||||
|     }, 10) |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   get customFieldFormFields(): FormArray { |   get customFieldFormFields(): FormArray { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 shamoon
					shamoon