[CST-3088] Replace use of AuthorityService with new VocabularyService

This commit is contained in:
Giuseppe Digilio
2020-06-25 15:21:44 +02:00
parent 3117916d5b
commit 63cca76b49
59 changed files with 740 additions and 706 deletions

View File

@@ -86,9 +86,6 @@ import { EPersonDataService } from './eperson/eperson-data.service';
import { EpersonResponseParsingService } from './eperson/eperson-response-parsing.service';
import { EPerson } from './eperson/models/eperson.model';
import { Group } from './eperson/models/group.model';
import { AuthorityService } from './integration/authority.service';
import { IntegrationResponseParsingService } from './integration/integration-response-parsing.service';
import { AuthorityValue } from './integration/models/authority.value';
import { JsonPatchOperationsBuilder } from './json-patch/builder/json-patch-operations-builder';
import { MetadataField } from './metadata/metadata-field.model';
import { MetadataSchema } from './metadata/metadata-schema.model';
@@ -148,6 +145,8 @@ import { WorkflowAction } from './tasks/models/workflow-action-object.model';
import { VocabularyEntry } from './submission/vocabularies/models/vocabulary-entry.model';
import { Vocabulary } from './submission/vocabularies/models/vocabulary.model';
import { VocabularyEntriesResponseParsingService } from './submission/vocabularies/vocabulary-entries-response-parsing.service';
import { VocabularyEntryDetail } from './submission/vocabularies/models/vocabulary-entry-detail.model';
import { VocabularyService } from './submission/vocabularies/vocabulary.service';
/**
* When not in production, endpoint responses can be mocked for testing purposes
@@ -224,8 +223,6 @@ const PROVIDERS = [
SubmissionResponseParsingService,
SubmissionJsonPatchOperationsService,
JsonPatchOperationsBuilder,
AuthorityService,
IntegrationResponseParsingService,
MetadataschemaParsingService,
MetadatafieldParsingService,
UploaderService,
@@ -276,6 +273,7 @@ const PROVIDERS = [
NotificationsService,
FilteredDiscoveryPageResponseParsingService,
{ provide: NativeWindowService, useFactory: NativeWindowFactory },
VocabularyService,
VocabularyEntriesResponseParsingService
];
@@ -305,7 +303,6 @@ export const models =
SubmissionSectionModel,
SubmissionUploadsModel,
AuthStatus,
AuthorityValue,
BrowseEntry,
BrowseDefinition,
ClaimedTask,
@@ -320,7 +317,8 @@ export const models =
VersionHistory,
WorkflowAction,
Vocabulary,
VocabularyEntry
VocabularyEntry,
VocabularyEntryDetail
];
@NgModule({

View File

@@ -9,7 +9,7 @@ import { JsonPatchOperationPathObject } from './json-patch-operation-path-combin
import { Injectable } from '@angular/core';
import { isEmpty, isNotEmpty } from '../../../shared/empty.util';
import { dateToISOFormat } from '../../../shared/date.util';
import { AuthorityValue } from '../../integration/models/authority.value';
import { VocabularyEntry } from '../../submission/vocabularies/models/vocabulary-entry.model';
import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model';
import { FormFieldLanguageValueObject } from '../../../shared/form/builder/models/form-field-language-value.model';
@@ -106,7 +106,7 @@ export class JsonPatchOperationsBuilder {
operationValue = value;
} else if (value instanceof Date) {
operationValue = new FormFieldMetadataValueObject(dateToISOFormat(value));
} else if (value instanceof AuthorityValue) {
} else if (value instanceof VocabularyEntry) {
operationValue = this.prepareAuthorityValue(value);
} else if (value instanceof FormFieldLanguageValueObject) {
operationValue = new FormFieldMetadataValueObject(value.value, value.language);
@@ -127,8 +127,8 @@ export class JsonPatchOperationsBuilder {
protected prepareAuthorityValue(value: any) {
let operationValue: any = null;
if (isNotEmpty(value.id)) {
operationValue = new FormFieldMetadataValueObject(value.value, value.language, value.id);
if (isNotEmpty(value.authority)) {
operationValue = new FormFieldMetadataValueObject(value.value, value.language, value.authority);
} else {
operationValue = new FormFieldMetadataValueObject(value.value, value.language);
}

View File

@@ -74,9 +74,7 @@ class VocabularyEntryDetailDataServiceImpl extends DataService<VocabularyEntryDe
/**
* A service responsible for fetching/sending data from/to the REST API on the vocabularies endpoint
*/
@Injectable({
providedIn: 'root'
})
@Injectable()
@dataService(VOCABULARY)
export class VocabularyService {
protected searchByMetadataAndCollectionMethod = 'byMetadataAndCollection';

View File

@@ -13,12 +13,13 @@ import {
import { findIndex } from 'lodash';
import { AuthorityValue } from '../../core/integration/models/authority.value';
import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
import { ConfidenceType } from '../../core/integration/models/confidence-type';
import { ConfidenceType } from '../../core/shared/confidence-type';
import { isNotEmpty, isNull } from '../empty.util';
import { ConfidenceIconConfig } from '../../../config/submission-config.interface';
import { environment } from '../../../environments/environment';
import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
/**
* Directive to add to the element a bootstrap utility class based on metadata confidence value
@@ -31,7 +32,7 @@ export class AuthorityConfidenceStateDirective implements OnChanges, AfterViewIn
/**
* The metadata value
*/
@Input() authorityValue: AuthorityValue | FormFieldMetadataValueObject | string;
@Input() authorityValue: VocabularyEntry | FormFieldMetadataValueObject | string;
/**
* A boolean representing if to show html icon if authority value is empty
@@ -65,7 +66,6 @@ export class AuthorityConfidenceStateDirective implements OnChanges, AfterViewIn
/**
* Initialize instance variables
*
* @param {GlobalConfig} EnvConfig
* @param {ElementRef} elem
* @param {Renderer2} renderer
*/
@@ -114,7 +114,8 @@ export class AuthorityConfidenceStateDirective implements OnChanges, AfterViewIn
private getConfidenceByValue(value: any): ConfidenceType {
let confidence: ConfidenceType = ConfidenceType.CF_UNSET;
if (isNotEmpty(value) && value instanceof AuthorityValue && value.hasAuthority()) {
if (isNotEmpty(value) && (value instanceof VocabularyEntry || value instanceof VocabularyEntryDetail)
&& value.hasAuthority()) {
confidence = ConfidenceType.CF_ACCEPTED;
}

View File

@@ -11,7 +11,7 @@ import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-
import { createTestComponent } from '../testing/utils.test';
import { AuthorityConfidenceStateDirective } from '../authority-confidence/authority-confidence-state.directive';
import { TranslateModule } from '@ngx-translate/core';
import { ConfidenceType } from '../../core/integration/models/confidence-type';
import { ConfidenceType } from '../../core/shared/confidence-type';
import { SortablejsModule } from 'ngx-sortablejs';
import { environment } from '../../../environments/environment';

View File

@@ -1,7 +1,7 @@
import { isObject, uniqueId } from 'lodash';
import { hasValue, isNotEmpty } from '../../empty.util';
import { FormFieldMetadataValueObject } from '../../form/builder/models/form-field-metadata-value.model';
import { ConfidenceType } from '../../../core/integration/models/confidence-type';
import { ConfidenceType } from '../../../core/shared/confidence-type';
import { PLACEHOLDER_PARENT_METADATA } from '../../form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
export interface ChipsItemIcon {

View File

@@ -5,7 +5,7 @@ import { hasValue, isNotEmpty } from '../../empty.util';
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';
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
export class Chips {
chipsItems: BehaviorSubject<ChipsItem[]>;
@@ -102,7 +102,7 @@ export class Chips {
private getChipsIcons(item) {
const icons = [];
if (typeof item === 'string' || item instanceof FormFieldMetadataValueObject || item instanceof AuthorityValue) {
if (typeof item === 'string' || item instanceof FormFieldMetadataValueObject || item instanceof VocabularyEntry) {
return icons;
}

View File

@@ -44,7 +44,7 @@ import { SharedModule } from '../../../shared.module';
import { DynamicDsDatePickerModel } from './models/date-picker/date-picker.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 { VocabularyOptions } from '../../../../core/submission/vocabularies/models/vocabulary-options.model';
import { DynamicListRadioGroupModel } from './models/list/dynamic-list-radio-group.model';
import { DynamicLookupModel } from './models/lookup/dynamic-lookup.model';
import { DynamicScrollableDropdownModel } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.model';
@@ -74,7 +74,7 @@ import { createSuccessfulRemoteDataObject } from '../../../remote-data.utils';
describe('DsDynamicFormControlContainerComponent test suite', () => {
const authorityOptions: AuthorityOptions = {
const vocabularyOptions: VocabularyOptions = {
closed: false,
metadata: 'list',
name: 'type_programme',
@@ -104,7 +104,7 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
new DynamicTypeaheadModel({ id: 'typeahead', metadataFields: [], repeatable: false, submissionId: '1234' }),
new DynamicScrollableDropdownModel({
id: 'scrollableDropdown',
authorityOptions: authorityOptions,
vocabularyOptions: vocabularyOptions,
metadataFields: [],
repeatable: false,
submissionId: '1234'
@@ -112,12 +112,12 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
new DynamicTagModel({ id: 'tag', metadataFields: [], repeatable: false, submissionId: '1234' }),
new DynamicListCheckboxGroupModel({
id: 'checkboxList',
authorityOptions: authorityOptions,
vocabularyOptions: vocabularyOptions,
repeatable: true
}),
new DynamicListRadioGroupModel({
id: 'radioList',
authorityOptions: authorityOptions,
vocabularyOptions: vocabularyOptions,
repeatable: false
}),
new DynamicRelationGroupModel({

View File

@@ -8,10 +8,6 @@ import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dyna
import { DsDatePickerComponent } from './date-picker.component';
import { DynamicDsDatePickerModel } from './date-picker.model';
import { FormBuilderService } from '../../../form-builder.service';
import { FormComponent } from '../../../../form.component';
import { FormService } from '../../../../form.service';
import { createTestComponent } from '../../../../../testing/utils.test';
export const DATE_TEST_GROUP = new FormGroup({
@@ -20,7 +16,7 @@ export const DATE_TEST_GROUP = new FormGroup({
export const DATE_TEST_MODEL_CONFIG = {
disabled: false,
errorMessages: {required: 'You must enter at least the year.'},
errorMessages: { required: 'You must enter at least the year.' },
id: 'date',
label: 'Date',
name: 'date',
@@ -52,8 +48,8 @@ describe('DsDatePickerComponent test suite', () => {
providers: [
ChangeDetectorRef,
DsDatePickerComponent,
{provide: DynamicFormLayoutService, useValue: {}},
{provide: DynamicFormValidationService, useValue: {}}
{ provide: DynamicFormLayoutService, useValue: {} },
{ provide: DynamicFormValidationService, useValue: {} }
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});

View File

@@ -20,10 +20,6 @@ export class DsDatePickerComponent extends DynamicFormControlComponent implement
@Input() bindId = true;
@Input() group: FormGroup;
@Input() model: DynamicDsDatePickerModel;
// @Input()
// minDate;
// @Input()
// maxDate;
@Output() selected = new EventEmitter<number>();
@Output() remove = new EventEmitter<number>();
@@ -65,7 +61,7 @@ export class DsDatePickerComponent extends DynamicFormControlComponent implement
this.initialMonth = now.getMonth() + 1;
this.initialDay = now.getDate();
if (this.model.value && this.model.value !== null) {
if (this.model && this.model.value !== null) {
const values = this.model.value.toString().split(DS_DATE_PICKER_SEPARATOR);
if (values.length > 0) {
this.initialYear = parseInt(values[0], 10);

View File

@@ -2,13 +2,13 @@ import { DynamicFormControlLayout, DynamicInputModel, DynamicInputModelConfig, s
import { Subject } from 'rxjs';
import { LanguageCode } from '../../models/form-field-language-value.model';
import { AuthorityOptions } from '../../../../../core/integration/models/authority-options.model';
import { VocabularyOptions } from '../../../../../core/submission/vocabularies/models/vocabulary-options.model';
import { hasValue } from '../../../../empty.util';
import { FormFieldMetadataValueObject } from '../../models/form-field-metadata-value.model';
import { RelationshipOptions } from '../../models/relationship-options.model';
export interface DsDynamicInputModelConfig extends DynamicInputModelConfig {
authorityOptions?: AuthorityOptions;
vocabularyOptions?: VocabularyOptions;
languageCodes?: LanguageCode[];
language?: string;
value?: any;
@@ -20,7 +20,7 @@ export interface DsDynamicInputModelConfig extends DynamicInputModelConfig {
export class DsDynamicInputModel extends DynamicInputModel {
@serializable() authorityOptions: AuthorityOptions;
@serializable() vocabularyOptions: VocabularyOptions;
@serializable() private _languageCodes: LanguageCode[];
@serializable() private _language: string;
@serializable() languageUpdates: Subject<string>;
@@ -58,11 +58,11 @@ export class DsDynamicInputModel extends DynamicInputModel {
this.language = lang;
});
this.authorityOptions = config.authorityOptions;
this.vocabularyOptions = config.vocabularyOptions;
}
get hasAuthority(): boolean {
return this.authorityOptions && hasValue(this.authorityOptions.name);
return this.vocabularyOptions && hasValue(this.vocabularyOptions.name);
}
get hasLanguages(): boolean {
@@ -83,7 +83,7 @@ export class DsDynamicInputModel extends DynamicInputModel {
set languageCodes(languageCodes: LanguageCode[]) {
this._languageCodes = languageCodes;
if (!this.language || this.language === null || this.language === '') {
if (!this.language || this.language === '') {
this.language = this.languageCodes ? this.languageCodes[0].code : null;
}
}

View File

@@ -1,16 +1,17 @@
import { Subject } from 'rxjs';
import {
DynamicCheckboxGroupModel, DynamicFormControlLayout,
DynamicCheckboxGroupModel,
DynamicFormControlLayout,
DynamicFormGroupModelConfig,
serializable
} from '@ng-dynamic-forms/core';
import { AuthorityValue } from '../../../../../../core/integration/models/authority.value';
import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { VocabularyOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-options.model';
import { hasValue } from '../../../../../empty.util';
export interface DynamicListCheckboxGroupModelConfig extends DynamicFormGroupModelConfig {
authorityOptions: AuthorityOptions;
vocabularyOptions: VocabularyOptions;
groupLength?: number;
repeatable: boolean;
value?: any;
@@ -18,43 +19,44 @@ export interface DynamicListCheckboxGroupModelConfig extends DynamicFormGroupMod
export class DynamicListCheckboxGroupModel extends DynamicCheckboxGroupModel {
@serializable() authorityOptions: AuthorityOptions;
@serializable() vocabularyOptions: VocabularyOptions;
@serializable() repeatable: boolean;
@serializable() groupLength: number;
@serializable() _value: AuthorityValue[];
isListGroup = true;
valueUpdates: Subject<any>;
constructor(config: DynamicListCheckboxGroupModelConfig, layout?: DynamicFormControlLayout) {
super(config, layout);
this.authorityOptions = config.authorityOptions;
this.vocabularyOptions = config.vocabularyOptions;
this.groupLength = config.groupLength || 5;
this._value = [];
this.repeatable = config.repeatable;
this.valueUpdates = new Subject<any>();
this.valueUpdates.subscribe((value: AuthorityValue | AuthorityValue[]) => this.value = value);
this.valueUpdates.subscribe((value: VocabularyEntry | VocabularyEntry[]) => this.value = value);
this.valueUpdates.next(config.value);
}
get hasAuthority(): boolean {
return this.authorityOptions && hasValue(this.authorityOptions.name);
}
@serializable() _value: VocabularyEntry[];
get value() {
return this._value;
}
set value(value: AuthorityValue | AuthorityValue[]) {
set value(value: VocabularyEntry | VocabularyEntry[]) {
if (value) {
if (Array.isArray(value)) {
this._value = value;
} else {
// _value is non extendible so assign it a new array
const newValue = (this.value as AuthorityValue[]).concat([value]);
const newValue = (this.value as VocabularyEntry[]).concat([value]);
this._value = newValue
}
}
}
get hasAuthority(): boolean {
return this.vocabularyOptions && hasValue(this.vocabularyOptions.name);
}
}

View File

@@ -4,11 +4,11 @@ import {
DynamicRadioGroupModelConfig,
serializable
} from '@ng-dynamic-forms/core';
import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model';
import { VocabularyOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-options.model';
import { hasValue } from '../../../../../empty.util';
export interface DynamicListModelConfig extends DynamicRadioGroupModelConfig<any> {
authorityOptions: AuthorityOptions;
vocabularyOptions: VocabularyOptions;
groupLength?: number;
repeatable: boolean;
value?: any;
@@ -16,7 +16,7 @@ export interface DynamicListModelConfig extends DynamicRadioGroupModelConfig<any
export class DynamicListRadioGroupModel extends DynamicRadioGroupModel<any> {
@serializable() authorityOptions: AuthorityOptions;
@serializable() vocabularyOptions: VocabularyOptions;
@serializable() repeatable: boolean;
@serializable() groupLength: number;
isListGroup = true;
@@ -24,13 +24,13 @@ export class DynamicListRadioGroupModel extends DynamicRadioGroupModel<any> {
constructor(config: DynamicListModelConfig, layout?: DynamicFormControlLayout) {
super(config, layout);
this.authorityOptions = config.authorityOptions;
this.vocabularyOptions = config.vocabularyOptions;
this.groupLength = config.groupLength || 5;
this.repeatable = config.repeatable;
this.valueUpdates.next(config.value);
}
get hasAuthority(): boolean {
return this.authorityOptions && hasValue(this.authorityOptions.name);
return this.vocabularyOptions && hasValue(this.vocabularyOptions.name);
}
}

View File

@@ -2,25 +2,25 @@
import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { async, ComponentFixture, inject, TestBed, } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { DsDynamicListComponent } from './dynamic-list.component';
import { DynamicListCheckboxGroupModel } from './dynamic-list-checkbox-group.model';
import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model';
import { FormBuilderService } from '../../../form-builder.service';
import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap';
import {
DynamicFormControlLayout,
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 { DsDynamicListComponent } from './dynamic-list.component';
import { DynamicListCheckboxGroupModel } from './dynamic-list-checkbox-group.model';
import { VocabularyOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-options.model';
import { FormBuilderService } from '../../../form-builder.service';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { VocabularyServiceStub } from '../../../../../testing/vocabulary-service.stub';
import { DynamicListRadioGroupModel } from './dynamic-list-radio-group.model';
import { By } from '@angular/platform-browser';
import { AuthorityValue } from '../../../../../../core/integration/models/authority.value';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { createTestComponent } from '../../../../../testing/utils.test';
export const LAYOUT_TEST = {
@@ -35,12 +35,12 @@ export const LIST_TEST_GROUP = new FormGroup({
});
export const LIST_CHECKBOX_TEST_MODEL_CONFIG = {
authorityOptions: {
vocabularyOptions: {
closed: false,
metadata: 'listCheckbox',
name: 'type_programme',
scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'
} as AuthorityOptions,
} as VocabularyOptions,
disabled: false,
id: 'listCheckbox',
label: 'Programme',
@@ -52,12 +52,12 @@ export const LIST_CHECKBOX_TEST_MODEL_CONFIG = {
};
export const LIST_RADIO_TEST_MODEL_CONFIG = {
authorityOptions: {
vocabularyOptions: {
closed: false,
metadata: 'listRadio',
name: 'type_programme',
scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'
} as AuthorityOptions,
} as VocabularyOptions,
disabled: false,
id: 'listRadio',
label: 'Programme',
@@ -77,7 +77,7 @@ describe('DsDynamicListComponent test suite', () => {
let html;
let modelValue;
const authorityServiceStub = new AuthorityServiceStub();
const vocabularyServiceStub = new VocabularyServiceStub();
// async beforeEach
beforeEach(async(() => {
@@ -99,9 +99,9 @@ describe('DsDynamicListComponent test suite', () => {
DsDynamicListComponent,
DynamicFormValidationService,
FormBuilderService,
{provide: AuthorityService, useValue: authorityServiceStub},
{provide: DynamicFormLayoutService, useValue: {}},
{provide: DynamicFormValidationService, useValue: {}}
{ provide: VocabularyService, useValue: vocabularyServiceStub },
{ provide: DynamicFormLayoutService, useValue: {} },
{ provide: DynamicFormValidationService, useValue: {} }
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
@@ -147,20 +147,16 @@ describe('DsDynamicListComponent test suite', () => {
});
it('should init component properly', () => {
const results$ = authorityServiceStub.getEntriesByName({} as any);
results$.subscribe((results) => {
expect((listComp as any).optionsList).toEqual(results.payload);
expect(listComp.items.length).toBe(1);
expect(listComp.items[0].length).toBe(2);
})
expect((listComp as any).optionsList).toEqual(vocabularyServiceStub.getList());
expect(listComp.items.length).toBe(1);
expect(listComp.items[0].length).toBe(2);
});
it('should set model value properly when a checkbox option is selected', () => {
const de = listFixture.debugElement.queryAll(By.css('div.custom-checkbox'));
const items = de[0].queryAll(By.css('input.custom-control-input'));
const item = items[0];
modelValue = [Object.assign(new AuthorityValue(), {id: 1, display: 'one', value: 1})];
modelValue = [Object.assign(new VocabularyEntry(), { authority: 1, display: 'one', value: 1 })];
item.nativeElement.click();
@@ -187,7 +183,7 @@ describe('DsDynamicListComponent test suite', () => {
listComp = listFixture.componentInstance; // FormComponent test instance
listComp.group = LIST_TEST_GROUP;
listComp.model = new DynamicListCheckboxGroupModel(LIST_CHECKBOX_TEST_MODEL_CONFIG, LAYOUT_TEST);
modelValue = [Object.assign(new AuthorityValue(), {id: 1, display: 'one', value: 1})];
modelValue = [Object.assign(new VocabularyEntry(), { authority: 1, display: 'one', value: 1 })];
listComp.model.value = modelValue;
listFixture.detectChanges();
});
@@ -198,13 +194,9 @@ describe('DsDynamicListComponent test suite', () => {
});
it('should init component properly', () => {
const results$ = authorityServiceStub.getEntriesByName({} as any);
results$.subscribe((results) => {
expect((listComp as any).optionsList).toEqual(results.payload);
expect(listComp.model.value).toEqual(modelValue);
expect((listComp.model as DynamicListCheckboxGroupModel).group[0].value).toBeTruthy();
})
expect((listComp as any).optionsList).toEqual(vocabularyServiceStub.getList());
expect(listComp.model.value).toEqual(modelValue);
expect((listComp.model as DynamicListCheckboxGroupModel).group[0].value).toBeTruthy();
});
it('should set model value properly when a checkbox option is deselected', () => {
@@ -237,20 +229,16 @@ describe('DsDynamicListComponent test suite', () => {
});
it('should init component properly', () => {
const results$ = authorityServiceStub.getEntriesByName({} as any);
results$.subscribe((results) => {
expect((listComp as any).optionsList).toEqual(results.payload);
expect(listComp.items.length).toBe(1);
expect(listComp.items[0].length).toBe(2);
})
expect((listComp as any).optionsList).toEqual(vocabularyServiceStub.getList());
expect(listComp.items.length).toBe(1);
expect(listComp.items[0].length).toBe(2);
});
it('should set model value when a radio option is selected', () => {
const de = listFixture.debugElement.queryAll(By.css('div.custom-radio'));
const items = de[0].queryAll(By.css('input.custom-control-input'));
const item = items[0];
modelValue = Object.assign(new AuthorityValue(), {id: 1, display: 'one', value: 1});
modelValue = Object.assign(new VocabularyEntry(), { authority: 1, display: 'one', value: 1 });
item.nativeElement.click();
@@ -265,7 +253,7 @@ describe('DsDynamicListComponent test suite', () => {
listComp = listFixture.componentInstance; // FormComponent test instance
listComp.group = LIST_TEST_GROUP;
listComp.model = new DynamicListRadioGroupModel(LIST_RADIO_TEST_MODEL_CONFIG, LAYOUT_TEST);
modelValue = Object.assign(new AuthorityValue(), {id: 1, display: 'one', value: 1});
modelValue = Object.assign(new VocabularyEntry(), { authority: 1, display: 'one', value: 1 });
listComp.model.value = modelValue;
listFixture.detectChanges();
});
@@ -276,13 +264,9 @@ describe('DsDynamicListComponent test suite', () => {
});
it('should init component properly', () => {
const results$ = authorityServiceStub.getEntriesByName({} as any);
results$.subscribe((results) => {
expect((listComp as any).optionsList).toEqual(results.payload);
expect(listComp.model.value).toEqual(modelValue);
expect((listComp.model as DynamicListRadioGroupModel).options[0].value).toBeTruthy();
})
expect((listComp as any).optionsList).toEqual(vocabularyServiceStub.getList());
expect(listComp.model.value).toEqual(modelValue);
expect((listComp.model as DynamicListRadioGroupModel).options[0].value).toBeTruthy();
});
});
});

View File

@@ -1,20 +1,23 @@
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormGroup } from '@angular/forms';
import {
DynamicCheckboxModel,
DynamicFormControlComponent,
DynamicFormLayoutService,
DynamicFormValidationService
} from '@ng-dynamic-forms/core';
import { findKey } from 'lodash';
import { AuthorityService } from '../../../../../../core/integration/authority.service';
import { IntegrationSearchOptions } from '../../../../../../core/integration/models/integration-options.model';
import { VocabularyFindOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
import { hasValue, isNotEmpty } from '../../../../../empty.util';
import { DynamicListCheckboxGroupModel } from './dynamic-list-checkbox-group.model';
import { FormBuilderService } from '../../../form-builder.service';
import {
DynamicCheckboxModel,
DynamicFormControlComponent, DynamicFormLayoutService,
DynamicFormValidationService
} from '@ng-dynamic-forms/core';
import { AuthorityValue } from '../../../../../../core/integration/models/authority.value';
import { DynamicListRadioGroupModel } from './dynamic-list-radio-group.model';
import { IntegrationData } from '../../../../../../core/integration/integration-data';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators';
import { PaginatedList } from '../../../../../../core/data/paginated-list';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
export interface ListItem {
id: string,
@@ -39,10 +42,10 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen
@Output() focus: EventEmitter<any> = new EventEmitter<any>();
public items: ListItem[][] = [];
protected optionsList: AuthorityValue[];
protected searchOptions: IntegrationSearchOptions;
protected optionsList: VocabularyEntry[];
protected searchOptions: VocabularyFindOptions;
constructor(private authorityService: AuthorityService,
constructor(private vocabularyService: VocabularyService,
private cdr: ChangeDetectorRef,
private formBuilderService: FormBuilderService,
protected layoutService: DynamicFormLayoutService,
@@ -54,10 +57,10 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen
ngOnInit() {
if (this.hasAuthorityOptions()) {
// TODO Replace max elements 1000 with a paginated request when pagination bug is resolved
this.searchOptions = new IntegrationSearchOptions(
this.model.authorityOptions.scope,
this.model.authorityOptions.name,
this.model.authorityOptions.metadata,
this.searchOptions = new VocabularyFindOptions(
this.model.vocabularyOptions.scope,
this.model.vocabularyOptions.name,
this.model.vocabularyOptions.metadata,
'',
1000, // Max elements
1);// Current Page
@@ -77,13 +80,13 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen
const target = event.target as any;
if (this.model.repeatable) {
// Target tabindex coincide with the array index of the value into the authority list
const authorityValue: AuthorityValue = this.optionsList[target.tabIndex];
const entry: VocabularyEntry = this.optionsList[target.tabIndex];
if (target.checked) {
this.model.valueUpdates.next(authorityValue);
this.model.valueUpdates.next(entry);
} else {
const newValue = [];
this.model.value
.filter((item) => item.value !== authorityValue.value)
.filter((item) => item.value !== entry.value)
.forEach((item) => newValue.push(item));
this.model.valueUpdates.next(newValue);
}
@@ -94,16 +97,18 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen
}
protected setOptionsFromAuthority() {
if (this.model.authorityOptions.name && this.model.authorityOptions.name.length > 0) {
if (this.model.vocabularyOptions.name && this.model.vocabularyOptions.name.length > 0) {
const listGroup = this.group.controls[this.model.id] as FormGroup;
this.authorityService.getEntriesByName(this.searchOptions).subscribe((authorities: IntegrationData) => {
this.vocabularyService.getVocabularyEntries(this.searchOptions).pipe(
getFirstSucceededRemoteDataPayload()
).subscribe((entries: PaginatedList<VocabularyEntry>) => {
let groupCounter = 0;
let itemsPerGroup = 0;
let tempList: ListItem[] = [];
this.optionsList = authorities.payload as AuthorityValue[];
this.optionsList = entries.page;
// Make a list of available options (checkbox/radio) and split in groups of 'model.groupLength'
(authorities.payload as AuthorityValue[]).forEach((option, key) => {
const value = option.id || option.value;
entries.page.forEach((option, key) => {
const value = option.authority || option.value;
const checked: boolean = isNotEmpty(findKey(
this.model.value,
(v) => v.value === option.value));
@@ -138,8 +143,8 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen
}
protected hasAuthorityOptions() {
return (hasValue(this.model.authorityOptions.scope)
&& hasValue(this.model.authorityOptions.name)
&& hasValue(this.model.authorityOptions.metadata));
return (hasValue(this.model.vocabularyOptions.scope)
&& hasValue(this.model.vocabularyOptions.name)
&& hasValue(this.model.vocabularyOptions.metadata));
}
}

View File

@@ -2,33 +2,33 @@
import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { async, ComponentFixture, fakeAsync, inject, TestBed, tick, } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model';
import { DynamicFormLayoutService, DynamicFormsCoreModule, DynamicFormValidationService } from '@ng-dynamic-forms/core';
import { TranslateModule } from '@ngx-translate/core';
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap';
import { AuthorityService } from '../../../../../../core/integration/authority.service';
import { AuthorityServiceStub } from '../../../../../testing/authority-service.stub';
import { DynamicFormLayoutService, DynamicFormsCoreModule, DynamicFormValidationService } from '@ng-dynamic-forms/core';
import { VocabularyOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-options.model';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { VocabularyServiceStub } from '../../../../../testing/vocabulary-service.stub';
import { DsDynamicLookupComponent } from './dynamic-lookup.component';
import { DynamicLookupModel } from './dynamic-lookup.model';
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { TranslateModule } from '@ngx-translate/core';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { By } from '@angular/platform-browser';
import { AuthorityValue } from '../../../../../../core/integration/models/authority.value';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { createTestComponent } from '../../../../../testing/utils.test';
import { DynamicLookupNameModel } from './dynamic-lookup-name.model';
import { AuthorityConfidenceStateDirective } from '../../../../../authority-confidence/authority-confidence-state.directive';
import { ObjNgFor } from '../../../../../utils/object-ngfor.pipe';
let LOOKUP_TEST_MODEL_CONFIG = {
authorityOptions: {
vocabularyOptions: {
closed: false,
metadata: 'lookup',
name: 'RPAuthority',
scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'
} as AuthorityOptions,
} as VocabularyOptions,
disabled: false,
errorMessages: { required: 'Required field.' },
id: 'lookup',
@@ -47,12 +47,12 @@ let LOOKUP_TEST_MODEL_CONFIG = {
};
let LOOKUP_NAME_TEST_MODEL_CONFIG = {
authorityOptions: {
vocabularyOptions: {
closed: false,
metadata: 'lookup-name',
name: 'RPAuthority',
scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'
} as AuthorityOptions,
} as VocabularyOptions,
disabled: false,
errorMessages: { required: 'Required field.' },
id: 'lookupName',
@@ -78,12 +78,12 @@ let LOOKUP_TEST_GROUP = new FormGroup({
describe('Dynamic Lookup component', () => {
function init() {
LOOKUP_TEST_MODEL_CONFIG = {
authorityOptions: {
vocabularyOptions: {
closed: false,
metadata: 'lookup',
name: 'RPAuthority',
scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'
} as AuthorityOptions,
} as VocabularyOptions,
disabled: false,
errorMessages: { required: 'Required field.' },
id: 'lookup',
@@ -102,12 +102,12 @@ describe('Dynamic Lookup component', () => {
};
LOOKUP_NAME_TEST_MODEL_CONFIG = {
authorityOptions: {
vocabularyOptions: {
closed: false,
metadata: 'lookup-name',
name: 'RPAuthority',
scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'
} as AuthorityOptions,
} as VocabularyOptions,
disabled: false,
errorMessages: { required: 'Required field.' },
id: 'lookupName',
@@ -137,12 +137,11 @@ describe('Dynamic Lookup component', () => {
let testFixture: ComponentFixture<TestComponent>;
let lookupFixture: ComponentFixture<DsDynamicLookupComponent>;
let html;
let vocabularyServiceStub: VocabularyServiceStub;
let authorityServiceStub;
// async beforeEach
beforeEach(async(() => {
const authorityService = new AuthorityServiceStub();
authorityServiceStub = authorityService;
vocabularyServiceStub = new VocabularyServiceStub();
TestBed.configureTestingModule({
imports: [
DynamicFormsCoreModule,
@@ -162,7 +161,7 @@ describe('Dynamic Lookup component', () => {
providers: [
ChangeDetectorRef,
DsDynamicLookupComponent,
{ provide: AuthorityService, useValue: authorityService },
{ provide: VocabularyService, useValue: vocabularyServiceStub },
{ provide: DynamicFormLayoutService, useValue: {} },
{ provide: DynamicFormValidationService, useValue: {} }
],
@@ -247,7 +246,7 @@ describe('Dynamic Lookup component', () => {
it('should return search results', fakeAsync(() => {
const de = lookupFixture.debugElement.queryAll(By.css('button'));
const btnEl = de[0].nativeElement;
const results$ = authorityServiceStub.getEntriesByName({} as any);
const results = vocabularyServiceStub.getList();
lookupComp.firstInputValue = 'test';
lookupFixture.detectChanges();
@@ -255,17 +254,15 @@ describe('Dynamic Lookup component', () => {
btnEl.click();
tick();
lookupFixture.detectChanges();
results$.subscribe((results) => {
expect(lookupComp.optionsList).toEqual(results.payload);
});
expect(lookupComp.optionsList).toEqual(results);
}));
it('should select a results entry properly', fakeAsync(() => {
let de = lookupFixture.debugElement.queryAll(By.css('button'));
const btnEl = de[0].nativeElement;
const selectedValue = Object.assign(new AuthorityValue(), {
id: 1,
const selectedValue = Object.assign(new VocabularyEntry(), {
authority: 1,
display: 'one',
value: 1
});
@@ -284,7 +281,7 @@ describe('Dynamic Lookup component', () => {
expect(lookupComp.change.emit).toHaveBeenCalled();
}));
it('should set model.value on input type when AuthorityOptions.closed is false', fakeAsync(() => {
it('should set model.value on input type when VocabularyOptions.closed is false', fakeAsync(() => {
lookupComp.firstInputValue = 'test';
lookupFixture.detectChanges();
@@ -293,8 +290,8 @@ describe('Dynamic Lookup component', () => {
}));
it('should not set model.value on input type when AuthorityOptions.closed is true', () => {
lookupComp.model.authorityOptions.closed = true;
it('should not set model.value on input type when VocabularyOptions.closed is true', () => {
lookupComp.model.vocabularyOptions.closed = true;
lookupComp.firstInputValue = 'test';
lookupFixture.detectChanges();
@@ -389,26 +386,26 @@ describe('Dynamic Lookup component', () => {
it('should select a results entry properly', fakeAsync(() => {
const payload = [
Object.assign(new AuthorityValue(), {
id: 1,
Object.assign(new VocabularyEntry(), {
authority: 1,
display: 'Name, Lastname',
value: 1
}),
Object.assign(new AuthorityValue(), {
id: 2,
Object.assign(new VocabularyEntry(), {
authority: 2,
display: 'NameTwo, LastnameTwo',
value: 2
}),
];
let de = lookupFixture.debugElement.queryAll(By.css('button'));
const btnEl = de[0].nativeElement;
const selectedValue = Object.assign(new AuthorityValue(), {
id: 1,
const selectedValue = Object.assign(new VocabularyEntry(), {
authority: 1,
display: 'Name, Lastname',
value: 1
});
spyOn(lookupComp.change, 'emit');
authorityServiceStub.setNewPayload(payload);
vocabularyServiceStub.setNewPayload(payload);
lookupComp.firstInputValue = 'test';
lookupFixture.detectChanges();
btnEl.click();

View File

@@ -1,8 +1,7 @@
import { ChangeDetectorRef, Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Subscription } from 'rxjs';
import { of as observableOf } from 'rxjs';
import { of as observableOf, Subscription } from 'rxjs';
import { catchError, distinctUntilChanged } from 'rxjs/operators';
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap';
import {
@@ -11,16 +10,16 @@ import {
DynamicFormValidationService
} from '@ng-dynamic-forms/core';
import { AuthorityService } from '../../../../../../core/integration/authority.service';
import { DynamicLookupModel } from './dynamic-lookup.model';
import { IntegrationSearchOptions } from '../../../../../../core/integration/models/integration-options.model';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { VocabularyFindOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
import { hasValue, isEmpty, isNotEmpty, isNull, isUndefined } from '../../../../../empty.util';
import { IntegrationData } from '../../../../../../core/integration/integration-data';
import { PageInfo } from '../../../../../../core/shared/page-info.model';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { AuthorityValue } from '../../../../../../core/integration/models/authority.value';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { DynamicLookupNameModel } from './dynamic-lookup-name.model';
import { ConfidenceType } from '../../../../../../core/integration/models/confidence-type';
import { ConfidenceType } from '../../../../../../core/shared/confidence-type';
import { PaginatedList } from '../../../../../../core/data/paginated-list';
import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators';
@Component({
selector: 'ds-dynamic-lookup',
@@ -43,10 +42,10 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem
public pageInfo: PageInfo;
public optionsList: any;
protected searchOptions: IntegrationSearchOptions;
protected searchOptions: VocabularyFindOptions;
protected subs: Subscription[] = [];
constructor(private authorityService: AuthorityService,
constructor(private vocabularyService: VocabularyService,
private cdr: ChangeDetectorRef,
protected layoutService: DynamicFormLayoutService,
protected validationService: DynamicFormValidationService
@@ -59,10 +58,10 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem
};
ngOnInit() {
this.searchOptions = new IntegrationSearchOptions(
this.model.authorityOptions.scope,
this.model.authorityOptions.name,
this.model.authorityOptions.metadata,
this.searchOptions = new VocabularyFindOptions(
this.model.vocabularyOptions.scope,
this.model.vocabularyOptions.name,
this.model.vocabularyOptions.metadata,
'',
this.model.maxOptions,
1);
@@ -79,6 +78,148 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem
}));
}
public formatItemForInput(item: any, field: number): string {
if (isUndefined(item) || isNull(item)) {
return '';
}
return (typeof item === 'string') ? item : this.inputFormatter(item, field);
}
public hasAuthorityValue() {
return hasValue(this.model.value)
&& this.model.value.hasAuthority();
}
public hasEmptyValue() {
return isNotEmpty(this.getCurrentValue());
}
public clearFields() {
// Clear inputs whether there is no results and authority is closed
if (this.model.vocabularyOptions.closed) {
this.resetFields();
}
}
public isEditDisabled() {
return !this.hasAuthorityValue();
}
public isInputDisabled() {
return (this.model.vocabularyOptions.closed && this.hasAuthorityValue() && !this.editMode);
}
public isLookupName() {
return (this.model instanceof DynamicLookupNameModel);
}
public isSearchDisabled() {
return isEmpty(this.firstInputValue) || this.editMode;
}
public onBlurEvent(event: Event) {
this.blur.emit(event);
}
public onFocusEvent(event) {
this.focus.emit(event);
}
public onChange(event) {
event.preventDefault();
if (!this.model.vocabularyOptions.closed) {
if (isNotEmpty(this.getCurrentValue())) {
const currentValue = new FormFieldMetadataValueObject(this.getCurrentValue());
if (!this.editMode) {
this.updateModel(currentValue);
}
} else {
this.remove();
}
}
}
public onScroll() {
if (!this.loading && this.pageInfo.currentPage <= this.pageInfo.totalPages) {
this.searchOptions.currentPage++;
this.search();
}
}
public onSelect(event) {
this.updateModel(event);
}
public openChange(isOpened: boolean) {
if (!isOpened) {
if (this.model.vocabularyOptions.closed && !this.hasAuthorityValue()) {
this.setInputsValue('');
}
}
}
public remove() {
this.group.markAsPristine();
this.model.valueUpdates.next(null);
this.change.emit(null);
}
public saveChanges() {
if (isNotEmpty(this.getCurrentValue())) {
const newValue = Object.assign(new VocabularyEntry(), this.model.value, {
display: this.getCurrentValue(),
value: this.getCurrentValue()
});
this.updateModel(newValue);
} else {
this.remove();
}
this.switchEditMode();
}
public search() {
this.optionsList = null;
this.pageInfo = null;
// Query
this.searchOptions.query = this.getCurrentValue();
this.loading = true;
this.subs.push(this.vocabularyService.getVocabularyEntries(this.searchOptions).pipe(
getFirstSucceededRemoteDataPayload(),
catchError(() =>
observableOf(new PaginatedList(
new PageInfo(),
[]
))
),
distinctUntilChanged())
.subscribe((list: PaginatedList<VocabularyEntry>) => {
console.log(list);
this.optionsList = list.page;
this.pageInfo = list.pageInfo;
this.loading = false;
this.cdr.detectChanges();
}));
}
public switchEditMode() {
this.editMode = !this.editMode;
}
public whenClickOnConfidenceNotAccepted(sdRef: NgbDropdown, confidence: ConfidenceType) {
if (!this.model.readOnly) {
sdRef.open();
this.search();
}
}
ngOnDestroy() {
this.subs
.filter((sub) => hasValue(sub))
.forEach((sub) => sub.unsubscribe());
}
protected getCurrentValue(): string {
let result = '';
if (!this.isLookupName()) {
@@ -106,7 +247,7 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem
protected setInputsValue(value) {
if (hasValue(value)) {
let displayValue = value;
if (value instanceof FormFieldMetadataValueObject || value instanceof AuthorityValue) {
if (value instanceof FormFieldMetadataValueObject || value instanceof VocabularyEntry) {
displayValue = value.display;
}
@@ -131,145 +272,4 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem
this.optionsList = null;
this.pageInfo = null;
}
public formatItemForInput(item: any, field: number): string {
if (isUndefined(item) || isNull(item)) {
return '';
}
return (typeof item === 'string') ? item : this.inputFormatter(item, field);
}
public hasAuthorityValue() {
return hasValue(this.model.value)
&& this.model.value.hasAuthority();
}
public hasEmptyValue() {
return isNotEmpty(this.getCurrentValue());
}
public clearFields() {
// Clear inputs whether there is no results and authority is closed
if (this.model.authorityOptions.closed) {
this.resetFields();
}
}
public isEditDisabled() {
return !this.hasAuthorityValue();
}
public isInputDisabled() {
return (this.model.authorityOptions.closed && this.hasAuthorityValue() && !this.editMode);
}
public isLookupName() {
return (this.model instanceof DynamicLookupNameModel);
}
public isSearchDisabled() {
return isEmpty(this.firstInputValue) || this.editMode;
}
public onBlurEvent(event: Event) {
this.blur.emit(event);
}
public onFocusEvent(event) {
this.focus.emit(event);
}
public onChange(event) {
event.preventDefault();
if (!this.model.authorityOptions.closed) {
if (isNotEmpty(this.getCurrentValue())) {
const currentValue = new FormFieldMetadataValueObject(this.getCurrentValue());
if (!this.editMode) {
this.updateModel(currentValue);
}
} else {
this.remove();
}
}
}
public onScroll() {
if (!this.loading && this.pageInfo.currentPage <= this.pageInfo.totalPages) {
this.searchOptions.currentPage++;
this.search();
}
}
public onSelect(event) {
this.updateModel(event);
}
public openChange(isOpened: boolean) {
if (!isOpened) {
if (this.model.authorityOptions.closed && !this.hasAuthorityValue()) {
this.setInputsValue('');
}
}
}
public remove() {
this.group.markAsPristine();
this.model.valueUpdates.next(null);
this.change.emit(null);
}
public saveChanges() {
if (isNotEmpty(this.getCurrentValue())) {
const newValue = Object.assign(new AuthorityValue(), this.model.value, {
display: this.getCurrentValue(),
value: this.getCurrentValue()
});
this.updateModel(newValue);
} else {
this.remove();
}
this.switchEditMode();
}
public search() {
this.optionsList = null;
this.pageInfo = null;
// Query
this.searchOptions.query = this.getCurrentValue();
this.loading = true;
this.subs.push(this.authorityService.getEntriesByName(this.searchOptions).pipe(
catchError(() => {
const emptyResult = new IntegrationData(
new PageInfo(),
[]
);
return observableOf(emptyResult);
}),
distinctUntilChanged())
.subscribe((object: IntegrationData) => {
this.optionsList = object.payload;
this.pageInfo = object.pageInfo;
this.loading = false;
this.cdr.detectChanges();
}));
}
public switchEditMode() {
this.editMode = !this.editMode;
}
public whenClickOnConfidenceNotAccepted(sdRef: NgbDropdown, confidence: ConfidenceType) {
if (!this.model.readOnly) {
sdRef.open();
this.search();
}
}
ngOnDestroy() {
this.subs
.filter((sub) => hasValue(sub))
.forEach((sub) => sub.unsubscribe());
}
}

View File

@@ -2,9 +2,12 @@
import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, inject, TestBed, } from '@angular/core/testing';
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { Store, StoreModule } from '@ngrx/store';
import { TranslateModule } from '@ngx-translate/core';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
import { DsDynamicRelationGroupComponent } from './dynamic-relation-group.components';
import { DynamicRelationGroupModel, DynamicRelationGroupModelConfig } from './dynamic-relation-group.model';
@@ -13,18 +16,14 @@ import { FormFieldModel } from '../../../models/form-field.model';
import { FormBuilderService } from '../../../form-builder.service';
import { FormService } from '../../../../form.service';
import { FormComponent } from '../../../../form.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { Chips } from '../../../../../chips/models/chips.model';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { DsDynamicInputModel } from '../ds-dynamic-input.model';
import { createTestComponent } from '../../../../../testing/utils.test';
import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
import { AuthorityService } from '../../../../../../core/integration/authority.service';
import { AuthorityServiceStub } from '../../../../../testing/authority-service.stub';
import { Store, StoreModule } from '@ngrx/store';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { VocabularyServiceStub } from '../../../../../testing/vocabulary-service.stub';
import { StoreMock } from '../../../../../testing/store.mock';
import { FormRowModel } from '../../../../../../core/config/models/config-submission-form.model';
import { GlobalConfig } from '../../../../../../../config/global-config.interface';
import { storeModuleConfig } from '../../../../../../app.reducer';
export let FORM_GROUP_TEST_MODEL_CONFIG;
@@ -47,7 +46,7 @@ function init() {
mandatoryMessage: 'Required field!',
repeatable: false,
selectableMetadata: [{
authority: 'RPAuthority',
controlledVocabulary: 'RPAuthority',
closed: false,
metadata: 'dc.contributor.author'
}],
@@ -61,7 +60,7 @@ function init() {
mandatory: 'false',
repeatable: false,
selectableMetadata: [{
authority: 'OUAuthority',
controlledVocabulary: 'OUAuthority',
closed: false,
metadata: 'local.contributor.affiliation'
}]
@@ -128,7 +127,7 @@ describe('DsDynamicRelationGroupComponent test suite', () => {
FormBuilderService,
FormComponent,
FormService,
{ provide: AuthorityService, useValue: new AuthorityServiceStub() },
{ provide: VocabularyService, useValue: new VocabularyServiceStub() },
{ provide: Store, useClass: StoreMock }
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]

View File

@@ -1,14 +1,4 @@
import {
ChangeDetectorRef,
Component,
EventEmitter,
Inject,
Input,
OnDestroy,
OnInit,
Output,
ViewChild
} from '@angular/core';
import { ChangeDetectorRef, Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { combineLatest, Observable, of as observableOf, Subscription } from 'rxjs';
@@ -33,12 +23,12 @@ import { hasValue, isEmpty, isNotEmpty, isNotNull } from '../../../../../empty.u
import { shrinkInOut } from '../../../../../animations/shrink';
import { ChipsItem } from '../../../../../chips/models/chips-item.model';
import { hasOnlyEmptyProperties } from '../../../../../object.util';
import { IntegrationSearchOptions } from '../../../../../../core/integration/models/integration-options.model';
import { AuthorityService } from '../../../../../../core/integration/authority.service';
import { IntegrationData } from '../../../../../../core/integration/integration-data';
import { VocabularyFindOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { AuthorityValue } from '../../../../../../core/integration/models/authority.value';
import { environment } from '../../../../../../../environments/environment';
import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators';
import { VocabularyEntryDetail } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
@Component({
selector: 'ds-dynamic-relation-group',
@@ -64,9 +54,9 @@ export class DsDynamicRelationGroupComponent extends DynamicFormControlComponent
private selectedChipItem: ChipsItem;
private subs: Subscription[] = [];
@ViewChild('formRef', {static: false}) private formRef: FormComponent;
@ViewChild('formRef', { static: false }) private formRef: FormComponent;
constructor(private authorityService: AuthorityService,
constructor(private vocabularyService: VocabularyService,
private formBuilderService: FormBuilderService,
private formService: FormService,
private cdr: ChangeDetectorRef,
@@ -177,6 +167,12 @@ export class DsDynamicRelationGroupComponent extends DynamicFormControlComponent
this.clear();
}
ngOnDestroy(): void {
this.subs
.filter((sub) => hasValue(sub))
.forEach((sub) => sub.unsubscribe());
}
private addToChips() {
if (!this.formRef.formGroup.valid) {
this.formService.validateAllFormFields(this.formRef.formGroup);
@@ -235,20 +231,16 @@ export class DsDynamicRelationGroupComponent extends DynamicFormControlComponent
if (isObject(valueObj[fieldName]) && valueObj[fieldName].hasAuthority() && isNotEmpty(valueObj[fieldName].authority)) {
const fieldId = fieldName.replace(/\./g, '_');
const model = this.formBuilderService.findById(fieldId, this.formModel);
const searchOptions: IntegrationSearchOptions = new IntegrationSearchOptions(
(model as any).authorityOptions.scope,
(model as any).authorityOptions.name,
(model as any).authorityOptions.metadata,
return$ = this.vocabularyService.findEntryDetailByValue(
valueObj[fieldName].authority,
(model as any).maxOptions,
1);
return$ = this.authorityService.getEntryByValue(searchOptions).pipe(
map((result: IntegrationData) => Object.assign(
(model as any).vocabularyOptions.name
).pipe(
getFirstSucceededRemoteDataPayload(),
map((entryDetail: VocabularyEntryDetail) => Object.assign(
new FormFieldMetadataValueObject(),
valueObj[fieldName],
{
otherInformation: (result.payload[0] as AuthorityValue).otherInformation
otherInformation: entryDetail.otherInformation
})
));
} else {
@@ -315,10 +307,4 @@ export class DsDynamicRelationGroupComponent extends DynamicFormControlComponent
}
}
ngOnDestroy(): void {
this.subs
.filter((sub) => hasValue(sub))
.forEach((sub) => sub.unsubscribe());
}
}

View File

@@ -9,12 +9,12 @@ import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { DynamicFormLayoutService, DynamicFormsCoreModule, DynamicFormValidationService } from '@ng-dynamic-forms/core';
import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap';
import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model';
import { AuthorityService } from '../../../../../../core/integration/authority.service';
import { AuthorityServiceStub } from '../../../../../testing/authority-service.stub';
import { VocabularyOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-options.model';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { VocabularyServiceStub } from '../../../../../testing/vocabulary-service.stub';
import { DsDynamicScrollableDropdownComponent } from './dynamic-scrollable-dropdown.component';
import { DynamicScrollableDropdownModel } from './dynamic-scrollable-dropdown.model';
import { AuthorityValue } from '../../../../../../core/integration/models/authority.value';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { createTestComponent, hasClass } from '../../../../../testing/utils.test';
export const SD_TEST_GROUP = new FormGroup({
@@ -22,14 +22,14 @@ export const SD_TEST_GROUP = new FormGroup({
});
export const SD_TEST_MODEL_CONFIG = {
authorityOptions: {
vocabularyOptions: {
closed: false,
metadata: 'dropdown',
name: 'common_iso_languages',
scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'
} as AuthorityOptions,
} as VocabularyOptions,
disabled: false,
errorMessages: {required: 'Required field.'},
errorMessages: { required: 'Required field.' },
id: 'dropdown',
label: 'Language',
maxOptions: 10,
@@ -52,7 +52,7 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => {
let html;
let modelValue;
const authorityServiceStub = new AuthorityServiceStub();
const vocabularyServiceStub = new VocabularyServiceStub();
// async beforeEach
beforeEach(async(() => {
@@ -74,9 +74,9 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => {
providers: [
ChangeDetectorRef,
DsDynamicScrollableDropdownComponent,
{provide: AuthorityService, useValue: authorityServiceStub},
{provide: DynamicFormLayoutService, useValue: {}},
{provide: DynamicFormValidationService, useValue: {}}
{ provide: VocabularyService, useValue: vocabularyServiceStub },
{ provide: DynamicFormLayoutService, useValue: {} },
{ provide: DynamicFormValidationService, useValue: {} }
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
@@ -121,11 +121,8 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => {
});
it('should init component properly', () => {
const results$ = authorityServiceStub.getEntriesByName({} as any);
expect(scrollableDropdownComp.optionsList).toBeDefined();
results$.subscribe((results) => {
expect(scrollableDropdownComp.optionsList).toEqual(results.payload);
})
expect(scrollableDropdownComp.optionsList).toEqual(vocabularyServiceStub.getList());
});
it('should display dropdown menu entries', () => {
@@ -154,7 +151,7 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => {
}));
it('should select a results entry properly', fakeAsync(() => {
const selectedValue = Object.assign(new AuthorityValue(), {id: 1, display: 'one', value: 1});
const selectedValue = Object.assign(new VocabularyEntry(), { authority: 1, display: 'one', value: 1 });
let de: any = scrollableDropdownFixture.debugElement.query(By.css('button.ds-form-input-btn'));
let btnEl = de.nativeElement;
@@ -192,7 +189,7 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => {
scrollableDropdownFixture = TestBed.createComponent(DsDynamicScrollableDropdownComponent);
scrollableDropdownComp = scrollableDropdownFixture.componentInstance; // FormComponent test instance
scrollableDropdownComp.group = SD_TEST_GROUP;
modelValue = Object.assign(new AuthorityValue(), {id: 1, display: 'one', value: 1});
modelValue = Object.assign(new VocabularyEntry(), { authority: 1, display: 'one', value: 1 });
scrollableDropdownComp.model = new DynamicScrollableDropdownModel(SD_TEST_MODEL_CONFIG);
scrollableDropdownComp.model.value = modelValue;
scrollableDropdownFixture.detectChanges();
@@ -204,12 +201,9 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => {
});
it('should init component properly', () => {
const results$ = authorityServiceStub.getEntriesByName({} as any);
expect(scrollableDropdownComp.optionsList).toBeDefined();
results$.subscribe((results) => {
expect(scrollableDropdownComp.optionsList).toEqual(results.payload);
expect(scrollableDropdownComp.model.value).toEqual(modelValue);
})
expect(scrollableDropdownComp.optionsList).toEqual(vocabularyServiceStub.getList());
expect(scrollableDropdownComp.model.value).toEqual(modelValue);
});
});
});

View File

@@ -2,7 +2,7 @@ import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } fro
import { FormGroup } from '@angular/forms';
import { Observable, of as observableOf } from 'rxjs';
import { catchError, distinctUntilChanged, first, tap } from 'rxjs/operators';
import { catchError, distinctUntilChanged, tap } from 'rxjs/operators';
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap';
import {
DynamicFormControlComponent,
@@ -10,13 +10,14 @@ import {
DynamicFormValidationService
} from '@ng-dynamic-forms/core';
import { AuthorityValue } from '../../../../../../core/integration/models/authority.value';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { DynamicScrollableDropdownModel } from './dynamic-scrollable-dropdown.model';
import { PageInfo } from '../../../../../../core/shared/page-info.model';
import { isNull, isUndefined } from '../../../../../empty.util';
import { AuthorityService } from '../../../../../../core/integration/authority.service';
import { IntegrationSearchOptions } from '../../../../../../core/integration/models/integration-options.model';
import { IntegrationData } from '../../../../../../core/integration/integration-data';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { VocabularyFindOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators';
import { PaginatedList } from '../../../../../../core/data/paginated-list';
@Component({
selector: 'ds-dynamic-scrollable-dropdown',
@@ -37,9 +38,9 @@ export class DsDynamicScrollableDropdownComponent extends DynamicFormControlComp
public pageInfo: PageInfo;
public optionsList: any;
protected searchOptions: IntegrationSearchOptions;
protected searchOptions: VocabularyFindOptions;
constructor(private authorityService: AuthorityService,
constructor(private vocabularyService: VocabularyService,
private cdr: ChangeDetectorRef,
protected layoutService: DynamicFormLayoutService,
protected validationService: DynamicFormValidationService
@@ -48,28 +49,26 @@ export class DsDynamicScrollableDropdownComponent extends DynamicFormControlComp
}
ngOnInit() {
this.searchOptions = new IntegrationSearchOptions(
this.model.authorityOptions.scope,
this.model.authorityOptions.name,
this.model.authorityOptions.metadata,
this.searchOptions = new VocabularyFindOptions(
this.model.vocabularyOptions.scope,
this.model.vocabularyOptions.name,
this.model.vocabularyOptions.metadata,
'',
this.model.maxOptions,
1);
this.authorityService.getEntriesByName(this.searchOptions).pipe(
catchError(() => {
const emptyResult = new IntegrationData(
new PageInfo(),
[]
);
return observableOf(emptyResult);
}),
first())
.subscribe((object: IntegrationData) => {
this.optionsList = object.payload;
this.vocabularyService.getVocabularyEntries(this.searchOptions).pipe(
getFirstSucceededRemoteDataPayload(),
catchError(() => observableOf(new PaginatedList(
new PageInfo(),
[]
))
))
.subscribe((list: PaginatedList<VocabularyEntry>) => {
this.optionsList = list.page;
if (this.model.value) {
this.setCurrentValue(this.model.value);
}
this.pageInfo = object.pageInfo;
this.pageInfo = list.pageInfo;
this.cdr.detectChanges();
});
@@ -80,7 +79,7 @@ export class DsDynamicScrollableDropdownComponent extends DynamicFormControlComp
}
inputFormatter = (x: AuthorityValue): string => x.display || x.value;
inputFormatter = (x: VocabularyEntry): string => x.display || x.value;
openDropdown(sdRef: NgbDropdown) {
if (!this.model.readOnly) {
@@ -92,18 +91,17 @@ export class DsDynamicScrollableDropdownComponent extends DynamicFormControlComp
if (!this.loading && this.pageInfo.currentPage <= this.pageInfo.totalPages) {
this.loading = true;
this.searchOptions.currentPage++;
this.authorityService.getEntriesByName(this.searchOptions).pipe(
catchError(() => {
const emptyResult = new IntegrationData(
new PageInfo(),
[]
);
return observableOf(emptyResult);
}),
this.vocabularyService.getVocabularyEntries(this.searchOptions).pipe(
getFirstSucceededRemoteDataPayload(),
catchError(() => observableOf(new PaginatedList(
new PageInfo(),
[]
))
),
tap(() => this.loading = false))
.subscribe((object: IntegrationData) => {
this.optionsList = this.optionsList.concat(object.payload);
this.pageInfo = object.pageInfo;
.subscribe((list: PaginatedList<VocabularyEntry>) => {
this.optionsList = this.optionsList.concat(list.page);
this.pageInfo = list.pageInfo;
this.cdr.detectChanges();
})
}

View File

@@ -1,11 +1,11 @@
import { AUTOCOMPLETE_OFF, DynamicFormControlLayout, serializable } from '@ng-dynamic-forms/core';
import { DsDynamicInputModel, DsDynamicInputModelConfig } from '../ds-dynamic-input.model';
import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model';
import { VocabularyOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-options.model';
export const DYNAMIC_FORM_CONTROL_TYPE_SCROLLABLE_DROPDOWN = 'SCROLLABLE_DROPDOWN';
export interface DynamicScrollableDropdownModelConfig extends DsDynamicInputModelConfig {
authorityOptions: AuthorityOptions;
vocabularyOptions: VocabularyOptions;
maxOptions?: number;
value?: any;
}
@@ -20,7 +20,7 @@ export class DynamicScrollableDropdownModel extends DsDynamicInputModel {
super(config, layout);
this.autoComplete = AUTOCOMPLETE_OFF;
this.authorityOptions = config.authorityOptions;
this.vocabularyOptions = config.vocabularyOptions;
this.maxOptions = config.maxOptions || 10;
}

View File

@@ -12,15 +12,14 @@ import {
import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap';
import { NgbModule, NgbTypeaheadSelectItemEvent } from '@ng-bootstrap/ng-bootstrap';
import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model';
import { AuthorityService } from '../../../../../../core/integration/authority.service';
import { AuthorityServiceStub } from '../../../../../testing/authority-service.stub';
import { VocabularyOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-options.model';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { VocabularyServiceStub } from '../../../../../testing/vocabulary-service.stub';
import { DsDynamicTagComponent } from './dynamic-tag.component';
import { DynamicTagModel } from './dynamic-tag.model';
import { GlobalConfig } from '../../../../../../../config/global-config.interface';
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 { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { createTestComponent } from '../../../../../testing/utils.test';
function createKeyUpEvent(key: number) {
@@ -45,12 +44,12 @@ function init() {
});
TAG_TEST_MODEL_CONFIG = {
authorityOptions: {
vocabularyOptions: {
closed: false,
metadata: 'tag',
name: 'common_iso_languages',
scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'
} as AuthorityOptions,
} as VocabularyOptions,
disabled: false,
id: 'tag',
label: 'Keywords',
@@ -75,7 +74,7 @@ describe('DsDynamicTagComponent test suite', () => {
// async beforeEach
beforeEach(async(() => {
const authorityServiceStub = new AuthorityServiceStub();
const vocabularyServiceStub = new VocabularyServiceStub();
init();
TestBed.configureTestingModule({
imports: [
@@ -92,7 +91,7 @@ describe('DsDynamicTagComponent test suite', () => {
providers: [
ChangeDetectorRef,
DsDynamicTagComponent,
{ provide: AuthorityService, useValue: authorityServiceStub },
{ provide: VocabularyService, useValue: vocabularyServiceStub },
{ provide: DynamicFormLayoutService, useValue: {} },
{ provide: DynamicFormValidationService, useValue: {} }
],
@@ -124,7 +123,7 @@ describe('DsDynamicTagComponent test suite', () => {
}));
});
describe('when authorityOptions are set', () => {
describe('when vocabularyOptions are set', () => {
describe('and init model value is empty', () => {
beforeEach(() => {
@@ -148,20 +147,20 @@ describe('DsDynamicTagComponent test suite', () => {
});
it('should search when 3+ characters typed', fakeAsync(() => {
spyOn((tagComp as any).authorityService, 'getEntriesByName').and.callThrough();
spyOn((tagComp as any).vocabularyService, 'getVocabularyEntries').and.callThrough();
tagComp.search(observableOf('test')).subscribe(() => {
expect((tagComp as any).authorityService.getEntriesByName).toHaveBeenCalled();
expect((tagComp as any).vocabularyService.getVocabularyEntries).toHaveBeenCalled();
});
}));
it('should select a results entry properly', fakeAsync(() => {
modelValue = [
Object.assign(new AuthorityValue(), { id: 1, display: 'Name, Lastname', value: 1 })
Object.assign(new VocabularyEntry(), { authority: 1, display: 'Name, Lastname', value: 1 })
];
const event: NgbTypeaheadSelectItemEvent = {
item: Object.assign(new AuthorityValue(), {
id: 1,
item: Object.assign(new VocabularyEntry(), {
authority: 1,
display: 'Name, Lastname',
value: 1
}),
@@ -239,7 +238,7 @@ describe('DsDynamicTagComponent test suite', () => {
});
describe('when authorityOptions are not set', () => {
describe('when vocabularyOptions are not set', () => {
describe('and init model value is empty', () => {
beforeEach(() => {
@@ -247,7 +246,7 @@ describe('DsDynamicTagComponent test suite', () => {
tagComp = tagFixture.componentInstance; // FormComponent test instance
tagComp.group = TAG_TEST_GROUP;
const config = TAG_TEST_MODEL_CONFIG;
config.authorityOptions = null;
config.vocabularyOptions = null;
tagComp.model = new DynamicTagModel(config);
tagFixture.detectChanges();
});

View File

@@ -1,4 +1,4 @@
import { ChangeDetectorRef, Component, EventEmitter, Inject, Input, OnInit, Output, ViewChild } from '@angular/core';
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { FormGroup } from '@angular/forms';
import {
@@ -6,17 +6,21 @@ import {
DynamicFormLayoutService,
DynamicFormValidationService
} from '@ng-dynamic-forms/core';
import { of as observableOf, Observable } from 'rxjs';
import { catchError, debounceTime, distinctUntilChanged, tap, switchMap, map, merge } from 'rxjs/operators';
import { Observable, of as observableOf } from 'rxjs';
import { catchError, debounceTime, distinctUntilChanged, map, merge, switchMap, tap } from 'rxjs/operators';
import { NgbTypeahead, NgbTypeaheadSelectItemEvent } from '@ng-bootstrap/ng-bootstrap';
import { isEqual } from 'lodash';
import { AuthorityService } from '../../../../../../core/integration/authority.service';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { DynamicTagModel } from './dynamic-tag.model';
import { IntegrationSearchOptions } from '../../../../../../core/integration/models/integration-options.model';
import { VocabularyFindOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
import { Chips } from '../../../../../chips/models/chips.model';
import { hasValue, isNotEmpty } from '../../../../../empty.util';
import { environment } from '../../../../../../../environments/environment';
import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators';
import { PaginatedList } from '../../../../../../core/data/paginated-list';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { PageInfo } from '../../../../../../core/shared/page-info.model';
@Component({
selector: 'ds-dynamic-tag',
@@ -32,17 +36,25 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
@Output() change: EventEmitter<any> = new EventEmitter<any>();
@Output() focus: EventEmitter<any> = new EventEmitter<any>();
@ViewChild('instance', {static: false}) instance: NgbTypeahead;
@ViewChild('instance', { static: false }) instance: NgbTypeahead;
chips: Chips;
hasAuthority: boolean;
searching = false;
searchOptions: IntegrationSearchOptions;
searchOptions: VocabularyFindOptions;
searchFailed = false;
hideSearchingWhenUnsubscribed = new Observable(() => () => this.changeSearchingStatus(false));
currentValue: any;
constructor(private vocabularyService: VocabularyService,
private cdr: ChangeDetectorRef,
protected layoutService: DynamicFormLayoutService,
protected validationService: DynamicFormValidationService
) {
super(layoutService, validationService);
}
formatter = (x: { display: string }) => x.display;
search = (text$: Observable<string>) =>
@@ -52,44 +64,33 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
tap(() => this.changeSearchingStatus(true)),
switchMap((term) => {
if (term === '' || term.length < this.model.minChars) {
return observableOf({list: []});
return observableOf({ list: [] });
} else {
this.searchOptions.query = term;
return this.authorityService.getEntriesByName(this.searchOptions).pipe(
map((authorities) => {
// @TODO Pagination for authority is not working, to refactor when it will be fixed
return {
list: authorities.payload,
pageInfo: authorities.pageInfo
};
}),
return this.vocabularyService.getVocabularyEntries(this.searchOptions).pipe(
getFirstSucceededRemoteDataPayload(),
tap(() => this.searchFailed = false),
catchError(() => {
this.searchFailed = true;
return observableOf({list: []});
return observableOf(new PaginatedList(
new PageInfo(),
[]
));
}));
}
}),
map((results) => results.list),
map((list: PaginatedList<VocabularyEntry>) => list.page),
tap(() => this.changeSearchingStatus(false)),
merge(this.hideSearchingWhenUnsubscribed));
constructor(private authorityService: AuthorityService,
private cdr: ChangeDetectorRef,
protected layoutService: DynamicFormLayoutService,
protected validationService: DynamicFormValidationService
) {
super(layoutService, validationService);
}
ngOnInit() {
this.hasAuthority = this.model.authorityOptions && hasValue(this.model.authorityOptions.name);
this.hasAuthority = this.model.vocabularyOptions && hasValue(this.model.vocabularyOptions.name);
if (this.hasAuthority) {
this.searchOptions = new IntegrationSearchOptions(
this.model.authorityOptions.scope,
this.model.authorityOptions.name,
this.model.authorityOptions.metadata);
this.searchOptions = new VocabularyFindOptions(
this.model.vocabularyOptions.scope,
this.model.vocabularyOptions.name,
this.model.vocabularyOptions.metadata);
}
this.chips = new Chips(
@@ -166,7 +167,7 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
}
private addTagsToChips() {
if (hasValue(this.currentValue) && (!this.hasAuthority || !this.model.authorityOptions.closed)) {
if (hasValue(this.currentValue) && (!this.hasAuthority || !this.model.vocabularyOptions.closed)) {
let res: string[] = [];
res = this.currentValue.split(',');

View File

@@ -10,10 +10,9 @@ import { DynamicFormLayoutService, DynamicFormsCoreModule, DynamicFormValidation
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 { AuthorityService } from '../../../../../../core/integration/authority.service';
import { AuthorityServiceStub } from '../../../../../testing/authority-service.stub';
import { GlobalConfig } from '../../../../../../../config/global-config.interface';
import { VocabularyOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-options.model';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { VocabularyServiceStub } from '../../../../../testing/vocabulary-service.stub';
import { DsDynamicTypeaheadComponent } from './dynamic-typeahead.component';
import { DynamicTypeaheadModel } from './dynamic-typeahead.model';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
@@ -31,12 +30,12 @@ function init() {
});
TYPEAHEAD_TEST_MODEL_CONFIG = {
authorityOptions: {
vocabularyOptions: {
closed: false,
metadata: 'typeahead',
name: 'EVENTAuthority',
scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'
} as AuthorityOptions,
} as VocabularyOptions,
disabled: false,
id: 'typeahead',
label: 'Conference',
@@ -49,6 +48,7 @@ function init() {
value: undefined
};
}
describe('DsDynamicTypeaheadComponent test suite', () => {
let testComp: TestComponent;
@@ -59,7 +59,7 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
// async beforeEach
beforeEach(async(() => {
const authorityServiceStub = new AuthorityServiceStub();
const vocabularyServiceStub = new VocabularyServiceStub();
init();
TestBed.configureTestingModule({
imports: [
@@ -79,7 +79,7 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
providers: [
ChangeDetectorRef,
DsDynamicTypeaheadComponent,
{ provide: AuthorityService, useValue: authorityServiceStub },
{ provide: VocabularyService, useValue: vocabularyServiceStub },
{ provide: DynamicFormLayoutService, useValue: {} },
{ provide: DynamicFormValidationService, useValue: {} }
],
@@ -134,17 +134,17 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
it('should search when 3+ characters typed', fakeAsync(() => {
spyOn((typeaheadComp as any).authorityService, 'getEntriesByName').and.callThrough();
spyOn((typeaheadComp as any).vocabularyService, 'getVocabularyEntries').and.callThrough();
typeaheadComp.search(observableOf('test')).subscribe();
tick(300);
typeaheadFixture.detectChanges();
expect((typeaheadComp as any).authorityService.getEntriesByName).toHaveBeenCalled();
expect((typeaheadComp as any).vocabularyService.getVocabularyEntries).toHaveBeenCalled();
}));
it('should set model.value on input type when AuthorityOptions.closed is false', () => {
it('should set model.value on input type when VocabularyOptions.closed is false', () => {
const inputDe = typeaheadFixture.debugElement.query(By.css('input.form-control'));
const inputElement = inputDe.nativeElement;
@@ -155,8 +155,8 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
});
it('should not set model.value on input type when AuthorityOptions.closed is true', () => {
typeaheadComp.model.authorityOptions.closed = true;
it('should not set model.value on input type when VocabularyOptions.closed is true', () => {
typeaheadComp.model.vocabularyOptions.closed = true;
typeaheadFixture.detectChanges();
const inputDe = typeaheadFixture.debugElement.query(By.css('input.form-control'));
const inputElement = inputDe.nativeElement;
@@ -184,18 +184,18 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
expect(typeaheadComp.blur.emit).not.toHaveBeenCalled();
});
it('should emit change Event onBlur when AuthorityOptions.closed is false and inputValue is changed', () => {
it('should emit change Event onBlur when VocabularyOptions.closed is false and inputValue is changed', () => {
typeaheadComp.inputValue = 'test value';
typeaheadFixture.detectChanges();
spyOn(typeaheadComp.blur, 'emit');
spyOn(typeaheadComp.change, 'emit');
spyOn(typeaheadComp.instance, 'isPopupOpen').and.returnValue(false);
typeaheadComp.onBlur(new Event('blur', ));
typeaheadComp.onBlur(new Event('blur',));
expect(typeaheadComp.change.emit).toHaveBeenCalled();
expect(typeaheadComp.blur.emit).toHaveBeenCalled();
});
it('should not emit change Event onBlur when AuthorityOptions.closed is false and inputValue is not changed', () => {
it('should not emit change Event onBlur when VocabularyOptions.closed is false and inputValue is not changed', () => {
typeaheadComp.inputValue = 'test value';
typeaheadComp.model = new DynamicTypeaheadModel(TYPEAHEAD_TEST_MODEL_CONFIG);
(typeaheadComp.model as any).value = 'test value';
@@ -203,12 +203,12 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
spyOn(typeaheadComp.blur, 'emit');
spyOn(typeaheadComp.change, 'emit');
spyOn(typeaheadComp.instance, 'isPopupOpen').and.returnValue(false);
typeaheadComp.onBlur(new Event('blur', ));
typeaheadComp.onBlur(new Event('blur',));
expect(typeaheadComp.change.emit).not.toHaveBeenCalled();
expect(typeaheadComp.blur.emit).toHaveBeenCalled();
});
it('should not emit change Event onBlur when AuthorityOptions.closed is false and inputValue is null', () => {
it('should not emit change Event onBlur when VocabularyOptions.closed is false and inputValue is null', () => {
typeaheadComp.inputValue = null;
typeaheadComp.model = new DynamicTypeaheadModel(TYPEAHEAD_TEST_MODEL_CONFIG);
(typeaheadComp.model as any).value = 'test value';
@@ -216,7 +216,7 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
spyOn(typeaheadComp.blur, 'emit');
spyOn(typeaheadComp.change, 'emit');
spyOn(typeaheadComp.instance, 'isPopupOpen').and.returnValue(false);
typeaheadComp.onBlur(new Event('blur', ));
typeaheadComp.onBlur(new Event('blur',));
expect(typeaheadComp.change.emit).not.toHaveBeenCalled();
expect(typeaheadComp.blur.emit).toHaveBeenCalled();
});

View File

@@ -10,12 +10,16 @@ import { catchError, debounceTime, distinctUntilChanged, filter, map, merge, swi
import { Observable, of as observableOf, Subject } from 'rxjs';
import { NgbTypeahead, NgbTypeaheadSelectItemEvent } from '@ng-bootstrap/ng-bootstrap';
import { AuthorityService } from '../../../../../../core/integration/authority.service';
import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service';
import { DynamicTypeaheadModel } from './dynamic-typeahead.model';
import { IntegrationSearchOptions } from '../../../../../../core/integration/models/integration-options.model';
import { VocabularyFindOptions } from '../../../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
import { isEmpty, isNotEmpty, isNotNull } from '../../../../../empty.util';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { ConfidenceType } from '../../../../../../core/integration/models/confidence-type';
import { ConfidenceType } from '../../../../../../core/shared/confidence-type';
import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators';
import { PaginatedList } from '../../../../../../core/data/paginated-list';
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
import { PageInfo } from '../../../../../../core/shared/page-info.model';
@Component({
selector: 'ds-dynamic-typeahead',
@@ -31,16 +35,24 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp
@Output() change: EventEmitter<any> = new EventEmitter<any>();
@Output() focus: EventEmitter<any> = new EventEmitter<any>();
@ViewChild('instance', {static: false}) instance: NgbTypeahead;
@ViewChild('instance', { static: false }) instance: NgbTypeahead;
searching = false;
searchOptions: IntegrationSearchOptions;
searchOptions: VocabularyFindOptions;
searchFailed = false;
hideSearchingWhenUnsubscribed$ = new Observable(() => () => this.changeSearchingStatus(false));
click$ = new Subject<string>();
currentValue: any;
inputValue: any;
constructor(private vocabularyService: VocabularyService,
private cdr: ChangeDetectorRef,
protected layoutService: DynamicFormLayoutService,
protected validationService: DynamicFormValidationService
) {
super(layoutService, validationService);
}
formatter = (x: { display: string }) => {
return (typeof x === 'object') ? x.display : x
};
@@ -53,44 +65,33 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp
tap(() => this.changeSearchingStatus(true)),
switchMap((term) => {
if (term === '' || term.length < this.model.minChars) {
return observableOf({list: []});
return observableOf({ list: [] });
} else {
this.searchOptions.query = term;
return this.authorityService.getEntriesByName(this.searchOptions).pipe(
map((authorities) => {
// @TODO Pagination for authority is not working, to refactor when it will be fixed
return {
list: authorities.payload,
pageInfo: authorities.pageInfo
};
}),
return this.vocabularyService.getVocabularyEntries(this.searchOptions).pipe(
getFirstSucceededRemoteDataPayload(),
tap(() => this.searchFailed = false),
catchError(() => {
this.searchFailed = true;
return observableOf({list: []});
return observableOf(new PaginatedList(
new PageInfo(),
[]
));
}));
}
}),
map((results) => results.list),
map((list: PaginatedList<VocabularyEntry>) => list.page),
tap(() => this.changeSearchingStatus(false)),
merge(this.hideSearchingWhenUnsubscribed$)
)
};
constructor(private authorityService: AuthorityService,
private cdr: ChangeDetectorRef,
protected layoutService: DynamicFormLayoutService,
protected validationService: DynamicFormValidationService
) {
super(layoutService, validationService);
}
ngOnInit() {
this.currentValue = this.model.value;
this.searchOptions = new IntegrationSearchOptions(
this.model.authorityOptions.scope,
this.model.authorityOptions.name,
this.model.authorityOptions.metadata);
this.searchOptions = new VocabularyFindOptions(
this.model.vocabularyOptions.scope,
this.model.vocabularyOptions.name,
this.model.vocabularyOptions.metadata);
this.group.get(this.model.id).valueChanges.pipe(
filter((value) => this.currentValue !== value))
.subscribe((value) => {
@@ -104,14 +105,14 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp
}
onInput(event) {
if (!this.model.authorityOptions.closed && isNotEmpty(event.target.value)) {
if (!this.model.vocabularyOptions.closed && isNotEmpty(event.target.value)) {
this.inputValue = new FormFieldMetadataValueObject(event.target.value);
}
}
onBlur(event: Event) {
if (!this.instance.isPopupOpen()) {
if (!this.model.authorityOptions.closed && isNotEmpty(this.inputValue)) {
if (!this.model.vocabularyOptions.closed && isNotEmpty(this.inputValue)) {
if (isNotNull(this.inputValue) && this.model.value !== this.inputValue) {
this.model.valueUpdates.next(this.inputValue);
this.change.emit(this.inputValue);

View File

@@ -36,7 +36,7 @@ import { DynamicLookupModel } from './ds-dynamic-form-ui/models/lookup/dynamic-l
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';
import { DynamicListRadioGroupModel } from './ds-dynamic-form-ui/models/list/dynamic-list-radio-group.model';
import { AuthorityOptions } from '../../../core/integration/models/authority-options.model';
import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
import { FormFieldModel } from './models/form-field.model';
import {
SubmissionFormsModel
@@ -78,7 +78,7 @@ describe('FormBuilderService test suite', () => {
]
});
const authorityOptions: AuthorityOptions = {
const vocabularyOptions: VocabularyOptions = {
closed: false,
metadata: 'list',
name: 'type_programme',
@@ -197,13 +197,13 @@ describe('FormBuilderService test suite', () => {
new DynamicTypeaheadModel({id: 'testTypeahead', repeatable: false, metadataFields: [], submissionId: '1234'}),
new DynamicScrollableDropdownModel({id: 'testScrollableDropdown', authorityOptions: authorityOptions, repeatable: false, metadataFields: [], submissionId: '1234'}),
new DynamicScrollableDropdownModel({id: 'testScrollableDropdown', vocabularyOptions: vocabularyOptions, repeatable: false, metadataFields: [], submissionId: '1234'}),
new DynamicTagModel({id: 'testTag', repeatable: false, metadataFields: [], submissionId: '1234'}),
new DynamicListCheckboxGroupModel({id: 'testCheckboxList', authorityOptions: authorityOptions, repeatable: true}),
new DynamicListCheckboxGroupModel({id: 'testCheckboxList', vocabularyOptions: vocabularyOptions, repeatable: true}),
new DynamicListRadioGroupModel({id: 'testRadioList', authorityOptions: authorityOptions, repeatable: false}),
new DynamicListRadioGroupModel({id: 'testRadioList', vocabularyOptions: vocabularyOptions, repeatable: false}),
new DynamicRelationGroupModel({
submissionId,
@@ -218,7 +218,7 @@ describe('FormBuilderService test suite', () => {
mandatoryMessage: 'Required field!',
repeatable: false,
selectableMetadata: [{
authority: 'RPAuthority',
controlledVocabulary: 'RPAuthority',
closed: false,
metadata: 'dc.contributor.author'
}],
@@ -232,7 +232,7 @@ describe('FormBuilderService test suite', () => {
mandatory: 'false',
repeatable: false,
selectableMetadata: [{
authority: 'OUAuthority',
controlledVocabulary: 'OUAuthority',
closed: false,
metadata: 'local.contributor.affiliation'
}]
@@ -284,7 +284,7 @@ describe('FormBuilderService test suite', () => {
selectableMetadata: [
{
metadata: 'journal',
authority: 'JOURNALAuthority',
controlledVocabulary: 'JOURNALAuthority',
closed: false
}
],
@@ -364,7 +364,7 @@ describe('FormBuilderService test suite', () => {
selectableMetadata: [
{
metadata: 'conference',
authority: 'EVENTAuthority',
controlledVocabulary: 'EVENTAuthority',
closed: false
}
],

View File

@@ -1,5 +1,5 @@
import { isEmpty, isNotEmpty, isNotNull } from '../../../empty.util';
import { ConfidenceType } from '../../../../core/integration/models/confidence-type';
import { ConfidenceType } from '../../../../core/shared/confidence-type';
import { PLACEHOLDER_PARENT_METADATA } from '../ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
import { MetadataValueInterface } from '../../../../core/shared/metadata.models';
@@ -7,15 +7,16 @@ export interface OtherInformation {
[name: string]: string
}
/**
* A class representing a specific input-form field's value
*/
export class FormFieldMetadataValueObject implements MetadataValueInterface {
metadata?: string;
value: any;
display: string;
language: any;
authority: string;
confidence: ConfidenceType;
place: number;
closed: boolean;
label: string;
otherInformation: OtherInformation;
@@ -42,9 +43,6 @@ export class FormFieldMetadataValueObject implements MetadataValueInterface {
}
this.place = place;
if (isNotEmpty(metadata)) {
this.metadata = metadata;
}
this.otherInformation = otherInformation;
}

View File

@@ -1,50 +1,121 @@
import { autoserialize } from 'cerialize';
import { LanguageCode } from './form-field-language-value.model';
import { FormFieldMetadataValueObject } from './form-field-metadata-value.model';
import { RelationshipOptions } from './relationship-options.model';
import { FormRowModel } from '../../../../core/config/models/config-submission-form.model';
/**
* Representing SelectableMetadata properties
*/
export interface SelectableMetadata {
/**
* The key of the metadata field to use to store the input
*/
metadata: string;
/**
* The label of the metadata field to use to store the input
*/
label: string;
/**
* The name of the controlled vocabulary used to retrieve value for the input see controlled vocabularies
*/
controlledVocabulary: string;
/**
* A boolean representing if value is closely related to the controlled vocabulary entry or not
*/
closed: boolean;
}
/**
* A class representing a specific input-form field
*/
export class FormFieldModel {
/**
* The hints for this metadata field to display on form
*/
@autoserialize
hints: string;
/**
* The label for this metadata field to display on form
*/
@autoserialize
label: string;
/**
* The languages available for this metadata field to display on form
*/
@autoserialize
languageCodes: LanguageCode[];
/**
* The error message for this metadata field to display on form in case of field is required
*/
@autoserialize
mandatoryMessage: string;
/**
* Representing if this metadata field is mandatory or not
*/
@autoserialize
mandatory: string;
/**
* Representing if this metadata field is repeatable or not
*/
@autoserialize
repeatable: boolean;
/**
* Containing additional properties for this metadata field
*/
@autoserialize
input: {
/**
* Representing the type for this metadata field
*/
type: string;
/**
* Containing regex to use for field validation
*/
regex?: string;
};
/**
* Representing additional vocabulary configuration for this metadata field
*/
@autoserialize
selectableMetadata: FormFieldMetadataValueObject[];
selectableMetadata: SelectableMetadata[];
/**
* Representing additional relationship configuration for this metadata field
*/
@autoserialize
selectableRelationship: RelationshipOptions;
@autoserialize
rows: FormRowModel[];
/**
* Representing the scope for this metadata field
*/
@autoserialize
scope: string;
/**
* Containing additional css classes for this metadata field to use on form
*/
@autoserialize
style: string;
/**
* Containing the value for this metadata field
*/
@autoserialize
value: any;
}

View File

@@ -12,7 +12,7 @@ describe('DateFieldParser test suite', () => {
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: null,
authorityUuid: null
collectionUUID: null
};
beforeEach(() => {

View File

@@ -12,7 +12,7 @@ describe('DisabledFieldParser test suite', () => {
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: null,
authorityUuid: null
collectionUUID: null
};
beforeEach(() => {

View File

@@ -11,7 +11,7 @@ describe('DropdownFieldParser test suite', () => {
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
authorityUuid: null
collectionUUID: null
};
beforeEach(() => {
@@ -26,7 +26,7 @@ describe('DropdownFieldParser test suite', () => {
selectableMetadata: [
{
metadata: 'type',
authority: 'common_types_dataset',
controlledVocabulary: 'common_types_dataset',
closed: false
}
],
@@ -50,7 +50,7 @@ describe('DropdownFieldParser test suite', () => {
});
it('should throw when authority is not passed', () => {
field.selectableMetadata[0].authority = null;
field.selectableMetadata[0].controlledVocabulary = null;
const parser = new DropdownFieldParser(submissionId, field, initFormValues, parserOptions);
expect(() => parser.parse())

View File

@@ -31,8 +31,8 @@ export class DropdownFieldParser extends FieldParser {
const dropdownModelConfig: DynamicScrollableDropdownModelConfig = this.initModel(null, label);
let layout: DynamicFormControlLayout;
if (isNotEmpty(this.configData.selectableMetadata[0].authority)) {
this.setAuthorityOptions(dropdownModelConfig, this.parserOptions.authorityUuid);
if (isNotEmpty(this.configData.selectableMetadata[0].controlledVocabulary)) {
this.setVocabularyOptions(dropdownModelConfig, this.parserOptions.collectionUUID);
if (isNotEmpty(fieldValue)) {
dropdownModelConfig.value = fieldValue;
}
@@ -47,7 +47,7 @@ export class DropdownFieldParser extends FieldParser {
const dropdownModel = new DynamicScrollableDropdownModel(dropdownModelConfig, layout);
return dropdownModel;
} else {
throw Error(`Authority name is not available. Please check the form configuration file.`);
throw Error(`Controlled Vocabulary name is not available. Please check the form configuration file.`);
}
}
}

View File

@@ -1,19 +1,20 @@
import { Inject, InjectionToken } from '@angular/core';
import { hasValue, isNotEmpty, isNotNull, isNotUndefined, isEmpty } from '../../../empty.util';
import { FormFieldModel } from '../models/form-field.model';
import { uniqueId } from 'lodash';
import { DynamicFormControlLayout } from '@ng-dynamic-forms/core';
import { hasValue, isEmpty, isNotEmpty, isNotNull, isNotUndefined } from '../../../empty.util';
import { FormFieldModel } from '../models/form-field.model';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
import {
DynamicRowArrayModel,
DynamicRowArrayModelConfig
} from '../ds-dynamic-form-ui/models/ds-dynamic-row-array-model';
import { DsDynamicInputModel, DsDynamicInputModelConfig } from '../ds-dynamic-form-ui/models/ds-dynamic-input.model';
import { DynamicFormControlLayout } from '@ng-dynamic-forms/core';
import { setLayout } from './parser.utils';
import { AuthorityOptions } from '../../../../core/integration/models/authority-options.model';
import { ParserOptions } from './parser-options';
import { RelationshipOptions } from '../models/relationship-options.model';
import { VocabularyOptions } from '../../../../core/submission/vocabularies/models/vocabulary-options.model';
export const SUBMISSION_ID: InjectionToken<string> = new InjectionToken<string>('submissionId');
export const CONFIG_DATA: InjectionToken<FormFieldModel> = new InjectionToken<FormFieldModel>('configData');
@@ -49,7 +50,7 @@ export abstract class FieldParser {
label: this.configData.label,
initialCount: this.getInitArrayIndex(),
notRepeatable: !this.configData.repeatable,
required: JSON.parse( this.configData.mandatory),
required: JSON.parse(this.configData.mandatory),
groupFactory: () => {
let model;
if ((arrayCounter === 0)) {
@@ -92,6 +93,52 @@ export abstract class FieldParser {
}
}
public setVocabularyOptions(controlModel, scope) {
if (isNotEmpty(this.configData.selectableMetadata) && isNotEmpty(this.configData.selectableMetadata[0].controlledVocabulary)) {
controlModel.vocabularyOptions = new VocabularyOptions(
this.configData.selectableMetadata[0].controlledVocabulary,
this.configData.selectableMetadata[0].metadata,
scope,
this.configData.selectableMetadata[0].closed
)
}
}
public setValues(modelConfig: DsDynamicInputModelConfig, fieldValue: any, forceValueAsObj: boolean = false, groupModel?: boolean) {
if (isNotEmpty(fieldValue)) {
if (groupModel) {
// Array, values is an array
modelConfig.value = this.getInitGroupValues();
if (Array.isArray(modelConfig.value) && modelConfig.value.length > 0 && modelConfig.value[0].language) {
// Array Item has language, ex. AuthorityModel
modelConfig.language = modelConfig.value[0].language;
}
return;
}
if (typeof fieldValue === 'object') {
modelConfig.language = fieldValue.language;
if (forceValueAsObj) {
modelConfig.value = fieldValue;
} else {
modelConfig.value = fieldValue.value;
}
} else {
if (forceValueAsObj) {
// If value isn't an instance of FormFieldMetadataValueObject instantiate it
modelConfig.value = new FormFieldMetadataValueObject(fieldValue);
} else {
if (typeof fieldValue === 'string') {
// Case only string
modelConfig.value = fieldValue;
}
}
}
}
return modelConfig;
}
protected getInitValueCount(index = 0, fieldId?): number {
const fieldIds = fieldId || this.getAllFieldIds();
if (isNotEmpty(this.initFormValues) && isNotNull(fieldIds) && fieldIds.length === 1 && this.initFormValues.hasOwnProperty(fieldIds[0])) {
@@ -135,7 +182,7 @@ export abstract class FieldParser {
fieldIds.forEach((id) => {
if (this.initFormValues.hasOwnProperty(id)) {
const valueObj: FormFieldMetadataValueObject = Object.assign(new FormFieldMetadataValueObject(), this.initFormValues[id][innerIndex]);
valueObj.metadata = id;
// valueObj.metadata = id;
// valueObj.value = this.initFormValues[id][innerIndex];
values.push(valueObj);
}
@@ -224,14 +271,6 @@ 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,50 +317,4 @@ export abstract class FieldParser {
}
}
public setAuthorityOptions(controlModel, authorityUuid) {
if (isNotEmpty(this.configData.selectableMetadata) && isNotEmpty(this.configData.selectableMetadata[0].authority)) {
controlModel.authorityOptions = new AuthorityOptions(
this.configData.selectableMetadata[0].authority,
this.configData.selectableMetadata[0].metadata,
authorityUuid,
this.configData.selectableMetadata[0].closed
)
}
}
public setValues(modelConfig: DsDynamicInputModelConfig, fieldValue: any, forceValueAsObj: boolean = false, groupModel?: boolean) {
if (isNotEmpty(fieldValue)) {
if (groupModel) {
// Array, values is an array
modelConfig.value = this.getInitGroupValues();
if (Array.isArray(modelConfig.value) && modelConfig.value.length > 0 && modelConfig.value[0].language) {
// Array Item has language, ex. AuthorityModel
modelConfig.language = modelConfig.value[0].language;
}
return;
}
if (typeof fieldValue === 'object') {
modelConfig.language = fieldValue.language;
if (forceValueAsObj) {
modelConfig.value = fieldValue;
} else {
modelConfig.value = fieldValue.value;
}
} else {
if (forceValueAsObj) {
// If value isn't an instance of FormFieldMetadataValueObject instantiate it
modelConfig.value = new FormFieldMetadataValueObject(fieldValue);
} else {
if (typeof fieldValue === 'string') {
// Case only string
modelConfig.value = fieldValue;
}
}
}
}
return modelConfig;
}
}

View File

@@ -13,7 +13,7 @@ describe('ListFieldParser test suite', () => {
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
authorityUuid: null
collectionUUID: null
};
beforeEach(() => {
@@ -28,7 +28,7 @@ describe('ListFieldParser test suite', () => {
selectableMetadata: [
{
metadata: 'type',
authority: 'type_programme',
controlledVocabulary: 'type_programme',
closed: false
}
],

View File

@@ -1,19 +1,19 @@
import { FieldParser } from './field-parser';
import { isNotEmpty } from '../../../empty.util';
import { IntegrationSearchOptions } from '../../../../core/integration/models/integration-options.model';
import { VocabularyFindOptions } from '../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
import { DynamicListCheckboxGroupModel } from '../ds-dynamic-form-ui/models/list/dynamic-list-checkbox-group.model';
import { DynamicListRadioGroupModel } from '../ds-dynamic-form-ui/models/list/dynamic-list-radio-group.model';
export class ListFieldParser extends FieldParser {
searchOptions: IntegrationSearchOptions;
searchOptions: VocabularyFindOptions;
public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any {
const listModelConfig = this.initModel(null, label);
listModelConfig.repeatable = this.configData.repeatable;
if (this.configData.selectableMetadata[0].authority
&& this.configData.selectableMetadata[0].authority.length > 0) {
if (this.configData.selectableMetadata[0].controlledVocabulary
&& this.configData.selectableMetadata[0].controlledVocabulary.length > 0) {
if (isNotEmpty(this.getInitGroupValues())) {
listModelConfig.value = [];
@@ -26,7 +26,7 @@ export class ListFieldParser extends FieldParser {
}
});
}
this.setAuthorityOptions(listModelConfig, this.parserOptions.authorityUuid);
this.setVocabularyOptions(listModelConfig, this.parserOptions.collectionUUID);
}
let listModel;

View File

@@ -12,7 +12,7 @@ describe('LookupFieldParser test suite', () => {
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
authorityUuid: null
collectionUUID: null
};
beforeEach(() => {
@@ -27,7 +27,7 @@ describe('LookupFieldParser test suite', () => {
selectableMetadata: [
{
metadata: 'journal',
authority: 'JOURNALAuthority',
controlledVocabulary: 'JOURNALAuthority',
closed: false
}
],

View File

@@ -5,10 +5,10 @@ import { FormFieldMetadataValueObject } from '../models/form-field-metadata-valu
export class LookupFieldParser extends FieldParser {
public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any {
if (this.configData.selectableMetadata[0].authority) {
if (this.configData.selectableMetadata[0].controlledVocabulary) {
const lookupModelConfig: DynamicLookupModelConfig = this.initModel(null, label);
this.setAuthorityOptions(lookupModelConfig, this.parserOptions.authorityUuid);
this.setVocabularyOptions(lookupModelConfig, this.parserOptions.collectionUUID);
this.setValues(lookupModelConfig, fieldValue, true);

View File

@@ -12,7 +12,7 @@ describe('LookupNameFieldParser test suite', () => {
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
authorityUuid: null
collectionUUID: null
};
beforeEach(() => {
@@ -27,7 +27,7 @@ describe('LookupNameFieldParser test suite', () => {
selectableMetadata: [
{
metadata: 'author',
authority: 'RPAuthority',
controlledVocabulary: 'RPAuthority',
closed: false
}
],

View File

@@ -8,10 +8,10 @@ import { FormFieldMetadataValueObject } from '../models/form-field-metadata-valu
export class LookupNameFieldParser extends FieldParser {
public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any {
if (this.configData.selectableMetadata[0].authority) {
if (this.configData.selectableMetadata[0].controlledVocabulary) {
const lookupModelConfig: DynamicLookupNameModelConfig = this.initModel(null, label);
this.setAuthorityOptions(lookupModelConfig, this.parserOptions.authorityUuid);
this.setVocabularyOptions(lookupModelConfig, this.parserOptions.collectionUUID);
this.setValues(lookupModelConfig, fieldValue, true);

View File

@@ -14,7 +14,7 @@ describe('NameFieldParser test suite', () => {
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
authorityUuid: null
collectionUUID: null
};
beforeEach(() => {

View File

@@ -15,7 +15,7 @@ describe('OneboxFieldParser test suite', () => {
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
authorityUuid: null
collectionUUID: null
};
beforeEach(() => {
@@ -28,7 +28,7 @@ describe('OneboxFieldParser test suite', () => {
selectableMetadata: [
{
metadata: 'title',
authority: 'EVENTAuthority',
controlledVocabulary: 'EVENTAuthority',
closed: false
}
],

View File

@@ -75,9 +75,9 @@ export class OneboxFieldParser extends FieldParser {
inputSelectGroup.group.push(new DsDynamicInputModel(inputModelConfig, clsInput));
return new DynamicQualdropModel(inputSelectGroup, clsGroup);
} else if (this.configData.selectableMetadata[0].authority) {
} else if (this.configData.selectableMetadata[0].controlledVocabulary) {
const typeaheadModelConfig: DsDynamicTypeaheadModelConfig = this.initModel(null, label);
this.setAuthorityOptions(typeaheadModelConfig, this.parserOptions.authorityUuid);
this.setVocabularyOptions(typeaheadModelConfig, this.parserOptions.collectionUUID);
this.setValues(typeaheadModelConfig, fieldValue, true);
return new DynamicTypeaheadModel(typeaheadModelConfig);

View File

@@ -1,5 +1,5 @@
export interface ParserOptions {
readOnly: boolean;
submissionScope: string;
authorityUuid: string
collectionUUID: string
}

View File

@@ -12,7 +12,7 @@ describe('RelationGroupFieldParser test suite', () => {
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
authorityUuid: 'WORKSPACE'
collectionUUID: 'WORKSPACE'
};
beforeEach(() => {

View File

@@ -16,7 +16,7 @@ export class RelationGroupFieldParser extends FieldParser {
const modelConfiguration: DynamicRelationGroupModelConfig = this.initModel(null, label);
modelConfiguration.submissionId = this.submissionId;
modelConfiguration.scopeUUID = this.parserOptions.authorityUuid;
modelConfiguration.scopeUUID = this.parserOptions.collectionUUID;
modelConfiguration.submissionScope = this.parserOptions.submissionScope;
if (this.configData && this.configData.rows && this.configData.rows.length > 0) {
modelConfiguration.formConfiguration = this.configData.rows;

View File

@@ -35,7 +35,7 @@ describe('RowParser test suite', () => {
selectableMetadata: [
{
metadata: 'journal',
authority: 'JOURNALAuthority',
controlledVocabulary: 'JOURNALAuthority',
closed: false
}
],
@@ -83,7 +83,7 @@ describe('RowParser test suite', () => {
selectableMetadata: [
{
metadata: 'title',
authority: 'EVENTAuthority',
controlledVocabulary: 'EVENTAuthority',
closed: false
}
],
@@ -103,7 +103,7 @@ describe('RowParser test suite', () => {
selectableMetadata: [
{
metadata: 'title',
authority: 'EVENTAuthority',
controlledVocabulary: 'EVENTAuthority',
closed: false
}
],
@@ -119,7 +119,7 @@ describe('RowParser test suite', () => {
selectableMetadata: [
{
metadata: 'otherTitle',
authority: 'EVENTAuthority',
controlledVocabulary: 'EVENTAuthority',
closed: false
}
],
@@ -141,7 +141,7 @@ describe('RowParser test suite', () => {
selectableMetadata: [
{
metadata: 'type',
authority: 'common_types_dataset',
controlledVocabulary: 'common_types_dataset',
closed: false
}
],
@@ -176,7 +176,7 @@ describe('RowParser test suite', () => {
selectableMetadata: [
{
metadata: 'author',
authority: 'RPAuthority',
controlledVocabulary: 'RPAuthority',
closed: false
}
],
@@ -198,7 +198,7 @@ describe('RowParser test suite', () => {
selectableMetadata: [
{
metadata: 'type',
authority: 'type_programme',
controlledVocabulary: 'type_programme',
closed: false
}
],
@@ -241,7 +241,7 @@ describe('RowParser test suite', () => {
selectableMetadata: [
{
metadata: 'subject',
authority: 'JOURNALAuthority',
controlledVocabulary: 'JOURNALAuthority',
closed: false
}
],

View File

@@ -5,7 +5,7 @@ import {
} from '@ng-dynamic-forms/core';
import { uniqueId } from 'lodash';
import { IntegrationSearchOptions } from '../../../../core/integration/models/integration-options.model';
import { VocabularyFindOptions } from '../../../../core/submission/vocabularies/models/vocabulary-find-options.model';
import { isEmpty } from '../../../empty.util';
import { DynamicRowGroupModel } from '../ds-dynamic-form-ui/models/ds-dynamic-row-group-model';
import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from '../ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
@@ -48,7 +48,7 @@ export class RowParser {
group: [],
};
const authorityOptions = new IntegrationSearchOptions(scopeUUID);
const vocabularyOptions = new VocabularyFindOptions(scopeUUID);
const scopedFields: FormFieldModel[] = this.filterScopedFields(rowData.fields, submissionScope);
@@ -58,7 +58,7 @@ export class RowParser {
const parserOptions: ParserOptions = {
readOnly: readOnly,
submissionScope: submissionScope,
authorityUuid: authorityOptions.uuid
collectionUUID: vocabularyOptions.collection
};
// Iterate over row's fields

View File

@@ -12,7 +12,7 @@ describe('SeriesFieldParser test suite', () => {
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
authorityUuid: null
collectionUUID: null
};
beforeEach(() => {

View File

@@ -12,7 +12,7 @@ describe('TagFieldParser test suite', () => {
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: 'testScopeUUID',
authorityUuid: null
collectionUUID: null
};
beforeEach(() => {
@@ -27,7 +27,7 @@ describe('TagFieldParser test suite', () => {
selectableMetadata: [
{
metadata: 'subject',
authority: 'JOURNALAuthority',
controlledVocabulary: 'JOURNALAuthority',
closed: false
}
],

View File

@@ -6,9 +6,9 @@ export class TagFieldParser extends FieldParser {
public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any {
const tagModelConfig: DynamicTagModelConfig = this.initModel(null, label);
if (this.configData.selectableMetadata[0].authority
&& this.configData.selectableMetadata[0].authority.length > 0) {
this.setAuthorityOptions(tagModelConfig, this.parserOptions.authorityUuid);
if (this.configData.selectableMetadata[0].controlledVocabulary
&& this.configData.selectableMetadata[0].controlledVocabulary.length > 0) {
this.setVocabularyOptions(tagModelConfig, this.parserOptions.collectionUUID);
}
this.setValues(tagModelConfig, fieldValue, null, true);

View File

@@ -12,7 +12,7 @@ describe('TextareaFieldParser test suite', () => {
const parserOptions: ParserOptions = {
readOnly: false,
submissionScope: null,
authorityUuid: null
collectionUUID: null
};
beforeEach(() => {

View File

@@ -1,16 +1,19 @@
import { DynamicSelectModel } from '@ng-dynamic-forms/core';
import { DsDynamicInputModel } from '../form/builder/ds-dynamic-form-ui/models/ds-dynamic-input.model';
import { DynamicQualdropModel } from '../form/builder/ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model';
import { DynamicRowArrayModel, DynamicRowArrayModelConfig } from '../form/builder/ds-dynamic-form-ui/models/ds-dynamic-row-array-model';
import { DynamicSelectModel } from '@ng-dynamic-forms/core';
import {
DynamicRowArrayModel,
DynamicRowArrayModelConfig
} from '../form/builder/ds-dynamic-form-ui/models/ds-dynamic-row-array-model';
import { SubmissionScopeType } from '../../core/submission/submission-scope-type';
import { DynamicRelationGroupModel } from '../form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
import { FormFieldModel } from '../form/builder/models/form-field.model';
import { AuthorityOptions } from '../../core/integration/models/authority-options.model';
import { AuthorityValue } from '../../core/integration/models/authority.value';
import { VocabularyOptions } from '../../core/submission/vocabularies/models/vocabulary-options.model';
import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
import { DynamicRowGroupModel } from '../form/builder/ds-dynamic-form-ui/models/ds-dynamic-row-group-model';
import { FormRowModel } from '../../core/config/models/config-submission-form.model';
import { WorkspaceItem } from '../../core/submission/models/workspaceitem.model';
export const qualdropSelectConfig = {
name: 'dc.identifier_QUALDROP_METADATA',
@@ -87,7 +90,7 @@ export const MockRowArrayQualdropModel: DynamicRowArrayModel = new DynamicRowArr
const mockFormRowModel = {
fields: [
{
input: {type: 'lookup'},
input: { type: 'lookup' },
label: 'Journal',
mandatory: 'false',
repeatable: false,
@@ -95,14 +98,14 @@ const mockFormRowModel = {
selectableMetadata: [
{
metadata: 'journal',
authority: 'JOURNALAuthority',
controlledVocabulary: 'JOURNALAuthority',
closed: false
}
],
languageCodes: []
} as FormFieldModel,
{
input: {type: 'onebox'},
input: { type: 'onebox' },
label: 'Issue',
mandatory: 'false',
repeatable: false,
@@ -142,7 +145,7 @@ const relationGroupConfig = {
export const MockRelationModel: DynamicRelationGroupModel = new DynamicRelationGroupModel(relationGroupConfig);
export const inputWithLanguageAndAuthorityConfig = {
authorityOptions: new AuthorityOptions('testAuthority', 'testWithAuthority', 'scope'),
vocabularyOptions: new VocabularyOptions('testAuthority', 'testWithAuthority', 'scope'),
languageCodes: [
{
display: 'English',
@@ -159,10 +162,10 @@ export const inputWithLanguageAndAuthorityConfig = {
readOnly: false,
disabled: false,
repeatable: false,
value: {
value: {
value: 'testWithLanguageAndAuthority',
display: 'testWithLanguageAndAuthority',
id: 'testWithLanguageAndAuthority',
authority: 'testWithLanguageAndAuthority',
},
submissionId: '1234',
metadataFields: []
@@ -195,7 +198,7 @@ export const inputWithLanguageConfig = {
export const mockInputWithLanguageModel = new DsDynamicInputModel(inputWithLanguageConfig);
export const inputWithLanguageAndAuthorityArrayConfig = {
authorityOptions: new AuthorityOptions('testAuthority', 'testWithAuthority', 'scope'),
vocabularyOptions: new VocabularyOptions('testAuthority', 'testWithAuthority', 'scope'),
languageCodes: [
{
display: 'English',
@@ -215,7 +218,7 @@ export const inputWithLanguageAndAuthorityArrayConfig = {
value: [{
value: 'testLanguageAndAuthorityArray',
display: 'testLanguageAndAuthorityArray',
id: 'testLanguageAndAuthorityArray',
authority: 'testLanguageAndAuthorityArray',
}],
submissionId: '1234',
metadataFields: []
@@ -242,7 +245,11 @@ export const inputWithAuthorityValueConfig = {
readOnly: false,
disabled: false,
repeatable: false,
value: Object.assign({}, new AuthorityValue(), { value: 'testWithAuthorityValue', id: 'testWithAuthorityValue', display: 'testWithAuthorityValue' }),
value: Object.assign({}, new VocabularyEntry(), {
value: 'testWithAuthorityValue',
authority: 'testWithAuthorityValue',
display: 'testWithAuthorityValue'
}),
submissionId: '1234',
metadataFields: []
};
@@ -255,7 +262,7 @@ export const inputWithObjectValueConfig = {
readOnly: false,
disabled: false,
repeatable: false,
value: { value: 'testWithObjectValue', id: 'testWithObjectValue', display: 'testWithObjectValue' },
value: { value: 'testWithObjectValue', authority: 'testWithObjectValue', display: 'testWithObjectValue' },
submissionId: '1234',
metadataFields: []
};

View File

@@ -1254,7 +1254,7 @@ export const mockUploadConfigResponse = {
{
metadata: 'dc.title',
label: null,
authority: null,
controlledVocabulary: null,
closed: null
}
],
@@ -1276,7 +1276,7 @@ export const mockUploadConfigResponse = {
{
metadata: 'dc.description',
label: null,
authority: null,
controlledVocabulary: null,
closed: null
}
],

View File

@@ -1,21 +0,0 @@
import {of as observableOf, Observable } from 'rxjs';
import { IntegrationSearchOptions } from '../../core/integration/models/integration-options.model';
import { IntegrationData } from '../../core/integration/integration-data';
import { PageInfo } from '../../core/shared/page-info.model';
import { AuthorityValue } from '../../core/integration/models/authority.value';
export class AuthorityServiceStub {
private _payload = [
Object.assign(new AuthorityValue(),{id: 1, display: 'one', value: 1}),
Object.assign(new AuthorityValue(),{id: 2, display: 'two', value: 2}),
];
setNewPayload(payload) {
this._payload = payload;
}
getEntriesByName(options: IntegrationSearchOptions) {
return observableOf(new IntegrationData(new PageInfo(), this._payload));
}
}

View File

@@ -0,0 +1,29 @@
import { Observable } from 'rxjs';
import { VocabularyFindOptions } from '../../core/submission/vocabularies/models/vocabulary-find-options.model';
import { PageInfo } from '../../core/shared/page-info.model';
import { VocabularyEntry } from '../../core/submission/vocabularies/models/vocabulary-entry.model';
import { PaginatedList } from '../../core/data/paginated-list';
import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils';
import { RemoteData } from '../../core/data/remote-data';
export class VocabularyServiceStub {
private _payload = [
Object.assign(new VocabularyEntry(),{authority: 1, display: 'one', value: 1}),
Object.assign(new VocabularyEntry(),{authority: 2, display: 'two', value: 2}),
];
setNewPayload(payload) {
this._payload = payload;
}
getList() {
return this._payload
}
getVocabularyEntries(options: VocabularyFindOptions): Observable<RemoteData<PaginatedList<VocabularyEntry>>> {
return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), this._payload));
}
}

View File

@@ -27,7 +27,7 @@ import {
mockRowGroupModel
} from '../../../shared/mocks/form-models.mock';
import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model';
import { AuthorityValue } from '../../../core/integration/models/authority.value';
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
describe('SectionFormOperationsService test suite', () => {
let formBuilderService: any;
@@ -365,7 +365,7 @@ describe('SectionFormOperationsService test suite', () => {
event = Object.assign({}, dynamicFormControlChangeEvent, {
model: mockInputWithLanguageAndAuthorityModel
});
expectedValue = Object.assign(new AuthorityValue(), mockInputWithLanguageAndAuthorityModel.value, {language: mockInputWithLanguageAndAuthorityModel.language});
expectedValue = Object.assign(new VocabularyEntry(), mockInputWithLanguageAndAuthorityModel.value, {language: mockInputWithLanguageAndAuthorityModel.language});
expect(service.getFieldValueFromChangeEvent(event)).toEqual(expectedValue);
@@ -373,7 +373,7 @@ describe('SectionFormOperationsService test suite', () => {
model: mockInputWithLanguageAndAuthorityArrayModel
});
expectedValue = [
Object.assign(new AuthorityValue(), mockInputWithLanguageAndAuthorityArrayModel.value[0],
Object.assign(new VocabularyEntry(), mockInputWithLanguageAndAuthorityArrayModel.value[0],
{ language: mockInputWithLanguageAndAuthorityArrayModel.language }
)
];

View File

@@ -15,11 +15,12 @@ import { FormFieldPreviousValueObject } from '../../../shared/form/builder/model
import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder';
import { FormFieldLanguageValueObject } from '../../../shared/form/builder/models/form-field-language-value.model';
import { DsDynamicInputModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-input.model';
import { AuthorityValue } from '../../../core/integration/models/authority.value';
import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vocabulary-entry.model';
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 { DynamicRelationGroupModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
import { VocabularyEntryDetail } from '../../../core/submission/vocabularies/models/vocabulary-entry-detail.model';
/**
* The service handling all form section operations
@@ -221,18 +222,19 @@ export class SectionFormOperationsService {
if ((event.model as DsDynamicInputModel).hasAuthority) {
if (Array.isArray(value)) {
value.forEach((authority, index) => {
authority = Object.assign(new AuthorityValue(), authority, { language });
authority = Object.assign(new VocabularyEntry(), authority, { language });
value[index] = authority;
});
fieldValue = value;
} else {
fieldValue = Object.assign(new AuthorityValue(), value, { language });
fieldValue = Object.assign(new VocabularyEntry(), value, { language });
}
} else {
// Language without Authority (input, textArea)
fieldValue = new FormFieldMetadataValueObject(value, language);
}
} else if (value instanceof FormFieldLanguageValueObject || value instanceof AuthorityValue || isObject(value)) {
} else if (value instanceof FormFieldLanguageValueObject || value instanceof VocabularyEntry
|| value instanceof VocabularyEntryDetail || isObject(value)) {
fieldValue = value;
} else {
fieldValue = new FormFieldMetadataValueObject(value);