diff --git a/src-ui/src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html b/src-ui/src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html index b4216e41c..ea57e1746 100644 --- a/src-ui/src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html +++ b/src-ui/src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.html @@ -28,6 +28,16 @@ } + @if (allSelectOptions.length > SELECT_OPTION_PAGE_SIZE) { + + } @if (object?.id) { Warning: existing instances of this field will retain their current value index (e.g. option #1, #2, #3) after editing the options here } diff --git a/src-ui/src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.spec.ts b/src-ui/src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.spec.ts index 62a0954a1..4486003de 100644 --- a/src-ui/src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.spec.ts +++ b/src-ui/src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.spec.ts @@ -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', + }) + }) }) diff --git a/src-ui/src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.ts index ce3be7e66..617d825b2 100644 --- a/src-ui/src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.ts +++ b/src-ui/src/app/components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component.ts @@ -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 @@ -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 } + 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(option.label), + id: new FormControl(option.id), + }) + ) + ) + } + public addSelectOption() { - this.selectOptions.push( - new FormGroup({ label: new FormControl(null), id: new FormControl(null) }) + 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 + ) } } diff --git a/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts index fa35dc6bf..75534a777 100644 --- a/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts +++ b/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts @@ -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) {