mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Fix: saved views do not return to default display fields after setting and then removing (#9168)
This commit is contained in:
		| @@ -2230,7 +2230,7 @@ | |||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> |           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> | ||||||
|           <context context-type="linenumber">103</context> |           <context context-type="linenumber">106</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context> |           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context> | ||||||
| @@ -2565,7 +2565,7 @@ | |||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> |           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> | ||||||
|           <context context-type="linenumber">105</context> |           <context context-type="linenumber">108</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context> |           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context> | ||||||
| @@ -3322,7 +3322,7 @@ | |||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> |           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> | ||||||
|           <context context-type="linenumber">85</context> |           <context context-type="linenumber">87</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="1841172489943868696" datatype="html"> |       <trans-unit id="1841172489943868696" datatype="html"> | ||||||
| @@ -3333,7 +3333,7 @@ | |||||||
|         </context-group> |         </context-group> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> |           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> | ||||||
|           <context context-type="linenumber">93</context> |           <context context-type="linenumber">96</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="6048892649018070225" datatype="html"> |       <trans-unit id="6048892649018070225" datatype="html"> | ||||||
| @@ -8160,28 +8160,28 @@ | |||||||
|         <source>Confirm delete field</source> |         <source>Confirm delete field</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> |           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> | ||||||
|           <context context-type="linenumber">101</context> |           <context context-type="linenumber">104</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="2939457975223185057" datatype="html"> |       <trans-unit id="2939457975223185057" datatype="html"> | ||||||
|         <source>This operation will permanently delete this field.</source> |         <source>This operation will permanently delete this field.</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> |           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> | ||||||
|           <context context-type="linenumber">102</context> |           <context context-type="linenumber">105</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="4679555638382452936" datatype="html"> |       <trans-unit id="4679555638382452936" datatype="html"> | ||||||
|         <source>Deleted field "<x id="PH" equiv-text="field.name"/>"</source> |         <source>Deleted field "<x id="PH" equiv-text="field.name"/>"</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> |           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> | ||||||
|           <context context-type="linenumber">111</context> |           <context context-type="linenumber">114</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="4704551499967874824" datatype="html"> |       <trans-unit id="4704551499967874824" datatype="html"> | ||||||
|         <source>Error deleting field "<x id="PH" equiv-text="field.name"/>".</source> |         <source>Error deleting field "<x id="PH" equiv-text="field.name"/>".</source> | ||||||
|         <context-group purpose="location"> |         <context-group purpose="location"> | ||||||
|           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> |           <context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context> | ||||||
|           <context context-type="linenumber">118</context> |           <context context-type="linenumber">122</context> | ||||||
|         </context-group> |         </context-group> | ||||||
|       </trans-unit> |       </trans-unit> | ||||||
|       <trans-unit id="8084492669582894778" datatype="html"> |       <trans-unit id="8084492669582894778" datatype="html"> | ||||||
|   | |||||||
| @@ -145,7 +145,10 @@ export class SavedViewWidgetComponent | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (this.savedView.display_fields) { |     if ( | ||||||
|  |       this.savedView.display_fields && | ||||||
|  |       this.savedView.display_fields.length > 0 | ||||||
|  |     ) { | ||||||
|       this.displayFields = this.savedView.display_fields |       this.displayFields = this.savedView.display_fields | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -114,6 +114,48 @@ describe(`Additional service tests for SavedViewService`, () => { | |||||||
|     ]) |     ]) | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|  |   it('should treat empty display_fields as null', () => { | ||||||
|  |     subscription = service | ||||||
|  |       .patch({ | ||||||
|  |         id: 1, | ||||||
|  |         name: 'Saved View', | ||||||
|  |         show_on_dashboard: true, | ||||||
|  |         show_in_sidebar: true, | ||||||
|  |         sort_field: 'name', | ||||||
|  |         sort_reverse: true, | ||||||
|  |         filter_rules: [], | ||||||
|  |         display_fields: [], | ||||||
|  |       }) | ||||||
|  |       .subscribe() | ||||||
|  |     const req = httpTestingController.expectOne( | ||||||
|  |       `${environment.apiBaseUrl}${endpoint}/1/` | ||||||
|  |     ) | ||||||
|  |     expect(req.request.body.display_fields).toBeNull() | ||||||
|  |   }) | ||||||
|  |  | ||||||
|  |   it('should support patch without reload', () => { | ||||||
|  |     subscription = service | ||||||
|  |       .patch( | ||||||
|  |         { | ||||||
|  |           id: 1, | ||||||
|  |           name: 'Saved View', | ||||||
|  |           show_on_dashboard: true, | ||||||
|  |           show_in_sidebar: true, | ||||||
|  |           sort_field: 'name', | ||||||
|  |           sort_reverse: true, | ||||||
|  |           filter_rules: [], | ||||||
|  |         }, | ||||||
|  |         false | ||||||
|  |       ) | ||||||
|  |       .subscribe() | ||||||
|  |     const req = httpTestingController.expectOne( | ||||||
|  |       `${environment.apiBaseUrl}${endpoint}/1/` | ||||||
|  |     ) | ||||||
|  |     expect(req.request.method).toEqual('PATCH') | ||||||
|  |     req.flush({}) | ||||||
|  |     httpTestingController.verify() // no reload | ||||||
|  |   }) | ||||||
|  |  | ||||||
|   beforeEach(() => { |   beforeEach(() => { | ||||||
|     // Dont need to setup again |     // Dont need to setup again | ||||||
|  |  | ||||||
|   | |||||||
| @@ -87,12 +87,21 @@ export class SavedViewService extends AbstractPaperlessService<SavedView> { | |||||||
|     return super.create(o).pipe(tap(() => this.reload())) |     return super.create(o).pipe(tap(() => this.reload())) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   update(o: SavedView) { |   patch(o: SavedView, reload: boolean = false): Observable<SavedView> { | ||||||
|     return super.update(o).pipe(tap(() => this.reload())) |     if (o.display_fields?.length === 0) { | ||||||
|  |       o.display_fields = null | ||||||
|  |     } | ||||||
|  |     return super.patch(o).pipe( | ||||||
|  |       tap(() => { | ||||||
|  |         if (reload) { | ||||||
|  |           this.reload() | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     ) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   patchMany(objects: SavedView[]): Observable<SavedView[]> { |   patchMany(objects: SavedView[]): Observable<SavedView[]> { | ||||||
|     return combineLatest(objects.map((o) => super.patch(o))).pipe( |     return combineLatest(objects.map((o) => this.patch(o, false))).pipe( | ||||||
|       tap(() => this.reload()) |       tap(() => this.reload()) | ||||||
|     ) |     ) | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1147,6 +1147,15 @@ class SavedViewSerializer(OwnedObjectSerializer): | |||||||
|         if "user" in validated_data: |         if "user" in validated_data: | ||||||
|             # backwards compatibility |             # backwards compatibility | ||||||
|             validated_data["owner"] = validated_data.pop("user") |             validated_data["owner"] = validated_data.pop("user") | ||||||
|  |         if ( | ||||||
|  |             "display_fields" in validated_data | ||||||
|  |             and isinstance( | ||||||
|  |                 validated_data["display_fields"], | ||||||
|  |                 list, | ||||||
|  |             ) | ||||||
|  |             and len(validated_data["display_fields"]) == 0 | ||||||
|  |         ): | ||||||
|  |             validated_data["display_fields"] = None | ||||||
|         super().update(instance, validated_data) |         super().update(instance, validated_data) | ||||||
|         if rules_data is not None: |         if rules_data is not None: | ||||||
|             SavedViewFilterRule.objects.filter(saved_view=instance).delete() |             SavedViewFilterRule.objects.filter(saved_view=instance).delete() | ||||||
|   | |||||||
| @@ -1815,6 +1815,19 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase): | |||||||
|         ) |         ) | ||||||
|         self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) |         self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) | ||||||
|  |  | ||||||
|  |         # empty display fields treated as none | ||||||
|  |         response = self.client.patch( | ||||||
|  |             f"/api/saved_views/{v1.id}/", | ||||||
|  |             { | ||||||
|  |                 "display_fields": [], | ||||||
|  |             }, | ||||||
|  |             format="json", | ||||||
|  |         ) | ||||||
|  |         self.assertEqual(response.status_code, status.HTTP_200_OK) | ||||||
|  |  | ||||||
|  |         v1.refresh_from_db() | ||||||
|  |         self.assertEqual(v1.display_fields, None) | ||||||
|  |  | ||||||
|     def test_saved_view_display_customfields(self): |     def test_saved_view_display_customfields(self): | ||||||
|         """ |         """ | ||||||
|         GIVEN: |         GIVEN: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 shamoon
					shamoon