diff --git a/package.json b/package.json index 88672dfe10..c91d99109c 100644 --- a/package.json +++ b/package.json @@ -74,9 +74,9 @@ "@angular/platform-server": "^6.1.4", "@angular/router": "^6.1.4", "@angularclass/bootloader": "1.0.1", - "@ng-bootstrap/ng-bootstrap": "^2.0.0", - "@ng-dynamic-forms/core": "6.0.9", - "@ng-dynamic-forms/ui-ng-bootstrap": "6.0.9", + "@ng-bootstrap/ng-bootstrap": "3.3.1", + "@ng-dynamic-forms/core": "6.2.0", + "@ng-dynamic-forms/ui-ng-bootstrap": "6.2.0", "@ngrx/effects": "^6.1.0", "@ngrx/router-store": "^6.1.0", "@ngrx/store": "^6.1.0", diff --git a/src/app/+home-page/home-page.component.html b/src/app/+home-page/home-page.component.html index 6a3e20ca9d..b6e55932a2 100644 --- a/src/app/+home-page/home-page.component.html +++ b/src/app/+home-page/home-page.component.html @@ -1,5 +1,6 @@ - -
- - -
+ diff --git a/src/app/+home-page/home-page.component.ts b/src/app/+home-page/home-page.component.ts index 902a0e820d..d766c606a0 100644 --- a/src/app/+home-page/home-page.component.ts +++ b/src/app/+home-page/home-page.component.ts @@ -1,4 +1,43 @@ -import { Component } from '@angular/core'; +import { ChangeDetectorRef, Component, Inject, ViewChild } from '@angular/core'; +import { DynamicFormControlModel, DynamicFormGroupModel, DynamicFormLayout } from '@ng-dynamic-forms/core'; +import { FormComponent } from '../shared/form/form.component'; +import { FormBuilderService } from '../shared/form/builder/form-builder.service'; +import { SubmissionFormsConfigService } from '../core/config/submission-forms-config.service'; +import { FormService } from '../shared/form/form.service'; +import { Store } from '@ngrx/store'; +import { AppState } from '../app.reducer'; +import { AuthorityOptions } from '../core/integration/models/authority-options.model'; +import { DynamicScrollableDropdownModel } from '../shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.model'; +import { FormFieldMetadataValueObject } from '../shared/form/builder/models/form-field-metadata-value.model'; +import { ConfidenceType } from '../core/integration/models/confidence-type'; +import { Chips } from '../shared/chips/models/chips.model'; +import { ChipsItem } from '../shared/chips/models/chips-item.model'; +import { GLOBAL_CONFIG, GlobalConfig } from '../../config'; + +export const NG_BOOTSTRAP_SAMPLE_FORM_MODEL: DynamicFormControlModel[] = [ + + new DynamicFormGroupModel({ + + id: 'typeGroup', + group: [ + new DynamicScrollableDropdownModel({ + + id: 'type', + label: 'type', + placeholder: 'Type', + authorityOptions: new AuthorityOptions( 'type', 'dc.type', 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23') + }) + ] + }), + + new DynamicScrollableDropdownModel({ + + id: 'dc_type', + label: 'type', + placeholder: 'Type', + authorityOptions: new AuthorityOptions( 'type', 'dc.type', 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23') + }) +]; @Component({ selector: 'ds-home-page', @@ -6,4 +45,40 @@ import { Component } from '@angular/core'; templateUrl: './home-page.component.html' }) export class HomePageComponent { + public formId; + public formLayout: DynamicFormLayout = {}; + public formModel: DynamicFormControlModel[]; + public displaySubmit = false; + public chips: Chips; + + @ViewChild('formRef') private formRef: FormComponent; + @ViewChild('formRefTwo') private formRefTwo: FormComponent; + + constructor(@Inject(GLOBAL_CONFIG) public envConfig: GlobalConfig, + protected cdr: ChangeDetectorRef, + protected formBuilderService: FormBuilderService, + protected formConfigService: SubmissionFormsConfigService, + protected formService: FormService, + protected store: Store) { + + } + + ngOnInit() { + + // const collectionId = '1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb'; + const collectionId = 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'; + const formId = 'traditionalpageone'; + + this.formId = this.formService.getUniqueId('test'); + this.formModel = NG_BOOTSTRAP_SAMPLE_FORM_MODEL; + + const item = { + mainField: new FormFieldMetadataValueObject('main test', null, 'test001', 'main test', 0, ConfidenceType.CF_ACCEPTED), + relatedField: new FormFieldMetadataValueObject('related test', null, 'test002', 'related test', 0, ConfidenceType.CF_ACCEPTED), + otherRelatedField: new FormFieldMetadataValueObject('other related test') + }; + + this.chips = new Chips([item], 'display', 'mainField', this.envConfig.submission.icons.metadata); + + } } diff --git a/src/app/core/cache/builders/remote-data-build.service.ts b/src/app/core/cache/builders/remote-data-build.service.ts index 1c353920e0..7582c29233 100644 --- a/src/app/core/cache/builders/remote-data-build.service.ts +++ b/src/app/core/cache/builders/remote-data-build.service.ts @@ -6,7 +6,7 @@ import { } from 'rxjs'; import { Injectable } from '@angular/core'; import { distinctUntilChanged, flatMap, map, startWith } from 'rxjs/operators'; -import { hasValue, hasValueOperator, isEmpty, isNotEmpty } from '../../../shared/empty.util'; +import { hasValue, hasValueOperator, isEmpty, isNotEmpty, isNotUndefined } from '../../../shared/empty.util'; import { PaginatedList } from '../../data/paginated-list'; import { RemoteData } from '../../data/remote-data'; import { RemoteDataError } from '../../data/remote-data-error'; @@ -266,8 +266,10 @@ export class RemoteDataBuildService { map((rd: RemoteData>) => { if (Array.isArray(rd.payload)) { return Object.assign(rd, { payload: new PaginatedList(pageInfo, rd.payload) }) - } else { + } else if (isNotUndefined(rd.payload)) { return Object.assign(rd, { payload: new PaginatedList(pageInfo, rd.payload.page) }); + } else { + return Object.assign(rd, { payload: new PaginatedList(pageInfo, []) }); } }) ); diff --git a/src/app/core/integration/models/authority.value.ts b/src/app/core/integration/models/authority.value.ts index 5d23b51dd5..269407d2c5 100644 --- a/src/app/core/integration/models/authority.value.ts +++ b/src/app/core/integration/models/authority.value.ts @@ -1,7 +1,7 @@ import { IntegrationModel } from './integration.model'; import { autoserialize } from 'cerialize'; import { isNotEmpty } from '../../../shared/empty.util'; -import { PLACEHOLDER_PARENT_METADATA } from '../../../shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; +import { PLACEHOLDER_PARENT_METADATA } from '../../../shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model'; export class AuthorityValue extends IntegrationModel { diff --git a/src/app/shared/chips/chips.component.spec.ts b/src/app/shared/chips/chips.component.spec.ts index 5ac1a2131e..d11ce7a639 100644 --- a/src/app/shared/chips/chips.component.spec.ts +++ b/src/app/shared/chips/chips.component.spec.ts @@ -10,6 +10,12 @@ import { SortablejsModule } from 'angular-sortablejs'; import { By } from '@angular/platform-browser'; import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model'; import { createTestComponent, hasClass } from '../testing/utils'; +import { AuthorityConfidenceStateDirective } from '../authority-confidence/authority-confidence-state.directive'; +import { TranslateModule } from '@ngx-translate/core'; +import { GlobalConfig } from '../../../config/global-config.interface'; +import { GLOBAL_CONFIG } from '../../../config'; +import { MOCK_SUBMISSION_CONFIG } from '../testing/mock-submission-config'; +import { ConfidenceType } from '../../core/integration/models/confidence-type'; describe('ChipsComponent test suite', () => { @@ -20,6 +26,7 @@ describe('ChipsComponent test suite', () => { let html; let chips: Chips; + const envConfig: GlobalConfig = MOCK_SUBMISSION_CONFIG; // async beforeEach beforeEach(async(() => { @@ -27,12 +34,15 @@ describe('ChipsComponent test suite', () => { imports: [ NgbModule.forRoot(), SortablejsModule.forRoot({animation: 150}), + TranslateModule.forRoot() ], declarations: [ ChipsComponent, TestComponent, + AuthorityConfidenceStateDirective ], // declare the test component providers: [ + { provide: GLOBAL_CONFIG, useValue: envConfig }, ChangeDetectorRef, ChipsComponent, UploaderService @@ -139,33 +149,16 @@ describe('ChipsComponent test suite', () => { describe('when has items as object', () => { beforeEach(() => { const item = { - mainField: new FormFieldMetadataValueObject('main test', null, 'test001'), - relatedField: new FormFieldMetadataValueObject('related test', null, 'test002'), + mainField: new FormFieldMetadataValueObject('main test', null, 'test001', 'main test', 0, ConfidenceType.CF_ACCEPTED), + relatedField: new FormFieldMetadataValueObject('related test', null, 'test002', 'related test', 0, ConfidenceType.CF_ACCEPTED), otherRelatedField: new FormFieldMetadataValueObject('other related test') }; - const iconsConfig = [ - { - name: 'mainField', - style: 'fa-user' - }, - { - name: 'relatedField', - style: 'fa-user-alt' - }, - { - name: 'otherRelatedField', - style: 'fa-user-alt' - }, - { - name: 'default', - style: '' - } - ]; - chips = new Chips([item], 'display', 'mainField', iconsConfig); + chips = new Chips([item], 'display', 'mainField', envConfig.submission.icons.metadata); chipsFixture = TestBed.createComponent(ChipsComponent); chipsComp = chipsFixture.componentInstance; // TruncatableComponent test instance chipsComp.editable = true; + chipsComp.showIcons = true; chipsComp.chips = chips; chipsFixture.detectChanges(); }); @@ -178,20 +171,13 @@ describe('ChipsComponent test suite', () => { }); - it('should has text-muted on icon style when field value had not authority', () => { - const de = chipsFixture.debugElement.query(By.css('li.nav-item')); - const icons = de.queryAll(By.css('i.fa')); - - expect(hasClass(icons[2].nativeElement, 'text-muted')).toBeTruthy(); - }); - it('should show tooltip on mouse over an icon', () => { const de = chipsFixture.debugElement.query(By.css('li.nav-item')); const icons = de.queryAll(By.css('i.fa')); icons[0].triggerEventHandler('mouseover', null); - expect(chipsComp.tipText).toBe('main test') + expect(chipsComp.tipText).toEqual(['main test']) }); }); }); diff --git a/src/app/shared/chips/models/chips.model.ts b/src/app/shared/chips/models/chips.model.ts index a688dc2fc9..25754361cb 100644 --- a/src/app/shared/chips/models/chips.model.ts +++ b/src/app/shared/chips/models/chips.model.ts @@ -2,7 +2,7 @@ import { findIndex, isEqual, isObject } from 'lodash'; import { BehaviorSubject } from 'rxjs'; import { ChipsItem, ChipsItemIcon } from './chips-item.model'; import { hasValue, isNotEmpty } from '../../empty.util'; -import { PLACEHOLDER_PARENT_METADATA } from '../../form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; +import { PLACEHOLDER_PARENT_METADATA } from '../../form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model'; import { MetadataIconConfig } from '../../../../config/submission-config.interface'; import { FormFieldMetadataValueObject } from '../../form/builder/models/form-field-metadata-value.model'; import { AuthorityValue } from '../../../core/integration/models/authority.value'; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html similarity index 64% rename from src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.html rename to src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html index 750ef721c2..6b4d1c6562 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html @@ -1,19 +1,25 @@
- - +
+ + +
+ {{ message | translate:model.validators }} +
+
@@ -32,8 +38,8 @@
- + - +
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts similarity index 93% rename from src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.spec.ts rename to src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts index ca12a7a4b4..d5dfce2575 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts @@ -25,11 +25,14 @@ import { DynamicTextAreaModel, DynamicTimePickerModel } from '@ng-dynamic-forms/core'; -import { DsDynamicFormControlComponent } from './ds-dynamic-form-control.component'; +import { + DsDynamicFormControlContainerComponent, + dsDynamicFormControlMapFn +} from './ds-dynamic-form-control-container.component'; import { TranslateModule } from '@ngx-translate/core'; import { SharedModule } from '../../../shared.module'; import { DynamicDsDatePickerModel } from './models/date-picker/date-picker.model'; -import { DynamicGroupModel } from './models/dynamic-group/dynamic-group.model'; +import { DynamicRelationGroupModel } from './models/relation-group/dynamic-relation-group.model'; import { DynamicListCheckboxGroupModel } from './models/list/dynamic-list-checkbox-group.model'; import { AuthorityOptions } from '../../../../core/integration/models/authority-options.model'; import { DynamicListRadioGroupModel } from './models/list/dynamic-list-radio-group.model'; @@ -57,11 +60,11 @@ import { DsDynamicTypeaheadComponent } from './models/typeahead/dynamic-typeahea import { DsDynamicScrollableDropdownComponent } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.component'; import { DsDynamicTagComponent } from './models/tag/dynamic-tag.component'; import { DsDynamicListComponent } from './models/list/dynamic-list.component'; -import { DsDynamicGroupComponent } from './models/dynamic-group/dynamic-group.components'; + import { DsDatePickerComponent } from './models/date-picker/date-picker.component'; import { DsDynamicLookupComponent } from './models/lookup/dynamic-lookup.component'; -describe('DsDynamicFormControlComponent test suite', () => { +describe('DsDynamicFormControlContainerComponent test suite', () => { const authorityOptions: AuthorityOptions = { closed: false, @@ -106,7 +109,7 @@ describe('DsDynamicFormControlComponent test suite', () => { authorityOptions: authorityOptions, repeatable: false }), - new DynamicGroupModel({ + new DynamicRelationGroupModel({ id: 'relationGroup', formConfiguration: [], mandatoryField: '', @@ -122,8 +125,8 @@ describe('DsDynamicFormControlComponent test suite', () => { ]; const testModel = formModel[8]; let formGroup: FormGroup; - let fixture: ComponentFixture; - let component: DsDynamicFormControlComponent; + let fixture: ComponentFixture; + let component: DsDynamicFormControlContainerComponent; let debugElement: DebugElement; let testElement: DebugElement; @@ -147,11 +150,11 @@ describe('DsDynamicFormControlComponent test suite', () => { TranslateModule.forRoot(), TextMaskModule ], - providers: [DsDynamicFormControlComponent, DynamicFormService], + providers: [DsDynamicFormControlContainerComponent, DynamicFormService], schemas: [CUSTOM_ELEMENTS_SCHEMA] }).compileComponents().then(() => { - fixture = TestBed.createComponent(DsDynamicFormControlComponent); + fixture = TestBed.createComponent(DsDynamicFormControlContainerComponent); component = fixture.componentInstance; debugElement = fixture.debugElement; @@ -254,7 +257,7 @@ describe('DsDynamicFormControlComponent test suite', () => { }); it('should map a form control model to a form control component', () => { - const testFn = DsDynamicFormControlComponent.getFormControlType; + const testFn = dsDynamicFormControlMapFn; expect(testFn(formModel[0])).toBe(DynamicNGBootstrapCheckboxComponent); expect(testFn(formModel[1])).toBe(DynamicNGBootstrapCheckboxGroupComponent); expect(testFn(formModel[2])).toBeNull(); @@ -278,7 +281,7 @@ describe('DsDynamicFormControlComponent test suite', () => { expect(testFn(formModel[18])).toBe(DsDynamicTagComponent); expect(testFn(formModel[19])).toBe(DsDynamicListComponent); expect(testFn(formModel[20])).toBe(DsDynamicListComponent); - expect(testFn(formModel[21])).toBe(DsDynamicGroupComponent); + expect(testFn(formModel[21])).toBe(DynamicRelationGroupModel); expect(testFn(formModel[22])).toBe(DsDatePickerComponent); expect(testFn(formModel[23])).toBe(DsDynamicLookupComponent); expect(testFn(formModel[24])).toBe(DsDynamicLookupComponent); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts similarity index 50% rename from src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.ts rename to src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts index 3544bce280..703e2fceb0 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts @@ -1,4 +1,5 @@ import { + ChangeDetectionStrategy, Component, ComponentFactoryResolver, ContentChildren, @@ -7,12 +8,15 @@ import { OnChanges, Output, QueryList, + Renderer2, SimpleChanges, Type, ViewChild, - ViewContainerRef + ViewContainerRef, + ViewEncapsulation } from '@angular/core'; import { FormGroup } from '@angular/forms'; + import { DYNAMIC_FORM_CONTROL_TYPE_ARRAY, DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX, @@ -28,48 +32,112 @@ import { DynamicFormControl, DynamicFormControlContainerComponent, DynamicFormControlEvent, - DynamicFormControlModel, DynamicFormLayout, + DynamicFormControlModel, + DynamicFormLayout, DynamicFormLayoutService, DynamicFormValidationService, DynamicTemplateDirective, } from '@ng-dynamic-forms/core'; -import { DYNAMIC_FORM_CONTROL_TYPE_TYPEAHEAD } from './models/typeahead/dynamic-typeahead.model'; -import { DYNAMIC_FORM_CONTROL_TYPE_SCROLLABLE_DROPDOWN } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.model'; -import { DYNAMIC_FORM_CONTROL_TYPE_TAG } from './models/tag/dynamic-tag.model'; -import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from './models/dynamic-group/dynamic-group.model'; -import { DYNAMIC_FORM_CONTROL_TYPE_DSDATEPICKER } from './models/date-picker/date-picker.model'; -import { DYNAMIC_FORM_CONTROL_TYPE_LOOKUP } from './models/lookup/dynamic-lookup.model'; -import { DynamicListCheckboxGroupModel } from './models/list/dynamic-list-checkbox-group.model'; -import { DynamicListRadioGroupModel } from './models/list/dynamic-list-radio-group.model'; -import { isNotEmpty } from '../../../empty.util'; -import { DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_NAME } from './models/lookup/dynamic-lookup-name.model'; -import { DsDynamicTagComponent } from './models/tag/dynamic-tag.component'; import { DynamicNGBootstrapCalendarComponent, DynamicNGBootstrapCheckboxComponent, DynamicNGBootstrapCheckboxGroupComponent, DynamicNGBootstrapDatePickerComponent, - DynamicNGBootstrapFormArrayComponent, - DynamicNGBootstrapFormGroupComponent, DynamicNGBootstrapInputComponent, DynamicNGBootstrapRadioGroupComponent, DynamicNGBootstrapSelectComponent, DynamicNGBootstrapTextAreaComponent, DynamicNGBootstrapTimePickerComponent } from '@ng-dynamic-forms/ui-ng-bootstrap'; + +import { DYNAMIC_FORM_CONTROL_TYPE_TYPEAHEAD } from './models/typeahead/dynamic-typeahead.model'; +import { DYNAMIC_FORM_CONTROL_TYPE_SCROLLABLE_DROPDOWN } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.model'; +import { DYNAMIC_FORM_CONTROL_TYPE_TAG } from './models/tag/dynamic-tag.model'; +import { DYNAMIC_FORM_CONTROL_TYPE_DSDATEPICKER } from './models/date-picker/date-picker.model'; +import { DYNAMIC_FORM_CONTROL_TYPE_LOOKUP } from './models/lookup/dynamic-lookup.model'; +import { DynamicListCheckboxGroupModel } from './models/list/dynamic-list-checkbox-group.model'; +import { DynamicListRadioGroupModel } from './models/list/dynamic-list-radio-group.model'; +import { isNotEmpty, isNotUndefined } from '../../../empty.util'; +import { DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_NAME } from './models/lookup/dynamic-lookup-name.model'; +import { DsDynamicTagComponent } from './models/tag/dynamic-tag.component'; import { DsDatePickerComponent } from './models/date-picker/date-picker.component'; import { DsDynamicListComponent } from './models/list/dynamic-list.component'; import { DsDynamicTypeaheadComponent } from './models/typeahead/dynamic-typeahead.component'; import { DsDynamicScrollableDropdownComponent } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.component'; -import { DsDynamicGroupComponent } from './models/dynamic-group/dynamic-group.components'; import { DsDynamicLookupComponent } from './models/lookup/dynamic-lookup.component'; +import { DsDynamicFormGroupComponent } from './models/form-group/dynamic-form-group.component'; +import { DsDynamicFormArrayComponent } from './models/array-group/dynamic-form-array.component'; +import { DsDynamicRelationGroupComponent } from './models/relation-group/dynamic-relation-group.components'; +import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from './models/relation-group/dynamic-relation-group.model'; + +export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type | null { + switch (model.type) { + + case DYNAMIC_FORM_CONTROL_TYPE_ARRAY: + return DsDynamicFormArrayComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX: + return DynamicNGBootstrapCheckboxComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX_GROUP: + return (model instanceof DynamicListCheckboxGroupModel) ? DsDynamicListComponent : DynamicNGBootstrapCheckboxGroupComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_DATEPICKER: + const datepickerModel = model as DynamicDatePickerModel; + + return datepickerModel.inline ? DynamicNGBootstrapCalendarComponent : DynamicNGBootstrapDatePickerComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_GROUP: + return DsDynamicFormGroupComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_INPUT: + return DynamicNGBootstrapInputComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_RADIO_GROUP: + return (model instanceof DynamicListRadioGroupModel) ? DsDynamicListComponent : DynamicNGBootstrapRadioGroupComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_SELECT: + return DynamicNGBootstrapSelectComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_TEXTAREA: + return DynamicNGBootstrapTextAreaComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_TIMEPICKER: + return DynamicNGBootstrapTimePickerComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_TYPEAHEAD: + return DsDynamicTypeaheadComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_SCROLLABLE_DROPDOWN: + return DsDynamicScrollableDropdownComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_TAG: + return DsDynamicTagComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP: + return DsDynamicRelationGroupComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_DSDATEPICKER: + return DsDatePickerComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_LOOKUP: + return DsDynamicLookupComponent; + + case DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_NAME: + return DsDynamicLookupComponent; + + default: + return null; + } +} @Component({ selector: 'ds-dynamic-form-control', - styleUrls: ['../../form.component.scss', './ds-dynamic-form.component.scss'], - templateUrl: './ds-dynamic-form-control.component.html' + styleUrls: ['./ds-dynamic-form.component.scss', '../../form.component.scss'], + templateUrl: './ds-dynamic-form-control-container.component.html', + changeDetection: ChangeDetectionStrategy.Default }) -export class DsDynamicFormControlComponent extends DynamicFormControlContainerComponent implements OnChanges { +export class DsDynamicFormControlContainerComponent extends DynamicFormControlContainerComponent implements OnChanges { @ContentChildren(DynamicTemplateDirective) contentTemplateList: QueryList; // tslint:disable-next-line:no-input-rename @@ -82,83 +150,29 @@ export class DsDynamicFormControlComponent extends DynamicFormControlContainerCo @Input() group: FormGroup; @Input() hasErrorMessaging = false; @Input() layout = null as DynamicFormLayout; - @Input() model: any; + @Input() model: DynamicFormControlModel; /* tslint:disable:no-output-rename */ @Output('dfBlur') blur: EventEmitter = new EventEmitter(); @Output('dfChange') change: EventEmitter = new EventEmitter(); @Output('dfFocus') focus: EventEmitter = new EventEmitter(); + @Output('ngbEvent') customEvent: EventEmitter = new EventEmitter(); /* tslint:enable:no-output-rename */ @ViewChild('componentViewContainer', {read: ViewContainerRef}) componentViewContainerRef: ViewContainerRef; + private showErrorMessagesPreviousStage: boolean; + get componentType(): Type | null { - return this.layoutService.getCustomComponentType(this.model) || DsDynamicFormControlComponent.getFormControlType(this.model); + return this.layoutService.getCustomComponentType(this.model) || dsDynamicFormControlMapFn(this.model); } - static getFormControlType(model: DynamicFormControlModel): Type | null { - - switch (model.type) { - - case DYNAMIC_FORM_CONTROL_TYPE_ARRAY: - return DynamicNGBootstrapFormArrayComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX: - return DynamicNGBootstrapCheckboxComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX_GROUP: - return (model instanceof DynamicListCheckboxGroupModel) ? DsDynamicListComponent : DynamicNGBootstrapCheckboxGroupComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_DATEPICKER: - const datepickerModel = model as DynamicDatePickerModel; - - return datepickerModel.inline ? DynamicNGBootstrapCalendarComponent : DynamicNGBootstrapDatePickerComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_GROUP: - return DynamicNGBootstrapFormGroupComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_INPUT: - return DynamicNGBootstrapInputComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_RADIO_GROUP: - return (model instanceof DynamicListRadioGroupModel) ? DsDynamicListComponent : DynamicNGBootstrapRadioGroupComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_SELECT: - return DynamicNGBootstrapSelectComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_TEXTAREA: - return DynamicNGBootstrapTextAreaComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_TIMEPICKER: - return DynamicNGBootstrapTimePickerComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_TYPEAHEAD: - return DsDynamicTypeaheadComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_SCROLLABLE_DROPDOWN: - return DsDynamicScrollableDropdownComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_TAG: - return DsDynamicTagComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP: - return DsDynamicGroupComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_DSDATEPICKER: - return DsDatePickerComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_LOOKUP: - return DsDynamicLookupComponent; - - case DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_NAME: - return DsDynamicLookupComponent; - - default: - return null; - } - } - - constructor(protected componentFactoryResolver: ComponentFactoryResolver, protected layoutService: DynamicFormLayoutService, - protected validationService: DynamicFormValidationService) { + protected test: boolean; + constructor( + protected componentFactoryResolver: ComponentFactoryResolver, + protected layoutService: DynamicFormLayoutService, + protected validationService: DynamicFormValidationService, + protected renderer: Renderer2 + ) { super(componentFactoryResolver, layoutService, validationService); } @@ -169,6 +183,28 @@ export class DsDynamicFormControlComponent extends DynamicFormControlContainerCo } } + ngDoCheck() { + if (isNotUndefined(this.showErrorMessagesPreviousStage) && this.showErrorMessagesPreviousStage !== this.showErrorMessages) { + this.showErrorMessagesPreviousStage = this.showErrorMessages; + this.forceShowErrorDetection(); + } + } + + ngAfterViewInit() { + this.showErrorMessagesPreviousStage = this.showErrorMessages + } + + /** + * Since Form Control Components created dynamically have 'OnPush' change detection strategy, + * changes are not propagated. So use this method to force an update + */ + protected forceShowErrorDetection() { + if (this.showErrorMessages) { + this.destroyFormControlComponent(); + this.createFormControlComponent(); + } + } + onChangeLanguage(event) { if (isNotEmpty((this.model as any).value)) { this.onChange(event); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form.component.ts index c1b4ca71c8..ccf9e6d292 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form.component.ts @@ -17,11 +17,12 @@ import { DynamicFormService, DynamicTemplateDirective, } from '@ng-dynamic-forms/core'; -import { DsDynamicFormControlComponent } from './ds-dynamic-form-control.component'; +import { DsDynamicFormControlContainerComponent } from './ds-dynamic-form-control-container.component'; import { FormBuilderService } from '../form-builder.service'; @Component({ selector: 'ds-dynamic-form', + styleUrls: ['../../form.component.scss'], templateUrl: './ds-dynamic-form.component.html' }) export class DsDynamicFormComponent extends DynamicFormComponent { @@ -35,11 +36,12 @@ export class DsDynamicFormComponent extends DynamicFormComponent { @Output('dfBlur') blur: EventEmitter = new EventEmitter(); @Output('dfChange') change: EventEmitter = new EventEmitter(); @Output('dfFocus') focus: EventEmitter = new EventEmitter(); + @Output('ngbEvent') customEvent: EventEmitter = new EventEmitter(); /* tslint:enable:no-output-rename */ @ContentChildren(DynamicTemplateDirective) templates: QueryList; - @ViewChildren(DsDynamicFormControlComponent) components: QueryList; + @ViewChildren(DsDynamicFormControlContainerComponent) components: QueryList; constructor(protected formService: FormBuilderService, protected layoutService: DynamicFormLayoutService) { super(formService, layoutService); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.html new file mode 100644 index 0000000000..56524523d1 --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.html @@ -0,0 +1,32 @@ + + +
+ +
+ + + + + + + +
+ +
+ +
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.ts new file mode 100644 index 0000000000..1e8fd3b55e --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.ts @@ -0,0 +1,38 @@ +import { Component, EventEmitter, Input, Output, QueryList } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { + DynamicFormArrayComponent, + DynamicFormArrayModel, + DynamicFormControlCustomEvent, DynamicFormControlEvent, + DynamicFormLayout, + DynamicFormLayoutService, + DynamicFormValidationService, + DynamicTemplateDirective +} from '@ng-dynamic-forms/core'; + +@Component({ + selector: 'ds-dynamic-form-array', + templateUrl: './dynamic-form-array.component.html' +}) +export class DsDynamicFormArrayComponent extends DynamicFormArrayComponent { + + @Input() bindId = true; + @Input() group: FormGroup; + @Input() layout: DynamicFormLayout; + @Input() model: DynamicFormArrayModel; + @Input() templates: QueryList | undefined; + + /* tslint:disable:no-output-rename */ + @Output('dfBlur') blur: EventEmitter = new EventEmitter(); + @Output('dfChange') change: EventEmitter = new EventEmitter(); + @Output('dfFocus') focus: EventEmitter = new EventEmitter(); + @Output('ngbEvent') customEvent: EventEmitter = new EventEmitter(); + /* tslint:enable:no-output-rename */ + + constructor(protected layoutService: DynamicFormLayoutService, + protected validationService: DynamicFormValidationService) { + + super(layoutService, validationService); + } + +} diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/form-group/dynamic-form-group.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/form-group/dynamic-form-group.component.html new file mode 100644 index 0000000000..c8443c640d --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/form-group/dynamic-form-group.component.html @@ -0,0 +1,24 @@ + + +
+ + +
+ +
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/form-group/dynamic-form-group.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/form-group/dynamic-form-group.component.ts new file mode 100644 index 0000000000..fb11ea4cfa --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/form-group/dynamic-form-group.component.ts @@ -0,0 +1,61 @@ +import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, QueryList } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { + DynamicFormControlComponent, + DynamicFormControlCustomEvent, DynamicFormControlEvent, + DynamicFormGroupModel, + DynamicFormLayout, + DynamicFormLayoutService, + DynamicFormValidationService, + DynamicTemplateDirective +} from '@ng-dynamic-forms/core'; +import { filter, tap } from 'rxjs/operators'; + +@Component({ + selector: 'ds-dynamic-form-group', + templateUrl: './dynamic-form-group.component.html', + changeDetection: ChangeDetectionStrategy.Default +}) +export class DsDynamicFormGroupComponent extends DynamicFormControlComponent { + + @Input() bindId = true; + @Input() group: FormGroup; + @Input() layout: DynamicFormLayout; + @Input() model: DynamicFormGroupModel; + @Input() templates: QueryList | DynamicTemplateDirective[] | undefined; + + /* tslint:disable:no-output-rename */ + @Output('dfBlur') blur: EventEmitter = new EventEmitter(); + @Output('dfChange') change: EventEmitter = new EventEmitter(); + @Output('dfFocus') focus: EventEmitter = new EventEmitter(); + @Output('ngbEvent') customEvent: EventEmitter = new EventEmitter(); + /* tslint:enable:no-output-rename */ + + constructor(protected layoutService: DynamicFormLayoutService, + protected validationService: DynamicFormValidationService) { + + super(layoutService, validationService); + } + +/* ngAfterViewInit() { + if (this.control) { + this.control.statusChanges.pipe( + tap((state) => console.log(this.model.id, state)), + filter((state) => state === 'INVALID'), + // filter(() => this.control.touched), + ) + .subscribe((state) => { + // const instance: DynamicFormControlComponent = this.componentRef.instance as any; + console.log('group', this.model.id, state); + // console.log(this.model.hasErrorMessages, this.control.touched, this.hasFocus, this.isInvalid); + // instance.control.markAsTouched(); + console.log('showErrorMessages ', this.showErrorMessages); + console.log('hasErrorMessages ', this.model.hasErrorMessages); + console.log('touched ', this.control.touched); + console.log('hasFocus ', this.hasFocus); + console.log('isInvalid ', this.isInvalid); + }); + } + }*/ + +} diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts index 6693eb4d66..186d359dd0 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts @@ -33,7 +33,6 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen @Input() bindId = true; @Input() group: FormGroup; @Input() model: DynamicListCheckboxGroupModel | DynamicListRadioGroupModel; - @Input() showErrorMessages = false; @Output() blur: EventEmitter = new EventEmitter(); @Output() change: EventEmitter = new EventEmitter(); @@ -132,7 +131,7 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen tempList = []; } }); - this.cdr.detectChanges(); + this.cdr.markForCheck(); }); } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts index 210cb1855d..df2252163d 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts @@ -23,6 +23,10 @@ import { By } from '@angular/platform-browser'; import { AuthorityValue } from '../../../../../../core/integration/models/authority.value'; import { createTestComponent } from '../../../../../testing/utils'; import { DynamicLookupNameModel } from './dynamic-lookup-name.model'; +import { AuthorityConfidenceStateDirective } from '../../../../../authority-confidence/authority-confidence-state.directive'; +import { ObjNgFor } from '../../../../../utils/object-ngfor.pipe'; +import { GLOBAL_CONFIG, GlobalConfig } from '../../../../../../../config'; +import { MOCK_SUBMISSION_CONFIG } from '../../../../../testing/mock-submission-config'; let LOOKUP_TEST_MODEL_CONFIG = { authorityOptions: { @@ -73,6 +77,8 @@ let LOOKUP_TEST_GROUP = new FormGroup({ lookupName: new FormControl() }); +const envConfig: GlobalConfig = MOCK_SUBMISSION_CONFIG; + describe('Dynamic Lookup component', () => { function init() { LOOKUP_TEST_MODEL_CONFIG = { @@ -150,10 +156,13 @@ describe('Dynamic Lookup component', () => { declarations: [ DsDynamicLookupComponent, TestComponent, + AuthorityConfidenceStateDirective, + ObjNgFor ], // declare the test component providers: [ ChangeDetectorRef, DsDynamicLookupComponent, + { provide: GLOBAL_CONFIG, useValue: envConfig }, { provide: AuthorityService, useValue: authorityService }, { provide: DynamicFormLayoutService, useValue: {} }, { provide: DynamicFormValidationService, useValue: {} } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.ts index 66697cab61..34202e68b3 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.ts @@ -30,7 +30,6 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem @Input() bindId = true; @Input() group: FormGroup; @Input() model: DynamicLookupModel | DynamicLookupNameModel; - @Input() showErrorMessages = false; @Output() blur: EventEmitter = new EventEmitter(); @Output() change: EventEmitter = new EventEmitter(); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html similarity index 100% rename from src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.html rename to src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.scss b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.scss similarity index 100% rename from src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.scss rename to src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.scss diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts similarity index 84% rename from src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.spec.ts rename to src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts index bd8d79dd42..20547d6b5b 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts @@ -6,16 +6,13 @@ import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angul import { TranslateModule } from '@ngx-translate/core'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; -import { DsDynamicGroupComponent } from './dynamic-group.components'; -import { DynamicGroupModel, DynamicGroupModelConfig } from './dynamic-group.model'; -import { - FormRowModel, - SubmissionFormsModel -} from '../../../../../../core/config/models/config-submission-forms.model'; +import { DsDynamicRelationGroupComponent } from './dynamic-relation-group.components'; +import { DynamicRelationGroupModel, DynamicRelationGroupModelConfig } from './dynamic-relation-group.model'; +import { FormRowModel, SubmissionFormsModel } from '../../../../../../core/config/models/config-submission-forms.model'; import { FormFieldModel } from '../../../models/form-field.model'; import { FormBuilderService } from '../../../form-builder.service'; import { FormService } from '../../../../form.service'; -import { GLOBAL_CONFIG } from '../../../../../../../config'; +import { GLOBAL_CONFIG, GlobalConfig } from '../../../../../../../config'; import { FormComponent } from '../../../../form.component'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { Chips } from '../../../../../chips/models/chips.model'; @@ -26,12 +23,17 @@ import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dyna import { MockStore } from '../../../../../testing/mock-store'; import { Store } from '@ngrx/store'; import { AppState } from '../../../../../../app.reducer'; +import { AuthService } from '../../../../../../core/auth/auth.service'; +import { AuthServiceStub } from '../../../../../testing/auth-service-stub'; +import { AuthorityService } from '../../../../../../core/integration/authority.service'; +import { AuthorityServiceStub } from '../../../../../testing/authority-service-stub'; +import { MOCK_SUBMISSION_CONFIG } from '../../../../../testing/mock-submission-config'; export let FORM_GROUP_TEST_MODEL_CONFIG; export let FORM_GROUP_TEST_GROUP; -let config; +const config: GlobalConfig = MOCK_SUBMISSION_CONFIG; function init() { FORM_GROUP_TEST_MODEL_CONFIG = { @@ -78,38 +80,19 @@ function init() { scopeUUID: '43fe1f8c-09a6-4fcf-9c78-5d4fed8f2c8f', submissionScope: undefined, validators: { required: null } - } as DynamicGroupModelConfig; + } as DynamicRelationGroupModelConfig; FORM_GROUP_TEST_GROUP = new FormGroup({ dc_contributor_author: new FormControl(), }); - config = { - form: { - validatorMap: { - required: 'required', - regex: 'pattern' - } - }, - submission: { - metadata: { - icons: [ - { - name: 'default', - config: {} - } - ] - } - } - } as any; - } -describe('DsDynamicGroupComponent test suite', () => { +describe('DsDynamicRelationGroupComponent test suite', () => { let testComp: TestComponent; - let groupComp: DsDynamicGroupComponent; + let groupComp: DsDynamicRelationGroupComponent; let testFixture: ComponentFixture; - let groupFixture: ComponentFixture; + let groupFixture: ComponentFixture; let modelValue: any; let html; let control1: FormControl; @@ -132,19 +115,20 @@ describe('DsDynamicGroupComponent test suite', () => { ], declarations: [ FormComponent, - DsDynamicGroupComponent, + DsDynamicRelationGroupComponent, TestComponent, ], // declare the test component providers: [ ChangeDetectorRef, - DsDynamicGroupComponent, + DsDynamicRelationGroupComponent, DynamicFormValidationService, DynamicFormLayoutService, FormBuilderService, FormComponent, FormService, + { provide: AuthorityService, useValue: new AuthorityServiceStub() }, { provide: GLOBAL_CONFIG, useValue: config }, - {provide: Store, useValue: store}, + { provide: Store, useValue: store }, ], schemas: [CUSTOM_ELEMENTS_SCHEMA] }); @@ -154,13 +138,12 @@ describe('DsDynamicGroupComponent test suite', () => { describe('', () => { // synchronous beforeEach beforeEach(() => { - html = ` - `; + (focus)="onFocus($event)">`; testFixture = createTestComponent(html, TestComponent) as ComponentFixture; testComp = testFixture.componentInstance; @@ -171,7 +154,7 @@ describe('DsDynamicGroupComponent test suite', () => { testComp = null; }); - it('should create DsDynamicGroupComponent', inject([DsDynamicGroupComponent], (app: DsDynamicGroupComponent) => { + it('should create DsDynamicRelationGroupComponent', inject([DsDynamicRelationGroupComponent], (app: DsDynamicRelationGroupComponent) => { expect(app).toBeDefined(); })); @@ -180,11 +163,11 @@ describe('DsDynamicGroupComponent test suite', () => { describe('when init model value is empty', () => { beforeEach(inject([FormBuilderService], (service: FormBuilderService) => { - groupFixture = TestBed.createComponent(DsDynamicGroupComponent); + groupFixture = TestBed.createComponent(DsDynamicRelationGroupComponent); groupComp = groupFixture.componentInstance; // FormComponent test instance groupComp.formId = 'testForm'; groupComp.group = FORM_GROUP_TEST_GROUP; - groupComp.model = new DynamicGroupModel(FORM_GROUP_TEST_MODEL_CONFIG); + groupComp.model = new DynamicRelationGroupModel(FORM_GROUP_TEST_MODEL_CONFIG); groupFixture.detectChanges(); control1 = service.getFormControlById('dc_contributor_author', (groupComp as any).formRef.formGroup, groupComp.formModel) as FormControl; model1 = service.findById('dc_contributor_author', groupComp.formModel) as DsDynamicInputModel; @@ -254,11 +237,11 @@ describe('DsDynamicGroupComponent test suite', () => { describe('when init model value is not empty', () => { beforeEach(() => { - groupFixture = TestBed.createComponent(DsDynamicGroupComponent); + groupFixture = TestBed.createComponent(DsDynamicRelationGroupComponent); groupComp = groupFixture.componentInstance; // FormComponent test instance groupComp.formId = 'testForm'; groupComp.group = FORM_GROUP_TEST_GROUP; - groupComp.model = new DynamicGroupModel(FORM_GROUP_TEST_MODEL_CONFIG); + groupComp.model = new DynamicRelationGroupModel(FORM_GROUP_TEST_MODEL_CONFIG); modelValue = [{ 'dc.contributor.author': new FormFieldMetadataValueObject('test author'), 'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation') @@ -339,7 +322,7 @@ class TestComponent { groupModelConfig = FORM_GROUP_TEST_MODEL_CONFIG; - model = new DynamicGroupModel(this.groupModelConfig); + model = new DynamicRelationGroupModel(this.groupModelConfig); showErrorMessages = false; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.components.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts similarity index 96% rename from src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.components.ts rename to src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts index 1c119a7223..04b5cf170d 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.components.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts @@ -23,7 +23,7 @@ import { } from '@ng-dynamic-forms/core'; import { isEqual, isObject } from 'lodash'; -import { DynamicGroupModel, PLACEHOLDER_PARENT_METADATA } from './dynamic-group.model'; +import { DynamicRelationGroupModel, PLACEHOLDER_PARENT_METADATA } from './dynamic-relation-group.model'; import { FormBuilderService } from '../../../form-builder.service'; import { SubmissionFormsModel } from '../../../../../../core/config/models/config-submission-forms.model'; import { FormService } from '../../../../form.service'; @@ -42,17 +42,16 @@ import { FormFieldMetadataValueObject } from '../../../models/form-field-metadat import { AuthorityValue } from '../../../../../../core/integration/models/authority.value'; @Component({ - selector: 'ds-dynamic-group', - styleUrls: ['./dynamic-group.component.scss'], - templateUrl: './dynamic-group.component.html', + selector: 'ds-dynamic-relation-group', + styleUrls: ['./dynamic-relation-group.component.scss'], + templateUrl: './dynamic-relation-group.component.html', animations: [shrinkInOut] }) -export class DsDynamicGroupComponent extends DynamicFormControlComponent implements OnDestroy, OnInit { +export class DsDynamicRelationGroupComponent extends DynamicFormControlComponent implements OnDestroy, OnInit { @Input() formId: string; @Input() group: FormGroup; - @Input() model: DynamicGroupModel; - @Input() showErrorMessages = false; + @Input() model: DynamicRelationGroupModel; @Output() blur: EventEmitter = new EventEmitter(); @Output() change: EventEmitter = new EventEmitter(); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model.ts similarity index 87% rename from src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model.ts rename to src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model.ts index bccbcabfc1..7a357dfc31 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model.ts @@ -1,7 +1,6 @@ import { DynamicFormControlLayout, serializable } from '@ng-dynamic-forms/core'; import { FormRowModel } from '../../../../../../core/config/models/config-submission-forms.model'; import { DsDynamicInputModel, DsDynamicInputModelConfig } from '../ds-dynamic-input.model'; -import { AuthorityValue } from '../../../../../../core/integration/models/authority.value'; import { isEmpty, isNull } from '../../../../../empty.util'; export const DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP = 'RELATION'; @@ -10,7 +9,7 @@ export const PLACEHOLDER_PARENT_METADATA = '#PLACEHOLDER_PARENT_METADATA_VALUE#' /** * Dynamic Group Model configuration interface */ -export interface DynamicGroupModelConfig extends DsDynamicInputModelConfig { +export interface DynamicRelationGroupModelConfig extends DsDynamicInputModelConfig { formConfiguration: FormRowModel[], mandatoryField: string, relationFields: string[], @@ -21,7 +20,7 @@ export interface DynamicGroupModelConfig extends DsDynamicInputModelConfig { /** * Dynamic Group Model class */ -export class DynamicGroupModel extends DsDynamicInputModel { +export class DynamicRelationGroupModel extends DsDynamicInputModel { @serializable() formConfiguration: FormRowModel[]; @serializable() mandatoryField: string; @serializable() relationFields: string[]; @@ -30,7 +29,7 @@ export class DynamicGroupModel extends DsDynamicInputModel { @serializable() _value: any[]; @serializable() readonly type: string = DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP; - constructor(config: DynamicGroupModelConfig, layout?: DynamicFormControlLayout) { + constructor(config: DynamicRelationGroupModelConfig, layout?: DynamicFormControlLayout) { super(config, layout); this.formConfiguration = config.formConfiguration; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts index 3b54226654..de39dacb55 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts @@ -27,7 +27,6 @@ export class DsDynamicScrollableDropdownComponent extends DynamicFormControlComp @Input() bindId = true; @Input() group: FormGroup; @Input() model: DynamicScrollableDropdownModel; - @Input() showErrorMessages = false; @Output() blur: EventEmitter = new EventEmitter(); @Output() change: EventEmitter = new EventEmitter(); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts index a5b0f48a4f..9aeada5032 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts @@ -23,6 +23,7 @@ import { Chips } from '../../../../../chips/models/chips.model'; import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model'; import { AuthorityValue } from '../../../../../../core/integration/models/authority.value'; import { createTestComponent } from '../../../../../testing/utils'; +import { MOCK_SUBMISSION_CONFIG } from '../../../../../testing/mock-submission-config'; function createKeyUpEvent(key: number) { /* tslint:disable:no-empty */ @@ -39,6 +40,7 @@ function createKeyUpEvent(key: number) { let TAG_TEST_GROUP; let TAG_TEST_MODEL_CONFIG; +const envConfig: GlobalConfig = MOCK_SUBMISSION_CONFIG; function init() { TAG_TEST_GROUP = new FormGroup({ @@ -94,7 +96,7 @@ describe('DsDynamicTagComponent test suite', () => { ChangeDetectorRef, DsDynamicTagComponent, { provide: AuthorityService, useValue: authorityServiceStub }, - { provide: GLOBAL_CONFIG, useValue: {} as GlobalConfig }, + { provide: GLOBAL_CONFIG, useValue: envConfig }, { provide: DynamicFormLayoutService, useValue: {} }, { provide: DynamicFormValidationService, useValue: {} } ], @@ -110,7 +112,6 @@ describe('DsDynamicTagComponent test suite', () => { `; @@ -161,7 +162,6 @@ describe('DsDynamicTagComponent test suite', () => { it('should select a results entry properly', fakeAsync(() => { modelValue = [ Object.assign(new AuthorityValue(), { id: 1, display: 'Name, Lastname', value: 1 }) - Object.assign(new AuthorityValue(), {id: 1, display: 'Name, Lastname', value: 1}) ]; const event: NgbTypeaheadSelectItemEvent = { item: Object.assign(new AuthorityValue(), { @@ -169,7 +169,6 @@ describe('DsDynamicTagComponent test suite', () => { display: 'Name, Lastname', value: 1 }), - item: Object.assign(new AuthorityValue(), {id: 1, display: 'Name, Lastname', value: 1}), preventDefault: () => { return; } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts index 4370986870..35bb6e1e31 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts @@ -29,7 +29,6 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement @Input() bindId = true; @Input() group: FormGroup; @Input() model: DynamicTagModel; - @Input() showErrorMessages = false; @Output() blur: EventEmitter = new EventEmitter(); @Output() change: EventEmitter = new EventEmitter(); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.spec.ts index c950f8f4ef..18797b69f7 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.spec.ts @@ -1,31 +1,34 @@ // Load the implementations that should be tested import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { async, ComponentFixture, fakeAsync, inject, TestBed, } from '@angular/core/testing'; +import { async, ComponentFixture, fakeAsync, inject, TestBed, tick, } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; + import { of as observableOf } from 'rxjs'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { DynamicFormLayoutService, DynamicFormsCoreModule, DynamicFormValidationService } from '@ng-dynamic-forms/core'; +import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap'; +import { TranslateModule } from '@ngx-translate/core'; import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model'; -import { - DynamicFormLayoutService, - DynamicFormsCoreModule, - DynamicFormValidationService -} from '@ng-dynamic-forms/core'; -import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap'; import { AuthorityService } from '../../../../../../core/integration/authority.service'; import { AuthorityServiceStub } from '../../../../../testing/authority-service-stub'; import { GlobalConfig } from '../../../../../../../config/global-config.interface'; import { GLOBAL_CONFIG } from '../../../../../../../config'; -import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { DsDynamicTypeaheadComponent } from './dynamic-typeahead.component'; import { DynamicTypeaheadModel } from './dynamic-typeahead.model'; import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model'; import { createTestComponent } from '../../../../../testing/utils'; +import { AuthorityConfidenceStateDirective } from '../../../../../authority-confidence/authority-confidence-state.directive'; +import { MOCK_SUBMISSION_CONFIG } from '../../../../../testing/mock-submission-config'; +import { ObjNgFor } from '../../../../../utils/object-ngfor.pipe'; export let TYPEAHEAD_TEST_GROUP; export let TYPEAHEAD_TEST_MODEL_CONFIG; +const envConfig: GlobalConfig = MOCK_SUBMISSION_CONFIG; + function init() { TYPEAHEAD_TEST_GROUP = new FormGroup({ typeahead: new FormControl(), @@ -61,7 +64,7 @@ describe('DsDynamicTypeaheadComponent test suite', () => { // async beforeEach beforeEach(async(() => { const authorityServiceStub = new AuthorityServiceStub(); - init() + init(); TestBed.configureTestingModule({ imports: [ DynamicFormsCoreModule, @@ -69,14 +72,18 @@ describe('DsDynamicTypeaheadComponent test suite', () => { FormsModule, NgbModule.forRoot(), ReactiveFormsModule, + TranslateModule.forRoot() ], declarations: [ DsDynamicTypeaheadComponent, TestComponent, + AuthorityConfidenceStateDirective, + ObjNgFor ], // declare the test component providers: [ ChangeDetectorRef, DsDynamicTypeaheadComponent, + { provide: GLOBAL_CONFIG, useValue: envConfig }, { provide: AuthorityService, useValue: authorityServiceStub }, { provide: DynamicFormLayoutService, useValue: {} }, { provide: DynamicFormValidationService, useValue: {} } @@ -130,13 +137,16 @@ describe('DsDynamicTypeaheadComponent test suite', () => { expect(typeaheadComp.currentValue).not.toBeDefined(); }); - it('should search when 3+ characters typed', fakeAsync(() => { + it('should search when 3+ characters typed', fakeAsync((done) => { + spyOn((typeaheadComp as any).authorityService, 'getEntriesByName').and.callThrough(); - typeaheadComp.search(observableOf('test')).subscribe(() => { - expect((typeaheadComp as any).authorityService.getEntriesByName).toHaveBeenCalled(); - }); + typeaheadComp.search(observableOf('test')).subscribe(); + tick(300); + typeaheadFixture.detectChanges(); + + expect((typeaheadComp as any).authorityService.getEntriesByName).toHaveBeenCalled(); })); it('should set model.value on input type when AuthorityOptions.closed is false', () => { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts index 142fbb0b86..ace6812858 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts @@ -27,7 +27,6 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp @Input() bindId = true; @Input() group: FormGroup; @Input() model: DynamicTypeaheadModel; - @Input() showErrorMessages = false; @Output() blur: EventEmitter = new EventEmitter(); @Output() change: EventEmitter = new EventEmitter(); diff --git a/src/app/shared/form/builder/form-builder.service.spec.ts b/src/app/shared/form/builder/form-builder.service.spec.ts index 80a4497dd6..b092b87a5a 100644 --- a/src/app/shared/form/builder/form-builder.service.spec.ts +++ b/src/app/shared/form/builder/form-builder.service.spec.ts @@ -31,7 +31,7 @@ import { DynamicTagModel } from './ds-dynamic-form-ui/models/tag/dynamic-tag.mod import { DynamicListCheckboxGroupModel } from './ds-dynamic-form-ui/models/list/dynamic-list-checkbox-group.model'; import { DynamicQualdropModel } from './ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model'; import { DynamicScrollableDropdownModel } from './ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.model'; -import { DynamicGroupModel } from './ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; +import { DynamicRelationGroupModel } from './ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model'; import { DynamicLookupModel } from './ds-dynamic-form-ui/models/lookup/dynamic-lookup.model'; import { DynamicDsDatePickerModel } from './ds-dynamic-form-ui/models/date-picker/date-picker.model'; import { DynamicTypeaheadModel } from './ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.model'; @@ -203,7 +203,7 @@ describe('FormBuilderService test suite', () => { new DynamicListRadioGroupModel({id: 'testRadioList', authorityOptions: authorityOptions, repeatable: false}), - new DynamicGroupModel({ + new DynamicRelationGroupModel({ id: 'testRelationGroup', formConfiguration: [{ fields: [{ diff --git a/src/app/shared/form/builder/form-builder.service.ts b/src/app/shared/form/builder/form-builder.service.ts index 918515a984..630e9280ff 100644 --- a/src/app/shared/form/builder/form-builder.service.ts +++ b/src/app/shared/form/builder/form-builder.service.ts @@ -4,7 +4,8 @@ import { AbstractControl, FormGroup } from '@angular/forms'; import { DYNAMIC_FORM_CONTROL_TYPE_ARRAY, DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX_GROUP, - DYNAMIC_FORM_CONTROL_TYPE_GROUP, DYNAMIC_FORM_CONTROL_TYPE_INPUT, + DYNAMIC_FORM_CONTROL_TYPE_GROUP, + DYNAMIC_FORM_CONTROL_TYPE_INPUT, DYNAMIC_FORM_CONTROL_TYPE_RADIO_GROUP, DynamicFormArrayModel, DynamicFormControlModel, @@ -18,13 +19,12 @@ import { isObject, isString, mergeWith } from 'lodash'; import { hasValue, isEmpty, isNotEmpty, isNotNull, isNotUndefined, isNull } from '../../empty.util'; import { DynamicQualdropModel } from './ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model'; import { SubmissionFormsModel } from '../../../core/config/models/config-submission-forms.model'; -import { - DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP, - DynamicGroupModel -} from './ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; import { DYNAMIC_FORM_CONTROL_TYPE_TAG } from './ds-dynamic-form-ui/models/tag/dynamic-tag.model'; import { RowParser } from './parsers/row-parser'; - +import { + DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP, + DynamicRelationGroupModel +} from './ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model'; import { DynamicRowArrayModel } from './ds-dynamic-form-ui/models/ds-dynamic-row-array-model'; import { DsDynamicInputModel } from './ds-dynamic-form-ui/models/ds-dynamic-input.model'; import { FormFieldMetadataValueObject } from './models/form-field-metadata-value.model'; @@ -158,7 +158,7 @@ export class FormBuilderService extends DynamicFormService { } if (this.isRelationGroup(controlModel)) { - const values = (controlModel as DynamicGroupModel).getGroupValue(); + const values = (controlModel as DynamicRelationGroupModel).getGroupValue(); values.forEach((groupValue, groupIndex) => { const newGroupValue = Object.create({}); Object.keys(groupValue) diff --git a/src/app/shared/form/builder/models/form-field-metadata-value.model.ts b/src/app/shared/form/builder/models/form-field-metadata-value.model.ts index a189ff95a0..10b3667676 100644 --- a/src/app/shared/form/builder/models/form-field-metadata-value.model.ts +++ b/src/app/shared/form/builder/models/form-field-metadata-value.model.ts @@ -1,6 +1,6 @@ import { isEmpty, isNotEmpty, isNotNull } from '../../../empty.util'; import { ConfidenceType } from '../../../../core/integration/models/confidence-type'; -import { PLACEHOLDER_PARENT_METADATA } from '../ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; +import { PLACEHOLDER_PARENT_METADATA } from '../ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model'; export class FormFieldMetadataValueObject { metadata?: string; diff --git a/src/app/shared/form/builder/models/form-field-unexpected-object.model.ts b/src/app/shared/form/builder/models/form-field-unexpected-object.model.ts deleted file mode 100644 index 1b37498a64..0000000000 --- a/src/app/shared/form/builder/models/form-field-unexpected-object.model.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface FormFieldChangedObject { - string: any -} diff --git a/src/app/shared/form/builder/parsers/field-parser.ts b/src/app/shared/form/builder/parsers/field-parser.ts index 3286b3fdbb..28e3fb8fb5 100644 --- a/src/app/shared/form/builder/parsers/field-parser.ts +++ b/src/app/shared/form/builder/parsers/field-parser.ts @@ -202,6 +202,14 @@ export abstract class FieldParser { if (this.configData.languageCodes && this.configData.languageCodes.length > 0) { (controlModel as DsDynamicInputModel).languageCodes = this.configData.languageCodes; } +/* (controlModel as DsDynamicInputModel).languageCodes = [{ + display: 'English', + code: 'en_US' + }, + { + display: 'Italian', + code: 'it_IT' + }];*/ return controlModel; } @@ -278,16 +286,6 @@ export abstract class FieldParser { } else { modelConfig.value = fieldValue.value; } - // if (hasValue(fieldValue.language)) { - // // Instance of FormFieldLanguageValueObject - // modelConfig.value = fieldValue.value; - // } else if (hasValue(fieldValue.metadata)) { - // // Is a combobox field's value - // modelConfig.value = fieldValue.value; - // } else { - // // Instance of FormFieldMetadataValueObject - // modelConfig.value = fieldValue; - // } } else { if (forceValueAsObj) { // If value isn't an instance of FormFieldMetadataValueObject instantiate it diff --git a/src/app/shared/form/builder/parsers/onebox-field-parser.ts b/src/app/shared/form/builder/parsers/onebox-field-parser.ts index 8949972918..e1c5f40039 100644 --- a/src/app/shared/form/builder/parsers/onebox-field-parser.ts +++ b/src/app/shared/form/builder/parsers/onebox-field-parser.ts @@ -29,7 +29,7 @@ export class OneboxFieldParser extends FieldParser { const clsSelect = { element: { - control: 'input-group-addon ds-form-input-addon', + control: 'ds-form-input-addon custom-select', }, grid: { host: 'col-sm-4 pr-0' @@ -74,11 +74,27 @@ export class OneboxFieldParser extends FieldParser { this.setAuthorityOptions(typeaheadModelConfig, this.parserOptions.authorityUuid); this.setValues(typeaheadModelConfig, fieldValue, true); const typeaheadModel = new DynamicTypeaheadModel(typeaheadModelConfig); +/* typeaheadModel.languageCodes = [{ + display: 'English', + code: 'en_US' + }, + { + display: 'Italian', + code: 'it_IT' + }];*/ return typeaheadModel; } else { const inputModelConfig: DsDynamicInputModelConfig = this.initModel(null, label); this.setValues(inputModelConfig, fieldValue); const inputModel = new DsDynamicInputModel(inputModelConfig); +/* inputModel.languageCodes = [{ + display: 'English', + code: 'en_US' + }, + { + display: 'Italian', + code: 'it_IT' + }];*/ return inputModel; } } diff --git a/src/app/shared/form/builder/parsers/parser-factory.ts b/src/app/shared/form/builder/parsers/parser-factory.ts index da5bee0be2..2cbee18783 100644 --- a/src/app/shared/form/builder/parsers/parser-factory.ts +++ b/src/app/shared/form/builder/parsers/parser-factory.ts @@ -3,7 +3,7 @@ import { GenericConstructor } from '../../../../core/shared/generic-constructor' import { FieldParser } from './field-parser'; import { DateFieldParser } from './date-field-parser'; import { DropdownFieldParser } from './dropdown-field-parser'; -import { GroupFieldParser } from './group-field-parser'; +import { RelationGroupFieldParser } from './relation-group-field-parser'; import { ListFieldParser } from './list-field-parser'; import { LookupFieldParser } from './lookup-field-parser'; import { LookupNameFieldParser } from './lookup-name-field-parser'; @@ -22,8 +22,8 @@ export class ParserFactory { case ParserType.Dropdown: { return DropdownFieldParser } - case ParserType.Group: { - return GroupFieldParser + case ParserType.RelationGroup: { + return RelationGroupFieldParser } case ParserType.List: { return ListFieldParser diff --git a/src/app/shared/form/builder/parsers/parser-type.ts b/src/app/shared/form/builder/parsers/parser-type.ts index d6bddf867c..a9af87d73f 100644 --- a/src/app/shared/form/builder/parsers/parser-type.ts +++ b/src/app/shared/form/builder/parsers/parser-type.ts @@ -1,7 +1,7 @@ export enum ParserType { Date = 'date', Dropdown = 'dropdown', - Group = 'group', + RelationGroup = 'group', List = 'list', Lookup = 'lookup', LookupName = 'lookup-name', diff --git a/src/app/shared/form/builder/parsers/group-field-parser.spec.ts b/src/app/shared/form/builder/parsers/relation-group-field-parser.spec.ts similarity index 75% rename from src/app/shared/form/builder/parsers/group-field-parser.spec.ts rename to src/app/shared/form/builder/parsers/relation-group-field-parser.spec.ts index abda8d7169..e6bf0dc2c8 100644 --- a/src/app/shared/form/builder/parsers/group-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/relation-group-field-parser.spec.ts @@ -1,10 +1,10 @@ import { FormFieldModel } from '../models/form-field.model'; -import { GroupFieldParser } from './group-field-parser'; -import { DynamicGroupModel } from '../ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; +import { RelationGroupFieldParser } from './relation-group-field-parser'; +import { DynamicRelationGroupModel } from '../ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; import { ParserOptions } from './parser-options'; -describe('GroupFieldParser test suite', () => { +describe('RelationGroupFieldParser test suite', () => { let field: FormFieldModel; let initFormValues = {}; @@ -71,22 +71,22 @@ describe('GroupFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new GroupFieldParser(field, initFormValues, parserOptions); + const parser = new RelationGroupFieldParser(field, initFormValues, parserOptions); - expect(parser instanceof GroupFieldParser).toBe(true); + expect(parser instanceof RelationGroupFieldParser).toBe(true); }); - it('should return a DynamicGroupModel object', () => { - const parser = new GroupFieldParser(field, initFormValues, parserOptions); + it('should return a DynamicRelationGroupModel object', () => { + const parser = new RelationGroupFieldParser(field, initFormValues, parserOptions); const fieldModel = parser.parse(); - expect(fieldModel instanceof DynamicGroupModel).toBe(true); + expect(fieldModel instanceof DynamicRelationGroupModel).toBe(true); }); it('should throw when rows configuration is empty', () => { field.rows = null; - const parser = new GroupFieldParser(field, initFormValues, parserOptions); + const parser = new RelationGroupFieldParser(field, initFormValues, parserOptions); expect(() => parser.parse()) .toThrow(); @@ -97,7 +97,7 @@ describe('GroupFieldParser test suite', () => { author: [new FormFieldMetadataValueObject('test author')], affiliation: [new FormFieldMetadataValueObject('test affiliation')] }; - const parser = new GroupFieldParser(field, initFormValues, parserOptions); + const parser = new RelationGroupFieldParser(field, initFormValues, parserOptions); const fieldModel = parser.parse(); const expectedValue = [{ diff --git a/src/app/shared/form/builder/parsers/group-field-parser.ts b/src/app/shared/form/builder/parsers/relation-group-field-parser.ts similarity index 86% rename from src/app/shared/form/builder/parsers/group-field-parser.ts rename to src/app/shared/form/builder/parsers/relation-group-field-parser.ts index 61edaf7f99..ca0469ef1a 100644 --- a/src/app/shared/form/builder/parsers/group-field-parser.ts +++ b/src/app/shared/form/builder/parsers/relation-group-field-parser.ts @@ -1,18 +1,19 @@ import { FieldParser } from './field-parser'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; import { FormFieldModel } from '../models/form-field.model'; -import { - DynamicGroupModel, - DynamicGroupModelConfig, - PLACEHOLDER_PARENT_METADATA -} from '../ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; + import { isNotEmpty } from '../../../empty.util'; import { FormRowModel } from '../../../../core/config/models/config-submission-forms.model'; +import { + DynamicRelationGroupModel, + DynamicRelationGroupModelConfig, + PLACEHOLDER_PARENT_METADATA +} from '../ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model'; -export class GroupFieldParser extends FieldParser { +export class RelationGroupFieldParser extends FieldParser { public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean) { - const modelConfiguration: DynamicGroupModelConfig = this.initModel(null, label); + const modelConfiguration: DynamicRelationGroupModelConfig = this.initModel(null, label); modelConfiguration.scopeUUID = this.parserOptions.authorityUuid; modelConfiguration.submissionScope = this.parserOptions.submissionScope; @@ -54,7 +55,7 @@ export class GroupFieldParser extends FieldParser { } }; - const model = new DynamicGroupModel(modelConfiguration, cls); + const model = new DynamicRelationGroupModel(modelConfiguration, cls); model.name = this.getFieldId(); return model; } diff --git a/src/app/shared/form/builder/parsers/row-parser.ts b/src/app/shared/form/builder/parsers/row-parser.ts index a09d84562c..0bb8a0e89a 100644 --- a/src/app/shared/form/builder/parsers/row-parser.ts +++ b/src/app/shared/form/builder/parsers/row-parser.ts @@ -2,7 +2,7 @@ import { DYNAMIC_FORM_CONTROL_TYPE_ARRAY, DynamicFormGroupModelConfig } from '@n import { uniqueId } from 'lodash'; import { IntegrationSearchOptions } from '../../../../core/integration/models/integration-options.model'; -import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from '../ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; +import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from '../ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model'; import { DynamicRowGroupModel } from '../ds-dynamic-form-ui/models/ds-dynamic-row-group-model'; import { isEmpty } from '../../../empty.util'; import { setLayout } from './parser.utils'; @@ -10,7 +10,6 @@ import { FormFieldModel } from '../models/form-field.model'; import { ParserType } from './parser-type'; import { ParserOptions } from './parser-options'; import { ParserFactory } from './parser-factory'; -import { TranslateService } from '@ngx-translate/core'; export const ROW_ID_PREFIX = 'df-row-group-config-'; diff --git a/src/app/shared/form/form.component.scss b/src/app/shared/form/form.component.scss index 0f8145f262..8530a2383c 100644 --- a/src/app/shared/form/form.component.scss +++ b/src/app/shared/form/form.component.scss @@ -1,9 +1,9 @@ @import "../../../styles/_variables.scss"; .ds-form-input-addon { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - border-right: 0; + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important; + border-right: 0 !important; } .ds-form-input-btn { @@ -18,6 +18,6 @@ } .ds-form-input-value { - border-top-left-radius: 0; - border-bottom-left-radius: 0; + border-top-left-radius: 0 !important; + border-bottom-left-radius: 0 !important; } diff --git a/src/app/shared/form/form.component.ts b/src/app/shared/form/form.component.ts index 2d74ddf8d4..69132c29c0 100644 --- a/src/app/shared/form/form.component.ts +++ b/src/app/shared/form/form.component.ts @@ -6,7 +6,7 @@ import { Input, OnDestroy, OnInit, - Output + Output, ViewEncapsulation } from '@angular/core'; import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; @@ -32,6 +32,7 @@ import { FormEntry, FormError } from './form.reducer'; selector: 'ds-form', styleUrls: ['form.component.scss'], templateUrl: 'form.component.html', + encapsulation: ViewEncapsulation.Native }) export class FormComponent implements OnDestroy, OnInit { diff --git a/src/app/shared/notifications/notification/notification.component.spec.ts b/src/app/shared/notifications/notification/notification.component.spec.ts index a0dbfc4afe..72c9d93841 100644 --- a/src/app/shared/notifications/notification/notification.component.spec.ts +++ b/src/app/shared/notifications/notification/notification.component.spec.ts @@ -10,7 +10,6 @@ import { NotificationsService } from '../notifications.service'; import { NotificationType } from '../models/notification-type'; import { notificationsReducer } from '../notifications.reducers'; import { NotificationOptions } from '../models/notification-options.model'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { INotificationBoardOptions } from '../../../../config/notifications-config.interfaces'; import { GlobalConfig } from '../../../../config/global-config.interface'; import { Notification } from '../models/notification.model'; diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index eb52041f74..5ae1795247 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -4,12 +4,7 @@ import { RouterModule } from '@angular/router'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { NouisliderModule } from 'ng2-nouislider'; -import { - NgbDatepickerModule, - NgbModule, - NgbTimepickerModule, - NgbTypeaheadModule -} from '@ng-bootstrap/ng-bootstrap'; +import { NgbDatepickerModule, NgbModule, NgbTimepickerModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule } from '@ngx-translate/core'; @@ -56,9 +51,12 @@ import { LogOutComponent } from './log-out/log-out.component'; import { FormComponent } from './form/form.component'; import { DsDynamicTypeaheadComponent } from './form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component'; import { DsDynamicScrollableDropdownComponent } from './form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component'; -import { DsDynamicFormControlComponent } from './form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component'; +import { + DsDynamicFormControlContainerComponent, + dsDynamicFormControlMapFn +} from './form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component'; import { DsDynamicFormComponent } from './form/builder/ds-dynamic-form-ui/ds-dynamic-form.component'; -import { DynamicFormsCoreModule } from '@ng-dynamic-forms/core'; +import { DYNAMIC_FORM_CONTROL_MAP_FN, DynamicFormsCoreModule } from '@ng-dynamic-forms/core'; import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap'; import { TextMaskModule } from 'angular2-text-mask'; import { DragClickDirective } from './utils/drag-click.directive'; @@ -70,7 +68,9 @@ import { UploaderComponent } from './uploader/uploader.component'; import { ChipsComponent } from './chips/chips.component'; import { DsDynamicTagComponent } from './form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component'; import { DsDynamicListComponent } from './form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component'; -import { DsDynamicGroupComponent } from './form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.components'; +import { DsDynamicFormGroupComponent } from './form/builder/ds-dynamic-form-ui/models/form-group/dynamic-form-group.component'; +import { DsDynamicFormArrayComponent } from './form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component'; +import { DsDynamicRelationGroupComponent } from './form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components'; import { SortablejsModule } from 'angular-sortablejs'; import { NumberPickerComponent } from './number-picker/number-picker.component'; import { DsDatePickerComponent } from './form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component'; @@ -78,7 +78,6 @@ import { DsDynamicLookupComponent } from './form/builder/ds-dynamic-form-ui/mode import { MockAdminGuard } from './mocks/mock-admin-guard.service'; import { AlertsComponent } from './alerts/alerts.component'; import { ObjNgFor } from './utils/object-ngfor.pipe'; -import { BrowseByModule } from '../+browse-by/browse-by.module'; import { BrowseByComponent } from './browse-by/browse-by.component'; import { BrowseEntryListElementComponent } from './object-list/browse-entry-list-element/browse-entry-list-element.component'; import { DebounceDirective } from './utils/debounce.directive'; @@ -134,14 +133,16 @@ const COMPONENTS = [ ComcolPageHeaderComponent, ComcolPageLogoComponent, DsDynamicFormComponent, - DsDynamicFormControlComponent, + DsDynamicFormControlContainerComponent, DsDynamicListComponent, DsDynamicLookupComponent, DsDynamicScrollableDropdownComponent, DsDynamicTagComponent, DsDynamicTypeaheadComponent, - DsDynamicGroupComponent, + DsDynamicRelationGroupComponent, DsDatePickerComponent, + DsDynamicFormGroupComponent, + DsDynamicFormArrayComponent, ErrorComponent, FormComponent, LoadingComponent, @@ -177,12 +178,25 @@ const ENTRY_COMPONENTS = [ CollectionGridElementComponent, CommunityGridElementComponent, SearchResultGridElementComponent, - BrowseEntryListElementComponent + BrowseEntryListElementComponent, + DsDynamicListComponent, + DsDynamicLookupComponent, + DsDynamicScrollableDropdownComponent, + DsDynamicTagComponent, + DsDynamicTypeaheadComponent, + DsDynamicRelationGroupComponent, + DsDatePickerComponent, + DsDynamicFormGroupComponent, + DsDynamicFormArrayComponent ]; const PROVIDERS = [ TruncatableService, - MockAdminGuard + MockAdminGuard, + { + provide: DYNAMIC_FORM_CONTROL_MAP_FN, + useValue: dsDynamicFormControlMapFn + } ]; const DIRECTIVES = [ diff --git a/src/app/shared/testing/mock-submission-config.ts b/src/app/shared/testing/mock-submission-config.ts new file mode 100644 index 0000000000..212a2fc5f3 --- /dev/null +++ b/src/app/shared/testing/mock-submission-config.ts @@ -0,0 +1,54 @@ +import { SubmissionConfig } from '../../../config/submission-config.interface'; +import { GlobalConfig } from '../../../config/global-config.interface'; + +export const MOCK_SUBMISSION_CONFIG = { + submission: { + autosave: { + // NOTE: which metadata trigger an autosave + metadata: ['dc.title', 'dc.identifier.doi', 'dc.identifier.pmid', 'dc.identifier.arxiv'], + // NOTE: every how many minutes submission is saved automatically + timer: 5 + }, + icons: { + metadata: [ + { + name: 'mainField', + style: 'fa-user' + }, + { + name: 'relatedField', + style: 'fa-university' + }, + { + name: 'otherRelatedField', + style: 'fa-circle' + }, + { + name: 'default', + style: '' + } + ], + authority: { + confidence: [ + { + value: 600, + style: 'text-success' + }, + { + value: 500, + style: 'text-info' + }, + { + value: 400, + style: 'text-warning' + }, + { + value: 'default', + style: 'text-muted' + }, + + ] + } + } + } as SubmissionConfig +} as GlobalConfig; diff --git a/src/app/submission/sections/form/form-operations.service.ts b/src/app/submission/sections/form/form-operations.service.ts index f79f824f77..b024f3226d 100644 --- a/src/app/submission/sections/form/form-operations.service.ts +++ b/src/app/submission/sections/form/form-operations.service.ts @@ -19,7 +19,7 @@ import { AuthorityValue } from '../../../core/integration/models/authority.value import { FormBuilderService } from '../../../shared/form/builder/form-builder.service'; import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model'; import { DynamicQualdropModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model'; -import { DynamicGroupModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; +import { DynamicRelationGroupModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model'; @Injectable() export class FormOperationsService { @@ -135,7 +135,7 @@ export class FormOperationsService { if (this.formBuilder.isModelInCustomGroup(event.model)) { fieldValue = (event.model.parent as any).value; } else if (this.formBuilder.isRelationGroup(event.model)) { - fieldValue = (event.model as DynamicGroupModel).getGroupValue(); + fieldValue = (event.model as DynamicRelationGroupModel).getGroupValue(); } else if ((event.model as any).hasLanguages) { const language = (event.model as any).language; if ((event.model as DsDynamicInputModel).hasAuthority) {