]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Enhancement: use patch instead of put for frontend document changes (#9744)
authorshamoon <4887959+shamoon@users.noreply.github.com>
Tue, 22 Apr 2025 19:58:28 +0000 (12:58 -0700)
committerGitHub <noreply@github.com>
Tue, 22 Apr 2025 19:58:28 +0000 (19:58 +0000)
src-ui/src/app/components/document-detail/document-detail.component.spec.ts
src-ui/src/app/components/document-detail/document-detail.component.ts
src-ui/src/app/services/rest/document.service.spec.ts
src-ui/src/app/services/rest/document.service.ts

index 345d488ebdae8a28ae21e6445ea22eb4fb8b90de..5b94c4922b10255e6c76dfcb2b3c6147ce238b8f 100644 (file)
@@ -456,11 +456,11 @@ describe('DocumentDetailComponent', () => {
     initNormally()
     component.title = 'Foo Bar'
     const closeSpy = jest.spyOn(component, 'close')
-    const updateSpy = jest.spyOn(documentService, 'update')
+    const patchSpy = jest.spyOn(documentService, 'patch')
     const toastSpy = jest.spyOn(toastService, 'showInfo')
-    updateSpy.mockImplementation((o) => of(doc))
+    patchSpy.mockImplementation((o) => of(doc))
     component.save(true)
-    expect(updateSpy).toHaveBeenCalled()
+    expect(patchSpy).toHaveBeenCalled()
     expect(closeSpy).toHaveBeenCalled()
     expect(toastSpy).toHaveBeenCalledWith(
       'Document "Doc 3" saved successfully.'
@@ -471,11 +471,11 @@ describe('DocumentDetailComponent', () => {
     initNormally()
     component.title = 'Foo Bar'
     const closeSpy = jest.spyOn(component, 'close')
-    const updateSpy = jest.spyOn(documentService, 'update')
+    const patchSpy = jest.spyOn(documentService, 'patch')
     const toastSpy = jest.spyOn(toastService, 'showInfo')
-    updateSpy.mockImplementation((o) => of(doc))
+    patchSpy.mockImplementation((o) => of(doc))
     component.save()
-    expect(updateSpy).toHaveBeenCalled()
+    expect(patchSpy).toHaveBeenCalled()
     expect(closeSpy).not.toHaveBeenCalled()
     expect(toastSpy).toHaveBeenCalledWith(
       'Document "Doc 3" saved successfully.'
@@ -487,12 +487,12 @@ describe('DocumentDetailComponent', () => {
     initNormally()
     component.title = 'Foo Bar'
     const closeSpy = jest.spyOn(component, 'close')
-    const updateSpy = jest.spyOn(documentService, 'update')
+    const patchSpy = jest.spyOn(documentService, 'patch')
     const toastSpy = jest.spyOn(toastService, 'showError')
     const error = new Error('failed to save')
-    updateSpy.mockImplementation(() => throwError(() => error))
+    patchSpy.mockImplementation(() => throwError(() => error))
     component.save()
-    expect(updateSpy).toHaveBeenCalled()
+    expect(patchSpy).toHaveBeenCalled()
     expect(closeSpy).not.toHaveBeenCalled()
     expect(toastSpy).toHaveBeenCalledWith(
       'Error saving document "Doc 3"',
@@ -505,13 +505,13 @@ describe('DocumentDetailComponent', () => {
     initNormally()
     component.title = 'Foo Bar'
     const closeSpy = jest.spyOn(component, 'close')
-    const updateSpy = jest.spyOn(documentService, 'update')
+    const patchSpy = jest.spyOn(documentService, 'patch')
     const toastSpy = jest.spyOn(toastService, 'showInfo')
-    updateSpy.mockImplementation(() =>
+    patchSpy.mockImplementation(() =>
       throwError(() => new Error('failed to save'))
     )
     component.save(true)
-    expect(updateSpy).toHaveBeenCalled()
+    expect(patchSpy).toHaveBeenCalled()
     expect(closeSpy).toHaveBeenCalled()
     expect(toastSpy).toHaveBeenCalledWith(
       'Document "Doc 3" saved successfully.'
@@ -522,8 +522,8 @@ describe('DocumentDetailComponent', () => {
     initNormally()
     const nextDocId = 100
     component.title = 'Foo Bar'
-    const updateSpy = jest.spyOn(documentService, 'update')
-    updateSpy.mockReturnValue(of(doc))
+    const patchSpy = jest.spyOn(documentService, 'patch')
+    patchSpy.mockReturnValue(of(doc))
     const nextSpy = jest.spyOn(documentListViewService, 'getNext')
     nextSpy.mockReturnValue(of(nextDocId))
     const closeSpy = jest.spyOn(openDocumentsService, 'closeDocument')
@@ -531,7 +531,7 @@ describe('DocumentDetailComponent', () => {
     const navigateSpy = jest.spyOn(router, 'navigate')
 
     component.saveEditNext()
-    expect(updateSpy).toHaveBeenCalled()
+    expect(patchSpy).toHaveBeenCalled()
     expect(navigateSpy).toHaveBeenCalledWith(['documents', nextDocId])
     expect
   })
@@ -541,12 +541,12 @@ describe('DocumentDetailComponent', () => {
     initNormally()
     component.title = 'Foo Bar'
     const closeSpy = jest.spyOn(component, 'close')
-    const updateSpy = jest.spyOn(documentService, 'update')
+    const patchSpy = jest.spyOn(documentService, 'patch')
     const toastSpy = jest.spyOn(toastService, 'showError')
     const error = new Error('failed to save')
-    updateSpy.mockImplementation(() => throwError(() => error))
+    patchSpy.mockImplementation(() => throwError(() => error))
     component.saveEditNext()
-    expect(updateSpy).toHaveBeenCalled()
+    expect(patchSpy).toHaveBeenCalled()
     expect(closeSpy).not.toHaveBeenCalled()
     expect(toastSpy).toHaveBeenCalledWith('Error saving document', error)
   })
@@ -965,10 +965,10 @@ describe('DocumentDetailComponent', () => {
     expect(fixture.debugElement.nativeElement.textContent).toContain(
       customFields[1].name
     )
-    const updateSpy = jest.spyOn(documentService, 'update')
+    const patchSpy = jest.spyOn(documentService, 'patch')
     component.save(true)
-    expect(updateSpy.mock.lastCall[0].custom_fields).toHaveLength(2)
-    expect(updateSpy.mock.lastCall[0].custom_fields[1]).toEqual({
+    expect(patchSpy.mock.lastCall[0].custom_fields).toHaveLength(2)
+    expect(patchSpy.mock.lastCall[0].custom_fields[1]).toEqual({
       field: customFields[1].id,
       value: null,
     })
@@ -985,9 +985,9 @@ describe('DocumentDetailComponent', () => {
     expect(
       fixture.debugElement.query(By.css('form')).nativeElement.textContent
     ).not.toContain('Field 1')
-    const updateSpy = jest.spyOn(documentService, 'update')
+    const patchSpy = jest.spyOn(documentService, 'patch')
     component.save(true)
-    expect(updateSpy.mock.lastCall[0].custom_fields).toHaveLength(
+    expect(patchSpy.mock.lastCall[0].custom_fields).toHaveLength(
       initialLength - 1
     )
   })
index 2f5b179b862d6c61f0a87dba8b9dd5196a9890cc..dac5f5de0d0e0ad2b4f15978e8e5fc2b1207aa73 100644 (file)
@@ -784,6 +784,7 @@ export class DocumentDetailComponent
           this.title = doc.title
           this.updateFormForCustomFields()
           this.documentForm.patchValue(doc)
+          this.documentForm.markAsPristine()
           this.openDocumentService.setDirty(doc, false)
         },
         error: () => {
@@ -794,11 +795,30 @@ export class DocumentDetailComponent
       })
   }
 
+  private getChangedFields(): any {
+    const changes = {
+      id: this.document.id,
+    }
+    Object.keys(this.documentForm.controls).forEach((key) => {
+      if (this.documentForm.get(key).dirty) {
+        if (key === 'permissions_form') {
+          changes['owner'] =
+            this.documentForm.get('permissions_form').value['owner']
+          changes['set_permissions'] =
+            this.documentForm.get('permissions_form').value['set_permissions']
+        } else {
+          changes[key] = this.documentForm.get(key).value
+        }
+      }
+    })
+    return changes
+  }
+
   save(close: boolean = false) {
     this.networkActive = true
     ;(document.activeElement as HTMLElement)?.dispatchEvent(new Event('change'))
     this.documentsService
-      .update(this.document)
+      .patch(this.getChangedFields())
       .pipe(first())
       .subscribe({
         next: (docValues) => {
@@ -852,7 +872,7 @@ export class DocumentDetailComponent
     this.networkActive = true
     this.store.next(this.documentForm.value)
     this.documentsService
-      .update(this.document)
+      .patch(this.getChangedFields())
       .pipe(
         switchMap((updateResult) => {
           return this.documentListViewService
@@ -1303,6 +1323,8 @@ export class DocumentDetailComponent
       created: new Date(),
     })
     this.updateFormForCustomFields(true)
+    this.documentForm.get('custom_fields').markAsDirty()
+    this.documentForm.updateValueAndValidity()
   }
 
   public removeField(fieldInstance: CustomFieldInstance) {
@@ -1311,6 +1333,7 @@ export class DocumentDetailComponent
       1
     )
     this.updateFormForCustomFields(true)
+    this.documentForm.get('custom_fields').markAsDirty()
     this.documentForm.updateValueAndValidity()
   }
 
index 84f7f6f8ad72d44892b55f37f35b9bf95962ee8d..9480e281618904123ecf03e3ffb7d1dda8056d78 100644 (file)
@@ -268,15 +268,15 @@ describe(`DocumentService`, () => {
     expect(req.request.method).toEqual('GET')
   })
 
-  it('should pass remove_inbox_tags setting to update', () => {
-    subscription = service.update(documents[0]).subscribe()
+  it('should pass remove_inbox_tags setting to patch', () => {
+    subscription = service.patch(documents[0]).subscribe()
     let req = httpTestingController.expectOne(
       `${environment.apiBaseUrl}${endpoint}/${documents[0].id}/`
     )
     expect(req.request.body.remove_inbox_tags).toEqual(false)
 
     settingsService.set(SETTINGS_KEYS.DOCUMENT_EDITING_REMOVE_INBOX_TAGS, true)
-    subscription = service.update(documents[0]).subscribe()
+    subscription = service.patch(documents[0]).subscribe()
     req = httpTestingController.expectOne(
       `${environment.apiBaseUrl}${endpoint}/${documents[0].id}/`
     )
index 0c6c8cfa68c91ca4d90e068b726b92459ae7671c..9cdb862802e6321a9e4684b0a01dd99be96fe0c7 100644 (file)
@@ -189,13 +189,13 @@ export class DocumentService extends AbstractPaperlessService<Document> {
     return this.http.get<number>(this.getResourceUrl(null, 'next_asn'))
   }
 
-  update(o: Document): Observable<Document> {
+  patch(o: Document): Observable<Document> {
     // we want to only set created_date
-    o.created = undefined
+    delete o.created
     o.remove_inbox_tags = !!this.settingsService.get(
       SETTINGS_KEYS.DOCUMENT_EDITING_REMOVE_INBOX_TAGS
     )
-    return super.update(o)
+    return super.patch(o)
   }
 
   uploadDocument(formData) {