diff --git a/src/app/core/data/metadata-value-data.service.ts b/src/app/core/data/metadata-value-data.service.ts index 5dd22956ade..8b412f3482e 100644 --- a/src/app/core/data/metadata-value-data.service.ts +++ b/src/app/core/data/metadata-value-data.service.ts @@ -15,7 +15,7 @@ import { RequestParam } from '../cache/models/request-param.model'; import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; import { MetadataValue } from '../metadata/metadata-value.model'; import { VocabularyEntry } from '../submission/vocabularies/models/vocabulary-entry.model'; -import { isNotEmpty } from '../../shared/empty.util'; +import { isEmpty, isNotEmpty } from '../../shared/empty.util'; import { EMPTY } from 'rxjs'; import { BaseDataService } from './base/base-data.service'; import { dataService } from './base/data-service.decorator'; @@ -59,7 +59,7 @@ export class MetadataValueDataService extends BaseDataService imp * Retrieve the MetadataValue object inside Vocabulary object body */ findByMetadataNameAndByValue(metadataName, term = ''): Observable> { - const metadataFields = metadataName.split('.'); + const metadataFields = metadataName?.split('.'); const schemaRP = new RequestParam('schema', ''); const elementRP = new RequestParam('element', ''); @@ -67,14 +67,14 @@ export class MetadataValueDataService extends BaseDataService imp const termRP = new RequestParam('searchValue', term); // schema and element are mandatory - cannot be empty - if (!isNotEmpty(metadataFields[0]) && !isNotEmpty(metadataFields[1])) { + if (isEmpty(metadataFields?.[0]) && isEmpty(metadataFields?.[1])) { return EMPTY; } // add value to the request params - schemaRP.fieldValue = metadataFields[0]; - elementRP.fieldValue = metadataFields[1]; - qualifierRP.fieldValue = isNotEmpty(metadataFields[2]) ? metadataFields[2] : null; + schemaRP.fieldValue = metadataFields?.[0]; + elementRP.fieldValue = metadataFields?.[1]; + qualifierRP.fieldValue = isNotEmpty(metadataFields?.[2]) ? metadataFields?.[2] : null; const optionParams = Object.assign(new FindListOptions(), {}, { searchParams: [ diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.component.spec.ts index 9d733ae9eeb..9e844a8b17d 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.component.spec.ts @@ -14,11 +14,19 @@ import { createTestComponent } from '../../../../../testing/utils.test'; import { DsDynamicAutocompleteComponent } from './ds-dynamic-autocomplete.component'; import { DsDynamicAutocompleteModel } from './ds-dynamic-autocomplete.model'; import { MetadataValueDataService } from '../../../../../../core/data/metadata-value-data.service'; -import { of as observableOf } from 'rxjs'; +import { of, of as observableOf } from 'rxjs'; import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model'; import { MockMetadataValueService } from '../../../../../testing/metadata-value-data-service.mock'; import { LookupRelationService } from '../../../../../../core/data/lookup-relation.service'; import { MockLookupRelationService } from '../../../../../testing/lookup-relation-service.mock'; +import { getMockRequestService } from '../../../../../mocks/request.service.mock'; +import { HALEndpointServiceStub } from '../../../../../testing/hal-endpoint-service.stub'; +import { getMockRemoteDataBuildService } from '../../../../../mocks/remote-data-build.service.mock'; +import { RequestService } from '../../../../../../core/data/request.service'; +import { HALEndpointService } from '../../../../../../core/shared/hal-endpoint.service'; +import { RemoteDataBuildService } from '../../../../../../core/cache/builders/remote-data-build.service'; +import { ConfigurationDataService } from '../../../../../../core/data/configuration-data.service'; +import {TranslateModule} from '@ngx-translate/core'; let AUT_TEST_GROUP; let AUT_TEST_MODEL_CONFIG; @@ -56,6 +64,12 @@ describe('DsDynamicAutocompleteComponent test suite', () => { const mockMetadataValueService = new MockMetadataValueService(); const vocabularyServiceStub = new VocabularyServiceStub(); const mockLookupRelationService = new MockLookupRelationService(); + const requestService = getMockRequestService(); + const halService = Object.assign(new HALEndpointServiceStub('url')); + const rdbService = getMockRemoteDataBuildService(); + const configurationServiceSpy = jasmine.createSpyObj('configurationService', { + findByPropertyName: of('hdl'), + }); init(); TestBed.configureTestingModule({ imports: [ @@ -64,6 +78,7 @@ describe('DsDynamicAutocompleteComponent test suite', () => { FormsModule, NgbModule, ReactiveFormsModule, + TranslateModule.forRoot(), ], declarations: [ DsDynamicAutocompleteComponent, @@ -76,7 +91,11 @@ describe('DsDynamicAutocompleteComponent test suite', () => { { provide: VocabularyService, useValue: vocabularyServiceStub }, { provide: DynamicFormLayoutService, useValue: mockDynamicFormLayoutService }, { provide: DynamicFormValidationService, useValue: mockDynamicFormValidationService }, - { provide: LookupRelationService, useValue: mockLookupRelationService} + { provide: LookupRelationService, useValue: mockLookupRelationService}, + { provide: RequestService, useValue: requestService }, + { provide: HALEndpointService, useValue: halService }, + { provide: RemoteDataBuildService, useValue: rdbService }, + { provide: ConfigurationDataService, useValue: configurationServiceSpy } ], schemas: [CUSTOM_ELEMENTS_SCHEMA] }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.component.ts index e7afc5ab22e..4a85aaf9905 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.component.ts @@ -1,18 +1,53 @@ import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, TemplateRef, ViewChild } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { DynamicTagModel } from '../tag/dynamic-tag.model'; import { NgbTypeahead, NgbTypeaheadSelectItemEvent } from '@ng-bootstrap/ng-bootstrap'; -import { Observable, of as observableOf } from 'rxjs'; +import { BehaviorSubject, Observable, of as observableOf } from 'rxjs'; import { PageInfo } from '../../../../../../core/shared/page-info.model'; import { VocabularyService } from '../../../../../../core/submission/vocabularies/vocabulary.service'; import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core'; import { catchError, debounceTime, distinctUntilChanged, map, merge, switchMap, tap } from 'rxjs/operators'; -import { buildPaginatedList } from '../../../../../../core/data/paginated-list.model'; -import { isEmpty, isNotEmpty } from '../../../../../empty.util'; +import { buildPaginatedList, PaginatedList } from '../../../../../../core/data/paginated-list.model'; +import { isEmpty, isNotEmpty, isNull } from '../../../../../empty.util'; import { DsDynamicTagComponent } from '../tag/dynamic-tag.component'; import { MetadataValueDataService } from '../../../../../../core/data/metadata-value-data.service'; import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model'; import { LookupRelationService } from '../../../../../../core/data/lookup-relation.service'; +import { + AUTOCOMPLETE_CUSTOM_JSON_PREFIX, + AUTOCOMPLETE_CUSTOM_SOLR_PREFIX, + DsDynamicAutocompleteModel +} from './ds-dynamic-autocomplete.model'; +import { getFirstSucceededRemoteDataPayload } from '../../../../../../core/shared/operators'; +import { GetRequest } from '../../../../../../core/data/request.models'; +import { HttpOptions } from '../../../../../../core/dspace-rest/dspace-rest.service'; +import { HttpParams } from '@angular/common/http'; +import { RequestService } from '../../../../../../core/data/request.service'; +import { RemoteDataBuildService } from '../../../../../../core/cache/builders/remote-data-build.service'; +import { HALEndpointService } from '../../../../../../core/shared/hal-endpoint.service'; +import { RemoteData } from '../../../../../../core/data/remote-data'; +import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model'; +import { ConfigurationDataService } from '../../../../../../core/data/configuration-data.service'; +import { CANONICAL_PREFIX_KEY } from '../../../../../handle.service'; +import { ConfigurationProperty } from '../../../../../../core/shared/configuration-property.model'; +import { DsDynamicAutocompleteService } from './ds-dynamic-autocomplete.service'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Prefix for custom autocomplete definition from the `submission-forms.xml`. + * autocomplete + */ +const AUTOCOMPLETE_CUSTOM_HANDLE_TITLE = 'solr-handle_title_ac'; + +/** + * Prefix for custom autocomplete definition from the `submission-forms.xml`. + * autocomplete + */ +const AUTOCOMPLETE_CUSTOM_LANGUAGE_JSON = 'json_static-iso_langs.json'; + +/** + * The suggestion has a `:` in the result value as a separator. + */ +const AUTOCOMPLETE_CUSTOM_VALUE_SEPARATOR = ':'; /** * Component representing a autocomplete input field. @@ -26,7 +61,7 @@ export class DsDynamicAutocompleteComponent extends DsDynamicTagComponent implem @Input() bindId = true; @Input() group: FormGroup; - @Input() model: DynamicTagModel; + @Input() model: DsDynamicAutocompleteModel; @Output() blur: EventEmitter = new EventEmitter(); @Output() change: EventEmitter = new EventEmitter(); @@ -35,19 +70,28 @@ export class DsDynamicAutocompleteComponent extends DsDynamicTagComponent implem @ViewChild('instance') instance: NgbTypeahead; hasAuthority: boolean; - isSponsorInputType = false; searching = false; searchFailed = false; currentValue: any; public pageInfo: PageInfo; + /** + * Handle canonical prefix loaded from the cfg `handle.canonical.prefix`. + */ + handlePrefix: BehaviorSubject = new BehaviorSubject(null); + constructor(protected vocabularyService: VocabularyService, protected cdr: ChangeDetectorRef, protected layoutService: DynamicFormLayoutService, protected validationService: DynamicFormValidationService, protected metadataValueService: MetadataValueDataService, - protected lookupRelationService: LookupRelationService + protected lookupRelationService: LookupRelationService, + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected halService: HALEndpointService, + protected configurationService: ConfigurationDataService, + protected translateService: TranslateService ) { super(vocabularyService, cdr, layoutService, validationService); } @@ -62,6 +106,17 @@ export class DsDynamicAutocompleteComponent extends DsDynamicTagComponent implem } this.setCurrentValue(this.model.value, true); } + + // Load handle prefix if autocomplete custom is `solr-handle_title_ac` and it is not loaded yet + if (this.model?.autocompleteCustom === AUTOCOMPLETE_CUSTOM_HANDLE_TITLE && isNull(this.handlePrefix.value)) { + // Load configuration property for handle prefix + this.configurationService.findByPropertyName(CANONICAL_PREFIX_KEY) + .pipe(getFirstSucceededRemoteDataPayload()) + .subscribe((handlePrefixCfgProp: ConfigurationProperty) => { + const handlePrefix = handlePrefixCfgProp?.values?.[0]; + this.handlePrefix.next(handlePrefix); + }); + } } /** @@ -87,6 +142,12 @@ export class DsDynamicAutocompleteComponent extends DsDynamicTagComponent implem * @param updateValue raw suggestion. */ updateModel(updateValue) { + if (this.model?.autocompleteCustom === AUTOCOMPLETE_CUSTOM_HANDLE_TITLE) { + const handle_title = updateValue.display.split(AUTOCOMPLETE_CUSTOM_VALUE_SEPARATOR); + updateValue.display = this.handlePrefix.value + handle_title[0]; + updateValue.value = this.handlePrefix.value + handle_title[0]; + } + this.dispatchUpdate(updateValue.display); } @@ -137,6 +198,10 @@ export class DsDynamicAutocompleteComponent extends DsDynamicTagComponent implem * @param suggestion */ suggestionFormatter = (suggestion: TemplateRef) => { + if (this.model.autocompleteCustom === AUTOCOMPLETE_CUSTOM_LANGUAGE_JSON) { + // Language suggestion has a special format - ISO code and language name + return DsDynamicAutocompleteService.pretifyLanguageSuggestion(suggestion, this.translateService); + } // @ts-ignore return suggestion.display; }; @@ -155,17 +220,30 @@ export class DsDynamicAutocompleteComponent extends DsDynamicTagComponent implem if (term === '' || term.length < this.model.minChars) { return observableOf({ list: [] }); } else { - // metadataValue request - const response = this.metadataValueService.findByMetadataNameAndByValue(this.model?.metadataFields?.pop(), term); - return response.pipe( - tap(() => this.searchFailed = false), - catchError((error) => { - this.searchFailed = true; - return observableOf(buildPaginatedList( - new PageInfo(), - [] - )); - })); + // Custom suggestion request + if (this.model.autocompleteCustom) { + if (this.model.autocompleteCustom.startsWith(AUTOCOMPLETE_CUSTOM_SOLR_PREFIX) || + this.model.autocompleteCustom.startsWith(AUTOCOMPLETE_CUSTOM_JSON_PREFIX)) { + return this.getCustomSuggestions(this.model.autocompleteCustom, term) + .pipe(getFirstSucceededRemoteDataPayload(), + map((list: PaginatedList) => { + return this.formatVocabularyEntryList(list); + }), + tap(() => this.searchFailed = false), + catchError(() => { + return this.onSearchErrorVocabularyEntries(); + })); + } + } else { + // MetadataValue request + const response = this.metadataValueService.findByMetadataNameAndByValue( + this.model?.metadataFields?.[this.model?.metadataFields?.length - 1], term); + return response.pipe( + tap(() => this.searchFailed = false), + catchError(() => { + return this.onSearchErrorVocabularyEntries(); + })); + } } }), map((list: any) => { @@ -173,4 +251,45 @@ export class DsDynamicAutocompleteComponent extends DsDynamicTagComponent implem }), tap(() => this.changeSearchingStatus(false)), merge(this.hideSearchingWhenUnsubscribed)); + + /** + * If this model is defined to fetch suggestions from a custom endpoint and solr index, fetch them. + */ + getCustomSuggestions(autocompleteCustom: string, term: string): Observable> { + const options: HttpOptions = Object.create({}); + options.params = new HttpParams({ fromString: 'autocompleteCustom=' + autocompleteCustom + '&searchValue=' + term }); + + const requestId = this.requestService.generateRequestId(); + const url = this.halService.getRootHref() + '/suggestions'; + const getRequest = new GetRequest(requestId, url, null, options); + this.requestService.send(getRequest); + + return this.rdbService.buildFromRequestUUID(requestId); + } + + /** + * Format the vocabulary entry list from `/suggestions` endpoint, because it is not a standard vocabulary endpoint. + */ + formatVocabularyEntryList(list: PaginatedList): PaginatedList { + const vocabularyEntryList: VocabularyEntry[] = []; + list.page.forEach((rawVocabularyEntry: VocabularyEntry) => { + const voc: VocabularyEntry = new VocabularyEntry(); + voc.display = rawVocabularyEntry.display; + voc.value = rawVocabularyEntry.value; + vocabularyEntryList.push(voc); + }); + list.page = vocabularyEntryList; + return list; + } + + /** + * Return empty list on error when fetching suggestions. + */ + onSearchErrorVocabularyEntries() { + this.searchFailed = true; + return observableOf(buildPaginatedList( + new PageInfo(), + [] + )); + } } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.model.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.model.ts index e63f6fbc588..741adfeef14 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.model.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.model.ts @@ -5,7 +5,9 @@ import { isEmpty } from '../../../../../empty.util'; export const DYNAMIC_FORM_CONTROL_TYPE_AUTOCOMPLETE = 'AUTOCOMPLETE'; export const AUTOCOMPLETE_COMPLEX_PREFIX = 'autocomplete_in_complex_input'; -export const DEFAULT_MIN_CHARS_TO_AUTOCOMPLETE = 3; +export const DEFAULT_MIN_CHARS_TO_AUTOCOMPLETE = 1; +export const AUTOCOMPLETE_CUSTOM_SOLR_PREFIX = 'solr-'; +export const AUTOCOMPLETE_CUSTOM_JSON_PREFIX = 'json_static-'; /** * Configuration for the DsDynamicAutocompleteModel. @@ -13,6 +15,7 @@ export const DEFAULT_MIN_CHARS_TO_AUTOCOMPLETE = 3; export interface DsDynamicAutocompleteModelConfig extends DsDynamicInputModelConfig { minChars?: number; value?: any; + autocompleteCustom?: string; } /** @@ -22,6 +25,7 @@ export class DsDynamicAutocompleteModel extends DsDynamicInputModel { @serializable() minChars: number; @serializable() readonly type: string = DYNAMIC_FORM_CONTROL_TYPE_AUTOCOMPLETE; + @serializable() autocompleteCustom: string; constructor(config: DsDynamicAutocompleteModelConfig, layout?: DynamicFormControlLayout) { @@ -35,5 +39,6 @@ export class DsDynamicAutocompleteModel extends DsDynamicInputModel { this.minChars = config.minChars || DEFAULT_MIN_CHARS_TO_AUTOCOMPLETE; // if value is not defined in the configuration -> value is empty this.value = config.value || []; + this.autocompleteCustom = config.autocompleteCustom; } } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.service.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.service.ts index 16008bc6ce6..2c051ca0ac1 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.service.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/autocomplete/ds-dynamic-autocomplete.service.ts @@ -1,12 +1,13 @@ import { take } from 'rxjs/operators'; import {isEmpty } from '../../../../../empty.util'; +import {TranslateService} from '@ngx-translate/core'; /** * Util methods for the DsAutocompleteComponent. */ export class DsDynamicAutocompleteService { - static pretifySuggestion(fundingProjectCode, fundingName, translateService) { + static prettifySponsorSuggestion(fundingProjectCode, fundingName, translateService) { if (isEmpty(fundingProjectCode) || isEmpty(fundingName)) { throw (new Error('The suggestion returns wrong data!')); } @@ -26,4 +27,14 @@ export class DsDynamicAutocompleteService { return (fundingCode + ': ').bold() + fundingProjectCode + '
' + (projectName + ': ').bold() + fundingName; } + + static pretifyLanguageSuggestion(suggestion, translateService: TranslateService) { + // fetch ISO message + const isoMessage = translateService.instant('autocomplete.suggestion.language.iso'); + // fetch language message + const languageMessage = translateService.instant('autocomplete.suggestion.language.title'); + + return (isoMessage + ': ').bold() + suggestion?.value + '
' + (languageMessage + ': ').bold() + + suggestion?.display; + } } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/sponsor-autocomplete/ds-dynamic-sponsor-autocomplete.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/sponsor-autocomplete/ds-dynamic-sponsor-autocomplete.component.spec.ts index 2d01e12da82..cecb59cc750 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/sponsor-autocomplete/ds-dynamic-sponsor-autocomplete.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/sponsor-autocomplete/ds-dynamic-sponsor-autocomplete.component.spec.ts @@ -22,8 +22,15 @@ import { createTestComponent } from '../../../../../testing/utils.test'; import { TranslateService } from '@ngx-translate/core'; import { getMockTranslateService } from '../../../../../mocks/translate.service.mock'; import { DsDynamicSponsorAutocompleteModel } from './ds-dynamic-sponsor-autocomplete.model'; -import { of as observableOf } from 'rxjs'; +import { of, of as observableOf } from 'rxjs'; import { DsDynamicSponsorAutocompleteComponent } from './ds-dynamic-sponsor-autocomplete.component'; +import { getMockRequestService } from '../../../../../mocks/request.service.mock'; +import { HALEndpointServiceStub } from '../../../../../testing/hal-endpoint-service.stub'; +import { getMockRemoteDataBuildService } from '../../../../../mocks/remote-data-build.service.mock'; +import { RequestService } from '../../../../../../core/data/request.service'; +import { HALEndpointService } from '../../../../../../core/shared/hal-endpoint.service'; +import { RemoteDataBuildService } from '../../../../../../core/cache/builders/remote-data-build.service'; +import { ConfigurationDataService } from '../../../../../../core/data/configuration-data.service'; let AUT_TEST_GROUP; let AUT_TEST_MODEL_CONFIG; @@ -45,7 +52,8 @@ function init() { placeholder: 'Keywords', readOnly: false, required: false, - repeatable: false + repeatable: false, + autocompleteCustom: null }; } @@ -61,6 +69,12 @@ describe('DsDynamicSponsorAutocompleteComponent test suite', () => { const vocabularyServiceStub = new VocabularyServiceStub(); const mockLookupRelationService = new MockLookupRelationService(); const mockTranslateService = getMockTranslateService(); + const requestService = getMockRequestService(); + const halService = Object.assign(new HALEndpointServiceStub('url')); + const rdbService = getMockRemoteDataBuildService(); + const configurationServiceSpy = jasmine.createSpyObj('configurationService', { + findByPropertyName: of('hdl'), + }); init(); TestBed.configureTestingModule({ imports: [ @@ -77,12 +91,16 @@ describe('DsDynamicSponsorAutocompleteComponent test suite', () => { providers: [ ChangeDetectorRef, DsDynamicSponsorAutocompleteComponent, - {provide: MetadataValueDataService, useValue: mockMetadataValueService}, - {provide: VocabularyService, useValue: vocabularyServiceStub}, - {provide: DynamicFormLayoutService, useValue: mockDynamicFormLayoutService}, - {provide: DynamicFormValidationService, useValue: mockDynamicFormValidationService}, - {provide: LookupRelationService, useValue: mockLookupRelationService}, - {provide: TranslateService, useValue: mockTranslateService} + { provide: MetadataValueDataService, useValue: mockMetadataValueService }, + { provide: VocabularyService, useValue: vocabularyServiceStub }, + { provide: DynamicFormLayoutService, useValue: mockDynamicFormLayoutService }, + { provide: DynamicFormValidationService, useValue: mockDynamicFormValidationService }, + { provide: LookupRelationService, useValue: mockLookupRelationService }, + { provide: TranslateService, useValue: mockTranslateService }, + { provide: RequestService, useValue: requestService }, + { provide: HALEndpointService, useValue: halService }, + { provide: RemoteDataBuildService, useValue: rdbService }, + { provide: ConfigurationDataService, useValue: configurationServiceSpy } ], schemas: [CUSTOM_ELEMENTS_SCHEMA] }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/sponsor-autocomplete/ds-dynamic-sponsor-autocomplete.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/sponsor-autocomplete/ds-dynamic-sponsor-autocomplete.component.ts index 3c5b462a69c..93b88283eb8 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/sponsor-autocomplete/ds-dynamic-sponsor-autocomplete.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/sponsor-autocomplete/ds-dynamic-sponsor-autocomplete.component.ts @@ -20,6 +20,10 @@ import { AUTOCOMPLETE_COMPLEX_PREFIX } from '../autocomplete/ds-dynamic-autocomp import { DsDynamicAutocompleteService } from '../autocomplete/ds-dynamic-autocomplete.service'; import { DEFAULT_EU_FUNDING_TYPES } from './ds-dynamic-sponsor-autocomplete.model'; import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model'; +import { RequestService } from '../../../../../../core/data/request.service'; +import { RemoteDataBuildService } from '../../../../../../core/cache/builders/remote-data-build.service'; +import { HALEndpointService } from '../../../../../../core/shared/hal-endpoint.service'; +import { ConfigurationDataService } from '../../../../../../core/data/configuration-data.service'; /** * Component representing a sponsor autocomplete input field in the complex input type. @@ -37,10 +41,14 @@ export class DsDynamicSponsorAutocompleteComponent extends DsDynamicAutocomplete protected validationService: DynamicFormValidationService, protected metadataValueService: MetadataValueDataService, protected lookupRelationService: LookupRelationService, - protected translateService: TranslateService + protected translateService: TranslateService, + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected halService: HALEndpointService, + protected configurationService: ConfigurationDataService ) { super(vocabularyService, cdr, layoutService, validationService, metadataValueService, - lookupRelationService); + lookupRelationService, requestService, rdbService, halService, configurationService, translateService); } /** @@ -77,7 +85,7 @@ export class DsDynamicSponsorAutocompleteComponent extends DsDynamicAutocomplete fundingProjectCode = fundingFields?.[1]; fundingName = fundingFields?.[3]; } - return DsDynamicAutocompleteService.pretifySuggestion(fundingProjectCode, fundingName, this.translateService); + return DsDynamicAutocompleteService.prettifySponsorSuggestion(fundingProjectCode, fundingName, this.translateService); }; /** diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/sponsor-autocomplete/ds-dynamic-sponsor-autocomplete.model.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/sponsor-autocomplete/ds-dynamic-sponsor-autocomplete.model.ts index eee5e6addf3..e36b364e016 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/sponsor-autocomplete/ds-dynamic-sponsor-autocomplete.model.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/sponsor-autocomplete/ds-dynamic-sponsor-autocomplete.model.ts @@ -17,6 +17,7 @@ export const DEFAULT_EU_FUNDING_TYPES = [DEFAULT_EU_DISPLAY_VALUE, DEFAULT_EU_ST export interface DsDynamicSponsorAutocompleteModelConfig extends DsDynamicInputModelConfig { minChars?: number; value?: any; + autocompleteCustom?: string; } /** @@ -27,6 +28,7 @@ export class DsDynamicSponsorAutocompleteModel extends DsDynamicInputModel { @serializable() minChars: number; @serializable() maxLength: number; @serializable() readonly type: string = DYNAMIC_FORM_CONTROL_TYPE_AUTOCOMPLETE; + @serializable() autocompleteCustom: string; constructor(config: DsDynamicSponsorAutocompleteModelConfig, layout?: DynamicFormControlLayout) { @@ -41,5 +43,6 @@ export class DsDynamicSponsorAutocompleteModel extends DsDynamicInputModel { this.maxLength = config.maxLength || DEFAULT_MAX_CHARS_TO_AUTOCOMPLETE; // if value is not defined in the configuration -> value is empty this.value = config.value || []; + this.autocompleteCustom = config.autocompleteCustom; } } diff --git a/src/app/shared/form/builder/models/form-field.model.ts b/src/app/shared/form/builder/models/form-field.model.ts index 698150ae9d1..f33c46af009 100644 --- a/src/app/shared/form/builder/models/form-field.model.ts +++ b/src/app/shared/form/builder/models/form-field.model.ts @@ -134,4 +134,7 @@ export class FormFieldModel { */ @autoserialize complexDefinition: string; + + @autoserialize + autocompleteCustom: string; } diff --git a/src/app/shared/form/builder/parsers/autocomplete-field-parser.ts b/src/app/shared/form/builder/parsers/autocomplete-field-parser.ts index efd4ea7434e..20785b83b9f 100644 --- a/src/app/shared/form/builder/parsers/autocomplete-field-parser.ts +++ b/src/app/shared/form/builder/parsers/autocomplete-field-parser.ts @@ -22,6 +22,10 @@ export class AutocompleteFieldParser extends FieldParser { this.setValues(autocompleteModelConfig, fieldValue); } + if (isNotEmpty(this.configData.autocompleteCustom)) { + autocompleteModelConfig.autocompleteCustom = this.configData.autocompleteCustom; + } + return new DsDynamicAutocompleteModel(autocompleteModelConfig); } diff --git a/src/assets/i18n/cs.json5 b/src/assets/i18n/cs.json5 index b5488c02980..8e6a96dcf64 100644 --- a/src/assets/i18n/cs.json5 +++ b/src/assets/i18n/cs.json5 @@ -3332,6 +3332,10 @@ "autocomplete.suggestion.sponsor.funding-code": "Kód financování", // "autocomplete.suggestion.sponsor.project-name": "Project name", "autocomplete.suggestion.sponsor.project-name": "Název projektu", + // "autocomplete.suggestion.language.iso": "ISO", + "autocomplete.suggestion.language.iso": "Kód", + // "autocomplete.suggestion.language.title": "Language", + "autocomplete.suggestion.language.title": "Jazyk", // "autocomplete.suggestion.sponsor.empty": "N/A", "autocomplete.suggestion.sponsor.empty": "nepoužitelné", // "autocomplete.suggestion.sponsor.eu": "EU", diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index a2591efd09e..26e7b2b44e1 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -3446,6 +3446,10 @@ "autocomplete.suggestion.sponsor.project-name": "Project name", + "autocomplete.suggestion.language.iso": "ISO", + + "autocomplete.suggestion.language.title": "Language", + "autocomplete.suggestion.sponsor.empty": "N/A", "autocomplete.suggestion.sponsor.eu": "EU",