mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Compare commits
	
		
			4 Commits
		
	
	
		
			v2.18.3
			...
			fc4134e15c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | fc4134e15c | ||
|   | ac1b420966 | ||
|   | 80595899c1 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 9463a8fd26 | 
| @@ -3,7 +3,7 @@ | ||||
|     "dockerComposeFile": "docker-compose.devcontainer.sqlite-tika.yml", | ||||
|     "service": "paperless-development", | ||||
|     "workspaceFolder": "/usr/src/paperless/paperless-ngx", | ||||
|     "postCreateCommand": "/bin/bash -c 'uv sync --group dev && uv run pre-commit install'", | ||||
|     "postCreateCommand": "/bin/bash -c 'rm -rf .venv/.*  && uv sync --group dev && uv run pre-commit install'", | ||||
|     "customizations": { | ||||
|         "vscode": { | ||||
|           "extensions": [ | ||||
|   | ||||
| @@ -1,5 +1,48 @@ | ||||
| # Changelog | ||||
|  | ||||
| ## paperless-ngx 2.18.3 | ||||
|  | ||||
| ### Bug Fixes | ||||
|  | ||||
| -   Fix: include application config language settings for dateparser auto-detection [@shamoon](https://github.com/shamoon) ([#10722](https://github.com/paperless-ngx/paperless-ngx/pull/10722)) | ||||
| -   Fix: hide sidebar counts during saved views organization [@shamoon](https://github.com/shamoon) ([#10716](https://github.com/paperless-ngx/paperless-ngx/pull/10716)) | ||||
| -   Fix: wrap long view titles in sidebar [@shamoon](https://github.com/shamoon) ([#10715](https://github.com/paperless-ngx/paperless-ngx/pull/10715)) | ||||
| -   Fixhancement: more saved view count refreshes [@shamoon](https://github.com/shamoon) ([#10694](https://github.com/paperless-ngx/paperless-ngx/pull/10694)) | ||||
| -   Fix: include pagination array items for valid openapi schema [@shamoon](https://github.com/shamoon) ([#10682](https://github.com/paperless-ngx/paperless-ngx/pull/10682)) | ||||
| -   Fix: prevent scroll for view name in sidebar [@shamoon](https://github.com/shamoon) ([#10676](https://github.com/paperless-ngx/paperless-ngx/pull/10676)) | ||||
| -   Tweak: center document close button in app frame [@shamoon](https://github.com/shamoon) ([#10661](https://github.com/paperless-ngx/paperless-ngx/pull/10661)) | ||||
| -   Performance: Enable virtual scrolling for large custom field selects @david-loe ([#10708](https://github.com/paperless-ngx/paperless-ngx/pull/10708)) | ||||
|  | ||||
| ### Dependencies | ||||
|  | ||||
| <details> | ||||
| <summary>5 changes</summary> | ||||
|  | ||||
| -   Chore(deps): Update granian[uvloop] requirement from ~=2.4.1 to ~=2.5.1 @[dependabot[bot]](https://github.com/apps/dependabot) ([#10529](https://github.com/paperless-ngx/paperless-ngx/pull/10529)) | ||||
| -   Chore(deps): Bump the small-changes group across 1 directory with 6 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#10714](https://github.com/paperless-ngx/paperless-ngx/pull/10714)) | ||||
| -   docker-compose(deps): Bump library/mariadb from 11 to 12 in /docker/compose @[dependabot[bot]](https://github.com/apps/dependabot) ([#10621](https://github.com/paperless-ngx/paperless-ngx/pull/10621)) | ||||
| -   docker-compose(deps): Bump gotenberg/gotenberg from 8.20 to 8.22 in /docker/compose @[dependabot[bot]](https://github.com/apps/dependabot) ([#10687](https://github.com/paperless-ngx/paperless-ngx/pull/10687)) | ||||
| -   docker(deps): Bump astral-sh/uv from 0.8.8-python3.12-bookworm-slim to 0.8.13-python3.12-bookworm-slim @[dependabot[bot]](https://github.com/apps/dependabot) ([#10685](https://github.com/paperless-ngx/paperless-ngx/pull/10685)) | ||||
| </details> | ||||
|  | ||||
| ### All App Changes | ||||
|  | ||||
| <details> | ||||
| <summary>11 changes</summary> | ||||
|  | ||||
| -   Fix: include application config language settings for dateparser auto-detection [@shamoon](https://github.com/shamoon) ([#10722](https://github.com/paperless-ngx/paperless-ngx/pull/10722)) | ||||
| -   Chore(deps): Update granian[uvloop] requirement from ~=2.4.1 to ~=2.5.1 @[dependabot[bot]](https://github.com/apps/dependabot) ([#10529](https://github.com/paperless-ngx/paperless-ngx/pull/10529)) | ||||
| -   Chore(deps): Bump the small-changes group across 1 directory with 6 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#10714](https://github.com/paperless-ngx/paperless-ngx/pull/10714)) | ||||
| -   Fix: hide sidebar counts during saved views organization [@shamoon](https://github.com/shamoon) ([#10716](https://github.com/paperless-ngx/paperless-ngx/pull/10716)) | ||||
| -   Fix: wrap long view titles in sidebar [@shamoon](https://github.com/shamoon) ([#10715](https://github.com/paperless-ngx/paperless-ngx/pull/10715)) | ||||
| -   Performance: Enable virtual scrolling for large custom field selects @david-loe ([#10708](https://github.com/paperless-ngx/paperless-ngx/pull/10708)) | ||||
| -   Chore: refactor document details component [@shamoon](https://github.com/shamoon) ([#10662](https://github.com/paperless-ngx/paperless-ngx/pull/10662)) | ||||
| -   Fixhancement: more saved view count refreshes [@shamoon](https://github.com/shamoon) ([#10694](https://github.com/paperless-ngx/paperless-ngx/pull/10694)) | ||||
| -   Fix: include pagination array items for valid openapi schema [@shamoon](https://github.com/shamoon) ([#10682](https://github.com/paperless-ngx/paperless-ngx/pull/10682)) | ||||
| -   Fix: prevent scroll for view name in sidebar [@shamoon](https://github.com/shamoon) ([#10676](https://github.com/paperless-ngx/paperless-ngx/pull/10676)) | ||||
| -   Tweak: center document close button in app frame [@shamoon](https://github.com/shamoon) ([#10661](https://github.com/paperless-ngx/paperless-ngx/pull/10661)) | ||||
| </details> | ||||
|  | ||||
| ## paperless-ngx 2.18.2 | ||||
|  | ||||
| ### Bug Fixes | ||||
|   | ||||
| @@ -553,7 +553,7 @@ | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html</context> | ||||
|           <context context-type="linenumber">45</context> | ||||
|           <context context-type="linenumber">55</context> | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.html</context> | ||||
| @@ -1444,7 +1444,7 @@ | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html</context> | ||||
|           <context context-type="linenumber">44</context> | ||||
|           <context context-type="linenumber">54</context> | ||||
|         </context-group> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.html</context> | ||||
| @@ -3673,42 +3673,42 @@ | ||||
|         <source>Warning: existing instances of this field will retain their current value index (e.g. option #1, #2, #3) after editing the options here</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html</context> | ||||
|           <context context-type="linenumber">32</context> | ||||
|           <context context-type="linenumber">42</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="2739003406164860877" datatype="html"> | ||||
|         <source>Default Currency</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html</context> | ||||
|           <context context-type="linenumber">37</context> | ||||
|           <context context-type="linenumber">47</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="7615210738790237590" datatype="html"> | ||||
|         <source>3-character currency code</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html</context> | ||||
|           <context context-type="linenumber">37</context> | ||||
|           <context context-type="linenumber">47</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="607636736207886379" datatype="html"> | ||||
|         <source>Use locale</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html</context> | ||||
|           <context context-type="linenumber">37</context> | ||||
|           <context context-type="linenumber">47</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="528950215505228201" datatype="html"> | ||||
|         <source>Create new custom field</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.ts</context> | ||||
|           <context context-type="linenumber">93</context> | ||||
|           <context context-type="linenumber">118</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="8751213029607178010" datatype="html"> | ||||
|         <source>Edit custom field</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.ts</context> | ||||
|           <context context-type="linenumber">97</context> | ||||
|           <context context-type="linenumber">122</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="6672809941092516947" datatype="html"> | ||||
|   | ||||
| @@ -28,6 +28,16 @@ | ||||
|               </div> | ||||
|             } | ||||
|           </div> | ||||
|           @if (allSelectOptions.length > SELECT_OPTION_PAGE_SIZE) { | ||||
|             <ngb-pagination | ||||
|               class="d-flex justify-content-end" | ||||
|               [pageSize]="SELECT_OPTION_PAGE_SIZE" | ||||
|               [collectionSize]="allSelectOptions.length" | ||||
|               [(page)]="selectOptionsPage" | ||||
|               [maxSize]="5" | ||||
|               size="sm" | ||||
|             ></ngb-pagination> | ||||
|           } | ||||
|           @if (object?.id) { | ||||
|             <small class="d-block mt-2" i18n>Warning: existing instances of this field will retain their current value index (e.g. option #1, #2, #3) after editing the options here</small> | ||||
|           } | ||||
|   | ||||
| @@ -125,4 +125,42 @@ describe('CustomFieldEditDialogComponent', () => { | ||||
|     fixture.detectChanges() | ||||
|     expect(document.activeElement).toBe(selectOptionInputs.last.nativeElement) | ||||
|   }) | ||||
|  | ||||
|   it('should send all select options including those changed in form on save', () => { | ||||
|     component.dialogMode = EditDialogMode.EDIT | ||||
|     component.object = { | ||||
|       id: 1, | ||||
|       name: 'Field 1', | ||||
|       data_type: CustomFieldDataType.Select, | ||||
|       extra_data: { | ||||
|         select_options: Array.from({ length: 50 }, (_, i) => ({ | ||||
|           label: `Option ${i + 1}`, | ||||
|           id: `${i + 1}-xyz`, | ||||
|         })), | ||||
|       }, | ||||
|     } | ||||
|     fixture.detectChanges() | ||||
|     component.ngOnInit() | ||||
|     component.selectOptionsPage = 2 | ||||
|     fixture.detectChanges() | ||||
|     component.objectForm | ||||
|       .get('extra_data') | ||||
|       .get('select_options') | ||||
|       .get('0') | ||||
|       .get('label') | ||||
|       .setValue('Updated Option 9') | ||||
|     const formValues = (component as any).getFormValues() | ||||
|     // first item unchanged | ||||
|     expect(formValues.extra_data.select_options[0]).toEqual({ | ||||
|       label: 'Option 1', | ||||
|       id: '1-xyz', | ||||
|     }) | ||||
|     // page 2 first item updated | ||||
|     expect( | ||||
|       formValues.extra_data.select_options[component.SELECT_OPTION_PAGE_SIZE] | ||||
|     ).toEqual({ | ||||
|       label: 'Updated Option 9', | ||||
|       id: '9-xyz', | ||||
|     }) | ||||
|   }) | ||||
| }) | ||||
|   | ||||
| @@ -14,6 +14,7 @@ import { | ||||
|   FormsModule, | ||||
|   ReactiveFormsModule, | ||||
| } from '@angular/forms' | ||||
| import { NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap' | ||||
| import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' | ||||
| import { takeUntil } from 'rxjs' | ||||
| import { | ||||
| @@ -28,6 +29,8 @@ import { SelectComponent } from '../../input/select/select.component' | ||||
| import { TextComponent } from '../../input/text/text.component' | ||||
| import { EditDialogComponent, EditDialogMode } from '../edit-dialog.component' | ||||
|  | ||||
| const SELECT_OPTION_PAGE_SIZE = 8 | ||||
|  | ||||
| @Component({ | ||||
|   selector: 'pngx-custom-field-edit-dialog', | ||||
|   templateUrl: './custom-field-edit-dialog.component.html', | ||||
| @@ -37,6 +40,7 @@ import { EditDialogComponent, EditDialogMode } from '../edit-dialog.component' | ||||
|     TextComponent, | ||||
|     FormsModule, | ||||
|     ReactiveFormsModule, | ||||
|     NgbPaginationModule, | ||||
|     NgxBootstrapIconsModule, | ||||
|   ], | ||||
| }) | ||||
| @@ -45,6 +49,21 @@ export class CustomFieldEditDialogComponent | ||||
|   implements OnInit, AfterViewInit | ||||
| { | ||||
|   CustomFieldDataType = CustomFieldDataType | ||||
|   SELECT_OPTION_PAGE_SIZE = SELECT_OPTION_PAGE_SIZE | ||||
|  | ||||
|   private _allSelectOptions: any[] = [] | ||||
|   public get allSelectOptions(): any[] { | ||||
|     return this._allSelectOptions | ||||
|   } | ||||
|  | ||||
|   private _selectOptionsPage: number | ||||
|   public get selectOptionsPage(): number { | ||||
|     return this._selectOptionsPage | ||||
|   } | ||||
|   public set selectOptionsPage(v: number) { | ||||
|     this._selectOptionsPage = v | ||||
|     this.updateSelectOptions() | ||||
|   } | ||||
|  | ||||
|   @ViewChildren('selectOption') | ||||
|   private selectOptionInputs: QueryList<ElementRef> | ||||
| @@ -67,17 +86,10 @@ export class CustomFieldEditDialogComponent | ||||
|       this.objectForm.get('data_type').disable() | ||||
|     } | ||||
|     if (this.object?.data_type === CustomFieldDataType.Select) { | ||||
|       this.selectOptions.clear() | ||||
|       this.object.extra_data.select_options | ||||
|         .filter((option) => option) | ||||
|         .forEach((option) => | ||||
|           this.selectOptions.push( | ||||
|             new FormGroup({ | ||||
|               label: new FormControl(option.label), | ||||
|               id: new FormControl(option.id), | ||||
|             }) | ||||
|           ) | ||||
|         ) | ||||
|       this._allSelectOptions = [ | ||||
|         ...(this.object.extra_data.select_options ?? []), | ||||
|       ] | ||||
|       this.selectOptionsPage = 1 | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -87,6 +99,19 @@ export class CustomFieldEditDialogComponent | ||||
|       .subscribe(() => { | ||||
|         this.selectOptionInputs.last?.nativeElement.focus() | ||||
|       }) | ||||
|  | ||||
|     this.objectForm.valueChanges | ||||
|       .pipe(takeUntil(this.unsubscribeNotifier)) | ||||
|       .subscribe((change) => { | ||||
|         // Update the relevant select options values if changed in the form, which is only a page of the entire list | ||||
|         this.objectForm | ||||
|           .get('extra_data.select_options') | ||||
|           ?.value.forEach((option, index) => { | ||||
|             this._allSelectOptions[ | ||||
|               index + (this.selectOptionsPage - 1) * SELECT_OPTION_PAGE_SIZE | ||||
|             ] = option | ||||
|           }) | ||||
|       }) | ||||
|   } | ||||
|  | ||||
|   getCreateTitle() { | ||||
| @@ -108,6 +133,17 @@ export class CustomFieldEditDialogComponent | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   protected getFormValues() { | ||||
|     const formValues = super.getFormValues() | ||||
|     if ( | ||||
|       this.objectForm.get('data_type')?.value === CustomFieldDataType.Select | ||||
|     ) { | ||||
|       // Make sure we send all select options, with updated values | ||||
|       formValues.extra_data.select_options = this._allSelectOptions | ||||
|     } | ||||
|     return formValues | ||||
|   } | ||||
|  | ||||
|   getDataTypes() { | ||||
|     return DATA_TYPE_LABELS | ||||
|   } | ||||
| @@ -116,13 +152,35 @@ export class CustomFieldEditDialogComponent | ||||
|     return this.dialogMode === EditDialogMode.EDIT | ||||
|   } | ||||
|  | ||||
|   public addSelectOption() { | ||||
|   private updateSelectOptions() { | ||||
|     this.selectOptions.clear() | ||||
|     this._allSelectOptions | ||||
|       .slice( | ||||
|         (this.selectOptionsPage - 1) * SELECT_OPTION_PAGE_SIZE, | ||||
|         this.selectOptionsPage * SELECT_OPTION_PAGE_SIZE | ||||
|       ) | ||||
|       .forEach((option) => | ||||
|         this.selectOptions.push( | ||||
|       new FormGroup({ label: new FormControl(null), id: new FormControl(null) }) | ||||
|           new FormGroup({ | ||||
|             label: new FormControl(option.label), | ||||
|             id: new FormControl(option.id), | ||||
|           }) | ||||
|         ) | ||||
|       ) | ||||
|   } | ||||
|  | ||||
|   public addSelectOption() { | ||||
|     this._allSelectOptions.push({ label: null, id: null }) | ||||
|     this.selectOptionsPage = Math.ceil( | ||||
|       this.allSelectOptions.length / SELECT_OPTION_PAGE_SIZE | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   public removeSelectOption(index: number) { | ||||
|     this.selectOptions.removeAt(index) | ||||
|     this._allSelectOptions.splice( | ||||
|       index + (this.selectOptionsPage - 1) * SELECT_OPTION_PAGE_SIZE, | ||||
|       1 | ||||
|     ) | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -147,9 +147,13 @@ export abstract class EditDialogComponent< | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   protected getFormValues(): any { | ||||
|     return Object.assign({}, this.objectForm.value) | ||||
|   } | ||||
|  | ||||
|   save() { | ||||
|     this.error = null | ||||
|     const formValues = Object.assign({}, this.objectForm.value) | ||||
|     const formValues = this.getFormValues() | ||||
|     const permissionsObject: PermissionsFormObject = | ||||
|       this.objectForm.get('permissions_form')?.value | ||||
|     if (permissionsObject) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user