create list of static external fetcher items

This commit is contained in:
amentis 2024-04-09 16:15:15 +03:00
parent 125b0aa408
commit 02c3ed7563
23 changed files with 507 additions and 208 deletions

View File

@ -6,17 +6,17 @@ import jakarta.xml.bind.annotation.XmlElementWrapper;
import java.util.List;
public class ExternalFetcherStaticOptionSourceConfigurationEntity extends ExternalFetcherBaseSourceConfigurationEntity implements SourceStaticOptionConfiguration<StaticOptionEntity> {
public class ExternalFetcherStaticOptionSourceConfigurationEntity extends ExternalFetcherBaseSourceConfigurationEntity implements SourceStaticOptionConfiguration<StaticEntity> {
List<StaticOptionEntity> options;
List<StaticEntity> items;
public List<StaticOptionEntity> getOptions() {
return options;
public List<StaticEntity> getItems() {
return items;
}
@XmlElementWrapper
@XmlElement(name = "option")
public void setOptions(List<StaticOptionEntity> options) {
this.options = options;
@XmlElement(name = "item")
public void setItems(List<StaticEntity> options) {
this.items = options;
}
}

View File

@ -0,0 +1,22 @@
package eu.eudat.commons.types.externalfetcher;
import eu.eudat.service.externalfetcher.config.entities.Static;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElementWrapper;
import java.util.List;
public class StaticEntity implements Static {
private List<StaticOptionEntity> options;
public List<StaticOptionEntity> getOptions() {
return options;
}
@XmlElementWrapper
@XmlElement(name = "option")
public void setOptions(List<StaticOptionEntity> options) {
this.options = options;
}
}

View File

@ -42,12 +42,12 @@ public class ExternalFetcherStaticOptionSourceConfigurationBuilder extends Exter
@Override
protected ExternalFetcherStaticOptionSourceConfiguration buildChild(FieldSet fields, ExternalFetcherStaticOptionSourceConfigurationEntity d, ExternalFetcherStaticOptionSourceConfiguration m) {
FieldSet optionsFields = fields.extractPrefixed(this.asPrefix(ExternalFetcherStaticOptionSourceConfiguration._options));
FieldSet itemsFields = fields.extractPrefixed(this.asPrefix(ExternalFetcherStaticOptionSourceConfiguration._items));
if(!authorizationService.authorize(Permission.EditReferenceType)) return m;
if (!optionsFields.isEmpty() && d.getOptions() != null) {
m.setOptions(this.builderFactory.builder(StaticOptionBuilder.class).authorize(this.authorize).build(optionsFields, d.getOptions()));
if (!itemsFields.isEmpty() && d.getItems() != null) {
m.setItems(this.builderFactory.builder(StaticBuilder.class).authorize(this.authorize).build(itemsFields, d.getItems()));
}
return m;

View File

@ -0,0 +1,65 @@
package eu.eudat.model.builder.externalfetcher;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.commons.types.externalfetcher.StaticEntity;
import eu.eudat.convention.ConventionService;
import eu.eudat.model.builder.BaseBuilder;
import eu.eudat.model.externalfetcher.Static;
import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyApplicationException;
import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.DataLogEntry;
import gr.cite.tools.logging.LoggerService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class StaticBuilder extends BaseBuilder<Static, StaticEntity> {
private final BuilderFactory builderFactory;
private final QueryFactory queryFactory;
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
@Autowired
public StaticBuilder(
ConventionService conventionService, BuilderFactory builderFactory, QueryFactory queryFactory) {
super(conventionService, new LoggerService(LoggerFactory.getLogger(QueryCaseConfigBuilder.class)));
this.builderFactory = builderFactory;
this.queryFactory = queryFactory;
}
public StaticBuilder authorize(EnumSet<AuthorizationFlags> values) {
this.authorize = values;
return this;
}
@Override
public List<Static> build(FieldSet fields, List<StaticEntity> data) throws MyApplicationException {
this.logger.debug("building for {} items requesting {} fields", Optional.ofNullable(data).map(List::size).orElse(0), Optional.ofNullable(fields).map(FieldSet::getFields).map(Set::size).orElse(0));
this.logger.trace(new DataLogEntry("requested fields", fields));
if (fields == null || data == null || fields.isEmpty())
return new ArrayList<>();
FieldSet optionsFields = fields.extractPrefixed(this.asPrefix(Static._options));
List<Static> models = new ArrayList<>();
for (StaticEntity d : data) {
Static m = new Static();
if (!optionsFields.isEmpty() && d.getOptions() != null) {
m.setOptions(this.builderFactory.builder(StaticOptionBuilder.class).authorize(this.authorize).build(optionsFields, d.getOptions()));
}
models.add(m);
}
this.logger.debug("build {} items", Optional.of(models).map(List::size).orElse(0));
return models;
}
}

View File

@ -44,7 +44,7 @@ public class ReferenceTypeSourceBaseConfigurationCensor extends BaseCensor {
FieldSet referenceTypeDependencyFields = fields.extractPrefixed(this.asIndexerPrefix(ExternalFetcherBaseSourceConfiguration._referenceTypeDependencies));
this.censorFactory.censor(ReferenceTypeCensor.class).censor(referenceTypeDependencyFields, userId);
FieldSet optionsFields = fields.extractPrefixed(this.asIndexerPrefix(ExternalFetcherStaticOptionSourceConfiguration._options));
FieldSet optionsFields = fields.extractPrefixed(this.asIndexerPrefix(ExternalFetcherStaticOptionSourceConfiguration._items));
this.censorFactory.censor(ReferenceTypeStaticOptionCensor.class).censor(optionsFields, userId);
FieldSet authFields = fields.extractPrefixed(this.asIndexerPrefix(ExternalFetcherApiSourceConfiguration._auth));

View File

@ -5,14 +5,14 @@ import java.util.List;
public class ExternalFetcherStaticOptionSourceConfiguration extends ExternalFetcherBaseSourceConfiguration {
public final static String _options = "options";
List<StaticOption> options;
public final static String _items = "items";
List<Static> items;
public List<StaticOption> getOptions() {
return options;
public List<Static> getItems() {
return items;
}
public void setOptions(List<StaticOption> options) {
this.options = options;
public void setItems(List<Static> items) {
this.items = items;
}
}

View File

@ -0,0 +1,18 @@
package eu.eudat.model.externalfetcher;
import java.util.List;
public class Static {
private List<StaticOption> options;
public final static String _options = "options";
public List<StaticOption> getOptions() {
return options;
}
public void setOptions(List<StaticOption> options) {
this.options = options;
}
}

View File

@ -7,22 +7,25 @@ import eu.eudat.errorcode.ErrorThesaurusProperties;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Scope;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
public class ExternalFetcherStaticOptionSourceConfigurationPersist extends ExternalFetcherBaseSourceConfigurationPersist {
List<StaticOptionPersist> options;
List<StaticPersist> items;
public static final String _options = "options";
public static final String _items = "items";
public List<StaticOptionPersist> getOptions() {
return options;
public List<StaticPersist> getItems() {
return items;
}
public void setOptions(List<StaticOptionPersist> options) {
this.options = options;
public void setItems(List<StaticPersist> items) {
this.items = items;
}
@Component(ExternalFetcherStaticOptionSourceConfigurationPersistValidator.ValidatorName)
@ -43,13 +46,16 @@ public class ExternalFetcherStaticOptionSourceConfigurationPersist extends Exter
@Override
protected List<Specification> specifications(ExternalFetcherStaticOptionSourceConfigurationPersist item) {
List<Specification> specifications = getBaseSpecifications(item);
specifications.add(
specifications.addAll(Arrays.asList(
this.spec()
.must(() -> !this.isListNullOrEmpty(item.getItems()))
.failOn(ExternalFetcherStaticOptionSourceConfigurationPersist._items).failWith(messageSource.getMessage("Validation_Required", new Object[]{ExternalFetcherStaticOptionSourceConfigurationPersist._items}, LocaleContextHolder.getLocale())),
this.navSpec()
.iff(() -> !this.isListNullOrEmpty(item.getOptions()))
.on(ExternalFetcherStaticOptionSourceConfigurationPersist._options)
.over(item.getOptions())
.using((itm) -> this.validatorFactory.validator(StaticOptionPersist.ReferenceTypeStaticOptionPersistValidator.class))
);
.iff(() -> !this.isListNullOrEmpty(item.getItems()))
.on(ExternalFetcherStaticOptionSourceConfigurationPersist._items)
.over(item.getItems())
.using((itm) -> this.validatorFactory.validator(StaticPersist.StaticPersistValidator.class))
));
return specifications;
}
}

View File

@ -39,15 +39,15 @@ public class StaticOptionPersist {
this.value = value;
}
@Component(ReferenceTypeStaticOptionPersistValidator.ValidatorName)
@Component(StaticOptionPersistValidator.ValidatorName)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public static class ReferenceTypeStaticOptionPersistValidator extends BaseValidator<StaticOptionPersist> {
public static class StaticOptionPersistValidator extends BaseValidator<StaticOptionPersist> {
public static final String ValidatorName = "ReferenceTypeStaticOptionPersistValidator";
public static final String ValidatorName = "StaticOptionPersistValidator";
private final MessageSource messageSource;
protected ReferenceTypeStaticOptionPersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource) {
protected StaticOptionPersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource) {
super(conventionService, errors);
this.messageSource = messageSource;
}

View File

@ -0,0 +1,65 @@
package eu.eudat.model.persist.externalfetcher;
import eu.eudat.commons.validation.BaseValidator;
import eu.eudat.convention.ConventionService;
import eu.eudat.errorcode.ErrorThesaurusProperties;
import gr.cite.tools.validation.ValidatorFactory;
import gr.cite.tools.validation.specification.Specification;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Scope;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
public class StaticPersist {
private List<StaticOptionPersist> options;
public final static String _options = "options";
public List<StaticOptionPersist> getOptions() {
return options;
}
public void setOptions(List<StaticOptionPersist> options) {
this.options = options;
}
@Component(StaticPersistValidator.ValidatorName)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public static class StaticPersistValidator extends BaseValidator<StaticPersist> {
public static final String ValidatorName = "StaticPersistValidatorValidator";
private final MessageSource messageSource;
private final ValidatorFactory validatorFactory;
protected StaticPersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, ValidatorFactory validatorFactory) {
super(conventionService, errors);
this.messageSource = messageSource;
this.validatorFactory = validatorFactory;
}
@Override
protected Class<StaticPersist> modelClass() {
return StaticPersist.class;
}
@Override
protected List<Specification> specifications(StaticPersist item) {
return Arrays.asList(
this.spec()
.must(() -> !this.isListNullOrEmpty(item.getOptions()))
.failOn(StaticPersist._options).failWith(messageSource.getMessage("Validation_Required", new Object[]{StaticPersist._options}, LocaleContextHolder.getLocale())),
this.navSpec()
.iff(() -> !this.isListNullOrEmpty(item.getOptions()))
.on(StaticPersist._options)
.over(item.getOptions())
.using((itm) -> this.validatorFactory.validator(StaticOptionPersist.StaticOptionPersistValidator.class))
);
}
}
}

View File

@ -99,27 +99,34 @@ public class ExternalFetcherServiceImpl implements ExternalFetcherService {
logger.error(e.getLocalizedMessage(), e);
}
} else if (source.getType() != null && source.getType().equals(ExternalFetcherSourceType.STATIC)) {
SourceStaticOptionConfiguration<StaticOption> staticSource = (SourceStaticOptionConfiguration)source;
SourceStaticOptionConfiguration<Static> staticSource = (SourceStaticOptionConfiguration)source;
results.addAll(queryStaticData(staticSource, externalReferenceCriteria));
}
}
return results;
}
private ExternalDataResult queryStaticData(SourceStaticOptionConfiguration<StaticOption> staticSource, ExternalReferenceCriteria externalReferenceCriteria){
private ExternalDataResult queryStaticData(SourceStaticOptionConfiguration<Static> staticSource, ExternalReferenceCriteria externalReferenceCriteria){
ExternalDataResult externalDataResult = new ExternalDataResult();
externalDataResult.setRawData(new ArrayList<>());
externalDataResult.setResults(new ArrayList<>());
for (Static item : staticSource.getItems()){
if (this.conventionService.isListNullOrEmpty(item.getOptions())) continue;
Map<String, String> result = new HashMap<>();
Map<String, Object> rawData = new HashMap<>();
for (StaticOption staticOption : staticSource.getOptions()){
for (Object object: item.getOptions()) {
eu.eudat.model.externalfetcher.StaticOption staticOption = (eu.eudat.model.externalfetcher.StaticOption) object;
if (!this.conventionService.isNullOrEmpty(externalReferenceCriteria.getLike()) && !externalReferenceCriteria.getLike().toUpperCase().contains(staticOption.getValue())) continue;
result.put(staticOption.getCode(), staticOption.getValue());
rawData.put(staticOption.getCode(), staticOption.getValue());
result.put(ReferenceEntity.KnownFields.SourceLabel, staticSource.getLabel());
result.put(ReferenceEntity.KnownFields.Key, staticSource.getKey());
}
ExternalDataResult externalDataResult = new ExternalDataResult();
externalDataResult.setRawData(new ArrayList<>());
externalDataResult.setResults(new ArrayList<>());
externalDataResult.getRawData().add(rawData);
externalDataResult.getResults().add(result);
}
return externalDataResult;
}

View File

@ -2,6 +2,6 @@ package eu.eudat.service.externalfetcher.config.entities;
import java.util.List;
public interface SourceStaticOptionConfiguration <Option extends StaticOption> extends SourceBaseConfiguration {
List<Option> getOptions();
public interface SourceStaticOptionConfiguration <Item extends Static> extends SourceBaseConfiguration {
List<Item> getItems();
}

View File

@ -0,0 +1,8 @@
package eu.eudat.service.externalfetcher.config.entities;
import java.util.List;
public interface Static <Option extends StaticOption>{
List<Option> getOptions();
}

View File

@ -59,6 +59,10 @@ export interface QueryCaseConfig{
}
export interface ExternalFetcherStaticOptionSourceConfiguration{
items: Static[];
}
export interface Static{
options: StaticOption[];
}
@ -127,6 +131,10 @@ export interface QueryCaseConfigPersist{
}
export interface ExternalFetcherStaticOptionSourceConfigurationPersist {
items: StaticPersist[];
}
export interface StaticPersist{
options: StaticOptionPersist[];
}

View File

@ -135,7 +135,7 @@
</button>
</div>
</div>
<app-external-fetcher-source-component [formGroup]="source" [validationErrorModel]="editorModel.validationErrorModel" [validationRootPath]="'definition.sources[' + sourceIndex + '].'" [referenceTypeSourceIndex]="sourceIndex" [referenceTypes]="referenceTypes" [sourceKeysMap]="sourceKeysMap">
<app-external-fetcher-source-component [formGroup]="source" [fieldsForm]="formGroup.get('definition').get('fields')" [validationErrorModel]="editorModel.validationErrorModel" [validationRootPath]="'definition.sources[' + sourceIndex + '].'" [referenceTypeSourceIndex]="sourceIndex" [referenceTypes]="referenceTypes" [sourceKeysMap]="sourceKeysMap">
</app-external-fetcher-source-component>
</div>
</div>

View File

@ -222,14 +222,6 @@ export class ReferenceTypeEditorComponent extends BaseEditor<ReferenceTypeEditor
const sourceFormArray = (this.formGroup.get('definition').get('sources') as FormArray);
if(sourceFormArray){
for (let i = 0; i < sourceFormArray.length; i++) {
const optionsFormArray = (sourceFormArray.at(i).get('options') as FormArray);
for (let j = 0; j < optionsFormArray.length; j++) {
if (fieldCode == optionsFormArray.at(j).get('code').getRawValue()) {
this.removeOption(i, j);
}
}
const fieldMappingFormArray = (sourceFormArray.at(i).get('results').get('fieldsMapping') as FormArray);
for (let j = 0; j < fieldMappingFormArray.length; j++) {
if (fieldCode == fieldMappingFormArray.at(j).get('code').getRawValue()) {
@ -250,7 +242,6 @@ export class ReferenceTypeEditorComponent extends BaseEditor<ReferenceTypeEditor
for (let j = 0; j < sourcesFormArray.length; j++) {
for (let i = 0; i < fieldsFormArray.length; i++) {
this.addFieldMapping(j, fieldsFormArray.at(i).get('code').value);
this.addOption(j, fieldsFormArray.at(i).get('code').value);
}
}
}
@ -266,15 +257,10 @@ export class ReferenceTypeEditorComponent extends BaseEditor<ReferenceTypeEditor
this.addFieldMapping(sourceIndex, "label");
this.addFieldMapping(sourceIndex, "description");
this.addOption(sourceIndex, "reference_id");
this.addOption(sourceIndex, "label");
this.addOption(sourceIndex, "description");
const fieldsFormArray = (this.formGroup.get('definition').get('fields') as FormArray);
if (fieldsFormArray && fieldsFormArray.length > 0) {
for (let i = 0; i < fieldsFormArray.length; i++) {
this.addFieldMapping(sourceIndex, fieldsFormArray.at(i).get('code').value);
this.addOption(sourceIndex, fieldsFormArray.at(i).get('code').value);
}
}
}
@ -326,37 +312,6 @@ export class ReferenceTypeEditorComponent extends BaseEditor<ReferenceTypeEditor
}
// Options
addOption(sourceIndex: number, code: string): void {
const optionsSize = ((this.formGroup.get('definition').get('sources') as FormArray).at(sourceIndex).get('options') as FormArray).length;
if (optionsSize > 0) {
for (let i = 0; i < optionsSize; i++) {
if (((this.formGroup.get('definition').get('sources') as FormArray).at(sourceIndex).get('options') as FormArray).at(i).get('code').getRawValue() == code) {
return;
}
}
}
((this.formGroup.get('definition').get('sources') as FormArray).at(sourceIndex).get('options') as FormArray).push(this.editorModel.createOptions(sourceIndex, optionsSize));
((this.formGroup.get('definition').get('sources') as FormArray).at(sourceIndex).get('options') as FormArray).at(optionsSize).get('code').patchValue(code);
}
removeOption(sourceIndex: number, optionIndex: number): void {
const formArray = ((this.formGroup.get('definition').get('sources') as FormArray).at(sourceIndex) as FormArray);
(formArray.get('options') as FormArray).removeAt(optionIndex);
ReferenceTypeEditorModel.reApplyDefinitionSourcesValidators(
{
formGroup: this.formGroup,
validationErrorModel: this.editorModel.validationErrorModel
}
);
(this.formGroup.get('definition').get('sources') as FormArray).at(sourceIndex).get('options').markAsDirty();
}
private getReferenceTypes(excludedId?: Guid): void {
let sourceKeys: string[] = [];

View File

@ -74,21 +74,6 @@ export class ReferenceTypeEditorModel extends BaseEditorModel implements Referen
return fieldMapping.buildForm({ rootPath: 'definition.sources[' + sourceIndex + '].results.fieldsMapping[' + index + '].'});
}
createOptions(sourceIndex: number, index: number): UntypedFormGroup {
const fieldMapping: StaticOptionEditorModel = new StaticOptionEditorModel(this.validationErrorModel);
return fieldMapping.buildForm({ rootPath: 'definition.sources[' + sourceIndex + '].options[' + index + '].'});
}
createQuery(sourceIndex: number, index: number): UntypedFormGroup {
const query: QueryConfigEditorModel = new QueryConfigEditorModel(this.validationErrorModel);
return query.buildForm({ rootPath: 'definition.sources[' + sourceIndex + '].queries[' + index + '].'});
}
createCase(sourceIndex: number, queryIndex: number, index: number): UntypedFormGroup {
const queryCase: QueryCaseConfigEditorModel = new QueryCaseConfigEditorModel(this.validationErrorModel);
return queryCase.buildForm({ rootPath: 'definition.sources[' + sourceIndex + '].queries[' + queryIndex + '].cases[' + index + '].'});
}
static reApplyDefinitionFieldsValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthenticationConfiguration, ExternalFetcherBaseSourceConfiguration, QueryCaseConfig, QueryConfig, ResultFieldsMappingConfiguration, ResultsConfiguration, StaticOption } from '@app/core/model/external-fetcher/external-fetcher';
import { AuthenticationConfiguration, ExternalFetcherBaseSourceConfiguration, QueryCaseConfig, QueryConfig, ResultFieldsMappingConfiguration, ResultsConfiguration, Static, StaticOption } from '@app/core/model/external-fetcher/external-fetcher';
import { ReferenceType, ReferenceTypeDefinition, ReferenceTypeField } from '@app/core/model/reference-type/reference-type';
import { ReferenceTypeService } from '@app/core/services/reference-type/reference-type.service';
import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
@ -65,8 +65,8 @@ export class ReferenceTypeEditorResolver extends BaseEditorResolver {
[nameof<ReferenceType>(x => x.definition), nameof<ReferenceTypeDefinition>(x => x.sources), nameof<ExternalFetcherBaseSourceConfiguration>(x => x.queries),nameof<QueryConfig>(x => x.cases),nameof<QueryCaseConfig>(x => x.referenceType),nameof<ReferenceType>(x => x.name)].join('.'),
[nameof<ReferenceType>(x => x.definition), nameof<ReferenceTypeDefinition>(x => x.sources), nameof<ExternalFetcherBaseSourceConfiguration>(x => x.queries),nameof<QueryConfig>(x => x.cases),nameof<QueryCaseConfig>(x => x.referenceTypeSourceKey)].join('.'),
[nameof<ReferenceType>(x => x.definition), nameof<ReferenceTypeDefinition>(x => x.sources), nameof<ExternalFetcherBaseSourceConfiguration>(x => x.options),nameof<StaticOption>(x => x.code)].join('.'),
[nameof<ReferenceType>(x => x.definition), nameof<ReferenceTypeDefinition>(x => x.sources), nameof<ExternalFetcherBaseSourceConfiguration>(x => x.options),nameof<StaticOption>(x => x.value)].join('.'),
[nameof<ReferenceType>(x => x.definition), nameof<ReferenceTypeDefinition>(x => x.sources), nameof<ExternalFetcherBaseSourceConfiguration>(x => x.items),nameof<Static>(x => x.options),nameof<StaticOption>(x => x.code)].join('.'),
[nameof<ReferenceType>(x => x.definition), nameof<ReferenceTypeDefinition>(x => x.sources), nameof<ExternalFetcherBaseSourceConfiguration>(x => x.items),nameof<Static>(x => x.options),nameof<StaticOption>(x => x.value)].join('.'),
nameof<ReferenceType>(x => x.createdAt),
nameof<ReferenceType>(x => x.updatedAt),

View File

@ -1,10 +1,10 @@
import { FormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
import { FormArray, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
import { ValidationErrorModel } from "@common/forms/validation/error-model/validation-error-model";
import { Validation, ValidationContext } from "@common/forms/validation/validation-context";
import { BackendErrorValidator } from "@common/forms/validation/custom-validator";
import { ExternalFetcherApiHTTPMethodType } from "@app/core/common/enum/external-fetcher-api-http-method-type";
import { ExternalFetcherSourceType } from "@app/core/common/enum/external-fetcher-source-type";
import { AuthenticationConfiguration, AuthenticationConfigurationPersist, ExternalFetcherBaseSourceConfiguration, ExternalFetcherBaseSourceConfigurationPersist, QueryCaseConfig, QueryCaseConfigPersist, QueryConfig, QueryConfigPersist, ResultFieldsMappingConfiguration, ResultFieldsMappingConfigurationPersist, ResultsConfiguration, ResultsConfigurationPersist, StaticOption, StaticOptionPersist } from "@app/core/model/external-fetcher/external-fetcher";
import { AuthenticationConfiguration, AuthenticationConfigurationPersist, ExternalFetcherBaseSourceConfiguration, ExternalFetcherBaseSourceConfigurationPersist, QueryCaseConfig, QueryCaseConfigPersist, QueryConfig, QueryConfigPersist, ResultFieldsMappingConfiguration, ResultFieldsMappingConfigurationPersist, ResultsConfiguration, ResultsConfigurationPersist, Static, StaticOption, StaticOptionPersist, StaticPersist } from "@app/core/model/external-fetcher/external-fetcher";
import { Guid } from "@common/types/guid";
export class ExternalFetcherBaseSourceConfigurationEditorModel implements ExternalFetcherBaseSourceConfigurationPersist {
@ -24,7 +24,7 @@ export class ExternalFetcherBaseSourceConfigurationEditorModel implements Extern
auth: AuthenticationConfigurationEditorModel = new AuthenticationConfigurationEditorModel(this.validationErrorModel);
queries?: QueryConfigEditorModel[] = [];
options: StaticOptionEditorModel[] = [];
items: StaticEditorModel[] = [];
referenceTypeDependencyIds: Guid[];
@ -52,13 +52,7 @@ export class ExternalFetcherBaseSourceConfigurationEditorModel implements Extern
if (item.auth) this.auth = new AuthenticationConfigurationEditorModel(this.validationErrorModel).fromModel(item.auth);
if (item.queries) { item.queries.map(x => this.queries.push(new QueryConfigEditorModel(this.validationErrorModel).fromModel(x))); }
if (item.options) {
item.options.map(x => this.options.push(new StaticOptionEditorModel(this.validationErrorModel).fromModel(x)));
} else {
this.options.push(new StaticOptionEditorModel().fromModel({ code: 'reference_id', value: undefined }));
this.options.push(new StaticOptionEditorModel().fromModel({ code: 'label', value: undefined }));
this.options.push(new StaticOptionEditorModel().fromModel({ code: 'description', value: undefined }));
}
if (item.items) item.items.map(x => this.items.push(new StaticEditorModel(this.validationErrorModel).fromModel(x)));
if (item.referenceTypeDependencies) { this.referenceTypeDependencyIds = item.referenceTypeDependencies.map(x => x.id)}
}
@ -104,12 +98,12 @@ export class ExternalFetcherBaseSourceConfigurationEditorModel implements Extern
})
), context.getValidation('queries').validators
),
options: this.formBuilder.array(
(this.options ?? []).map(
items: this.formBuilder.array(
(this.items ?? []).map(
(item, index) => item.buildForm({
rootPath: `${rootPath}options[${index}].`
rootPath: `${rootPath}items[${index}].`
})
), context.getValidation('options').validators
), context.getValidation('items').validators
),
referenceTypeDependencyIds: [{ value: this.referenceTypeDependencyIds, disabled: disabled }, context.getValidation('referenceTypeDependencyIds').validators],
@ -139,7 +133,7 @@ export class ExternalFetcherBaseSourceConfigurationEditorModel implements Extern
baseValidationArray.push({ key: 'results', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}results`)] });
baseValidationArray.push({ key: 'queries', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}queries`)] });
baseValidationArray.push({ key: 'options', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}options`)] });
baseValidationArray.push({ key: 'items', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}items`)] });
baseValidationArray.push({ key: 'referenceTypeDependencyIds', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}referenceTypeDependencyIds`)] });
@ -177,10 +171,10 @@ export class ExternalFetcherBaseSourceConfigurationEditorModel implements Extern
validationErrorModel: validationErrorModel
});
(formGroup.get('options') as FormArray).controls?.forEach(
(control, index) => StaticOptionEditorModel.reapplyStaticOptionsValidators({
(formGroup.get('items') as FormArray).controls?.forEach(
(control, index) => StaticEditorModel.reapplyStaticValidators({
formGroup: control as UntypedFormGroup,
rootPath: `${rootPath}options[${index}].`,
rootPath: `${rootPath}items[${index}].`,
validationErrorModel: validationErrorModel
}
)
@ -619,6 +613,83 @@ export class QueryCaseConfigEditorModel implements QueryCaseConfigPersist {
}
}
export class StaticEditorModel implements StaticPersist {
options: StaticOptionEditorModel[] = [];
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
constructor(
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
) { }
public fromModel(item: Static): StaticEditorModel {
if (item) {
if (item.options) {
item.options.map(x => this.options.push(new StaticOptionEditorModel(this.validationErrorModel).fromModel(x)));
} else {
this.options.push(new StaticOptionEditorModel(this.validationErrorModel).fromModel({ code: 'reference_id', value: undefined }));
this.options.push(new StaticOptionEditorModel(this.validationErrorModel).fromModel({ code: 'label', value: undefined }));
this.options.push(new StaticOptionEditorModel(this.validationErrorModel).fromModel({ code: 'description', value: undefined }));
}
}
return this;
}
buildForm(params?: {
context?: ValidationContext,
disabled?: boolean,
rootPath?: string
}): UntypedFormGroup {
let { context = null, disabled = false, rootPath } = params ?? {}
if (context == null) {
context = StaticEditorModel.createValidationContext({
validationErrorModel: this.validationErrorModel,
rootPath
});
}
return this.formBuilder.group({
options: this.formBuilder.array(
(this.options ?? []).map(
(item, index) => item.buildForm({
rootPath: `${rootPath}options[${index}].`,
disabled: disabled
})
), context.getValidation('options').validators
),
});
}
static createValidationContext(params: {
rootPath?: string,
validationErrorModel: ValidationErrorModel
}): ValidationContext {
const { rootPath = '', validationErrorModel } = params;
const baseContext: ValidationContext = new ValidationContext();
const baseValidationArray: Validation[] = new Array<Validation>();
baseValidationArray.push({ key: 'options', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}options`)] });
baseContext.validation = baseValidationArray;
return baseContext;
}
static reapplyStaticValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
rootPath: string
}): void {
const {formGroup, validationErrorModel, rootPath } = params;
(formGroup.get('options') as FormArray).controls?.forEach(
(control, index) => StaticOptionEditorModel.reapplyStaticOptionsValidators({
formGroup: control as UntypedFormGroup,
rootPath: `${rootPath}options[${index}].`,
validationErrorModel: validationErrorModel
})
);
}
}
export class StaticOptionEditorModel implements StaticOptionPersist {
public code: string;
public value: string;

View File

@ -1,7 +1,7 @@
<div class="row">
<div class="col-3">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.KEY' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.KEY' | translate}}</mat-label>
<input matInput type="text" name="key" [formControl]="formGroup.get('key')" required>
<mat-error *ngIf="formGroup.get('key').hasError('backendError')">{{formGroup.get('key').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('key').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -9,7 +9,7 @@
</div>
<div class="col-3">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.LABEL' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.LABEL' | translate}}</mat-label>
<input matInput type="text" name="label" [formControl]="formGroup.get('label')" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -17,7 +17,7 @@
</div>
<div class="col-3">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.ORDINAL' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.ORDINAL' | translate}}</mat-label>
<input matInput type="number" name="ordinal" [formControl]="formGroup.get('ordinal')" required>
<mat-error *ngIf="formGroup.get('ordinal').hasError('backendError')">{{formGroup.get('ordinal').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('ordinal').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -25,7 +25,7 @@
</div>
<div class="col-3" *ngIf="referenceTypeSourceIndex != null">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.DEPENDENCIES' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.DEPENDENCIES' | translate}}</mat-label>
<mat-select multiple (selectionChange)="setReferenceTypeDependenciesMap($event.value, referenceTypeSourceIndex)" [formControl]="formGroup.get('referenceTypeDependencyIds')">
<mat-option *ngFor="let referenceType of referenceTypes" [value]="referenceType.id">{{referenceType.name}}</mat-option>
</mat-select>
@ -35,7 +35,7 @@
</div>
<div class="col-12" *ngIf="referenceTypeSourceIndex != null">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.SOURCE-TYPE' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.SOURCE-TYPE' | translate}}</mat-label>
<mat-select name="type" [formControl]="formGroup.get('type')" required>
<mat-option *ngFor="let sourceType of externalFetcherSourceTypeEnum" [value]="sourceType">
{{enumUtils.toExternalFetcherSourceTypeString(sourceType)}}
@ -50,7 +50,7 @@
<div class="row">
<div class="col-6">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.URL' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.URL' | translate}}</mat-label>
<input matInput type="text" name="ordinal" [formControl]="formGroup.get('url')">
<mat-error *ngIf="formGroup.get('url').hasError('backendError')">{{formGroup.get('url').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('url').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -58,7 +58,7 @@
</div>
<div class="col-6">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.PAGINATION-PATH' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.PAGINATION-PATH' | translate}}</mat-label>
<input matInput type="text" name="paginationPath" [formControl]="formGroup.get('paginationPath')">
<mat-error *ngIf="formGroup.get('paginationPath').hasError('backendError')">{{formGroup.get('paginationPath').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('paginationPath').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -66,7 +66,7 @@
</div>
<div class="col-3">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.CONTENT-TYPE' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.CONTENT-TYPE' | translate}}</mat-label>
<input matInput type="text" name="contentType" [formControl]="formGroup.get('contentType')">
<mat-error *ngIf="formGroup.get('contentType').hasError('backendError')">{{formGroup.get('contentType').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('contentType').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -74,7 +74,7 @@
</div>
<div class="col-3">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.FIRST-PAGE' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.FIRST-PAGE' | translate}}</mat-label>
<input matInput type="text" name="firstPage" [formControl]="formGroup.get('firstPage')">
<mat-error *ngIf="formGroup.get('firstPage').hasError('backendError')">{{formGroup.get('firstPage').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('firstPage').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -82,7 +82,7 @@
</div>
<div class="col-3">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.HTTP-METHOD' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.HTTP-METHOD' | translate}}</mat-label>
<mat-select name="httpMethod" [formControl]="formGroup.get('httpMethod')">
<mat-option *ngFor="let httpMethod of externalFetcherApiHTTPMethodTypeEnum" [value]="httpMethod">
{{enumUtils.toExternalFetcherApiHTTPMethodTypeString(httpMethod)}}
@ -94,7 +94,7 @@
</div>
<div class="col-3" *ngIf="formGroup.get('httpMethod').value == externalFetcherApiHTTPMethodType.POST">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.REQUEST-BODY' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.REQUEST-BODY' | translate}}</mat-label>
<input matInput type="text" name="requestBody" [formControl]="formGroup.get('requestBody')">
<mat-error *ngIf="formGroup.get('requestBody').hasError('backendError')">{{formGroup.get('requestBody').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('requestBody').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -102,24 +102,24 @@
</div>
<div class="col-3">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.FILTER-TYPE' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.FILTER-TYPE' | translate}}</mat-label>
<input matInput type="text" name="filterType" [formControl]="formGroup.get('filterType')">
<mat-error *ngIf="formGroup.get('filterType').hasError('backendError')">{{formGroup.get('filterType').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('filterType').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<!-- Results info -->
<h3 class="col-12">{{'REFERENCE-TYPE-EDITOR.FIELDS.RESULTS' | translate}}</h3>
<h3 class="col-12">{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.RESULTS' | translate}}</h3>
<div class="col-12">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.RESULTS-PATH' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.RESULTS-PATH' | translate}}</mat-label>
<input matInput type="text" name="resultsArrayPath" [formControl]="formGroup.get('results').get('resultsArrayPath')">
<mat-error *ngIf="formGroup.get('results').get('resultsArrayPath').hasError('backendError')">{{formGroup.get('results').get('resultsArrayPath').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('results').get('resultsArrayPath').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<!-- fields mapping -->
<h3 class="col-12">{{'REFERENCE-TYPE-EDITOR.FIELDS.FIELD-MAPPINGS' | translate}}</h3>
<h3 class="col-12">{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.FIELD-MAPPINGS' | translate}}</h3>
<div class="col-12">
<div *ngFor="let field of formGroup.get('results').get('fieldsMapping').controls; let fieldMappingIndex=index;" class="row mb-3">
<div class="col-12">
@ -129,7 +129,7 @@
</div>
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.CODE' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.CODE' | translate}}</mat-label>
<input matInput type="text" [readonly]="field.get('code').disabled" name="code" [formControl]="field.get('code')" [readOnly]="true">
<mat-error *ngIf="field.get('code').hasError('backendError')">{{field.get('code').getError('backendError').message}}</mat-error>
<mat-error *ngIf="field.get('code').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -137,7 +137,7 @@
</div>
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.RESPONSE-PATH' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.RESPONSE-PATH' | translate}}</mat-label>
<input matInput type="text" name="responsePath" [formControl]="field.get('responsePath')">
<mat-error *ngIf="field.get('responsePath').hasError('backendError')">{{field.get('responsePath').getError('backendError').message}}</mat-error>
<mat-error *ngIf="field.get('responsePath').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -148,14 +148,14 @@
</div>
</div>
<!-- Auth info -->
<h3 class="col-12">{{'REFERENCE-TYPE-EDITOR.FIELDS.AUTHENTICATION' | translate}}
<h3 class="col-12">{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.AUTHENTICATION' | translate}}
<mat-checkbox [formControl]="formGroup.get('auth').get('enabled')"></mat-checkbox>
</h3>
<div class="col-12" *ngIf="formGroup.get('auth').get('enabled').value == true">
<div class="row">
<div class="col-12">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.URL' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.URL' | translate}}</mat-label>
<input matInput type="text" name="authUrl" [formControl]="formGroup.get('auth').get('authUrl')">
<mat-error *ngIf="formGroup.get('auth').get('authUrl').hasError('backendError')">{{formGroup.get('auth').get('authUrl').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('auth').get('authUrl').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -163,7 +163,7 @@
</div>
<div class="col-4">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.HTTP-METHOD' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.HTTP-METHOD' | translate}}</mat-label>
<mat-select name="httpMethod" [formControl]="formGroup.get('auth').get('authMethod')">
<mat-option *ngFor="let httpMethod of externalFetcherApiHTTPMethodTypeEnum" [value]="httpMethod">
{{enumUtils.toExternalFetcherApiHTTPMethodTypeString(httpMethod)}}
@ -175,7 +175,7 @@
</div>
<div class="col-4">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.TOKEN-PATH' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.TOKEN-PATH' | translate}}</mat-label>
<input matInput type="text" name="authTokenPath" [formControl]="formGroup.get('auth').get('authTokenPath')">
<mat-error *ngIf="formGroup.get('auth').get('authTokenPath').hasError('backendError')">{{formGroup.get('auth').get('authTokenPath').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('auth').get('authTokenPath').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -183,7 +183,7 @@
</div>
<div class="col-4">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.TYPE' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.TYPE' | translate}}</mat-label>
<input matInput type="text" name="type" [formControl]="formGroup.get('auth').get('type')">
<mat-error *ngIf="formGroup.get('auth').get('type').hasError('backendError')">{{formGroup.get('auth').get('type').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('auth').get('type').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -191,7 +191,7 @@
</div>
<div class="col-12">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.REQUEST-BODY' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.REQUEST-BODY' | translate}}</mat-label>
<input matInput type="text" name="authRequestBody" [formControl]="formGroup.get('auth').get('authRequestBody')">
<mat-error *ngIf="formGroup.get('auth').get('authRequestBody').hasError('backendError')">{{formGroup.get('auth').get('authRequestBody').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('auth').get('authRequestBody').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -200,18 +200,18 @@
</div>
</div>
<!-- Queries info -->
<h3 class="col-12">{{'REFERENCE-TYPE-EDITOR.FIELDS.QUERIES' | translate}}
<button mat-button type="button" class="action-btn" (click)="addQuery()" [disabled]="formGroup.disabled">{{'REFERENCE-TYPE-EDITOR.ACTIONS.ADD-QUERY' | translate}}</button>
<h3 class="col-12">{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.QUERIES' | translate}}
<button mat-button type="button" class="action-btn" (click)="addQuery()" [disabled]="formGroup.disabled">{{'EXTERNAL-FETCHER-SOURCE-EDITOR.ACTIONS.ADD-QUERY' | translate}}</button>
</h3>
<div class="col-12">
<div *ngFor="let query of formGroup.get('queries').controls; let queryIndex=index;" class="row mb-3">
<div class="col-12">
<div class="row mb-3 d-flex align-items-center">
<div class="col-auto d-flex">
<h4 class="col-12">{{'REFERENCE-TYPE-EDITOR.FIELDS.QUERY' | translate}} {{queryIndex + 1}}</h4>
<h4 class="col-12">{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.QUERY' | translate}} {{queryIndex + 1}}</h4>
</div>
<div class="col-auto d-flex">
<button mat-icon-button class="action-list-icon" matTooltip="{{'REFERENCE-TYPE-EDITOR.ACTIONS.REMOVE-QUERY' | translate}}" (click)="removeQuery(queryIndex)" [disabled]="formGroup.disabled">
<button mat-icon-button class="action-list-icon" matTooltip="{{'EXTERNAL-FETCHER-SOURCE-EDITOR.ACTIONS.REMOVE-QUERY' | translate}}" (click)="removeQuery(queryIndex)" [disabled]="formGroup.disabled">
<mat-icon>delete</mat-icon>
</button>
</div>
@ -219,7 +219,7 @@
<div class="row">
<div class="col-6">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.NAME' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.NAME' | translate}}</mat-label>
<input matInput type="text" name="name" [formControl]="query.get('name')" required>
<mat-error *ngIf="query.get('name').hasError('backendError')">{{query.get('name').getError('backendError').message}}</mat-error>
<mat-error *ngIf="query.get('name').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -227,7 +227,7 @@
</div>
<div class="col-6">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.DEFAULT-VALUE' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.DEFAULT-VALUE' | translate}}</mat-label>
<input matInput type="text" name="defaultValue" [formControl]="query.get('defaultValue')">
<mat-error *ngIf="query.get('defaultValue').hasError('backendError')">{{query.get('defaultValue').getError('backendError').message}}</mat-error>
<mat-error *ngIf="query.get('defaultValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -236,8 +236,8 @@
</div>
<!-- Query Cases -->
<h3 class="col-12">{{'REFERENCE-TYPE-EDITOR.FIELDS.CASES' | translate}}
<button mat-button class="action-btn" type="button" (click)="addCase(queryIndex)" [disabled]="formGroup.disabled">{{'REFERENCE-TYPE-EDITOR.ACTIONS.ADD-CASE' | translate}}</button>
<h3 class="col-12">{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.CASES' | translate}}
<button mat-button class="action-btn" type="button" (click)="addCase(queryIndex)" [disabled]="formGroup.disabled">{{'EXTERNAL-FETCHER-SOURCE-EDITOR.ACTIONS.ADD-CASE' | translate}}</button>
</h3>
<div *ngFor="let case of query.get('cases').controls; let caseIndex=index;" class="row">
<div class="col-12">
@ -249,7 +249,7 @@
<div class="row">
<div class="col-4">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.LIKE-PATTERN' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.LIKE-PATTERN' | translate}}</mat-label>
<input matInput type="text" name="likePattern" [formControl]="case.get('likePattern')">
<mat-error *ngIf="case.get('likePattern').hasError('backendError')">{{case.get('likePattern').getError('backendError').message}}</mat-error>
<mat-error *ngIf="case.get('likePattern').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -257,7 +257,7 @@
</div>
<div class="col-4">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.SEPARATOR' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.SEPARATOR' | translate}}</mat-label>
<input matInput type="text" name="separator" [formControl]="case.get('separator')">
<mat-error *ngIf="case.get('separator').hasError('backendError')">{{case.get('separator').getError('backendError').message}}</mat-error>
<mat-error *ngIf="case.get('separator').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -265,7 +265,7 @@
</div>
<div class="col-4">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.VALUE' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.VALUE' | translate}}</mat-label>
<input matInput type="text" name="value" [formControl]="case.get('value')">
<mat-error *ngIf="case.get('value').hasError('backendError')">{{case.get('value').getError('backendError').message}}</mat-error>
<mat-error *ngIf="case.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -273,7 +273,7 @@
</div>
<div class="col-6" *ngIf="formGroup.get('referenceTypeDependencyIds').value">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.DEPENDENCY' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.DEPENDENCY' | translate}}</mat-label>
<mat-select name="referenceTypeId" [formControl]="case.get('referenceTypeId')">
<mat-option *ngFor="let referenceType of referenceTypeDependenciesMap.get(referenceTypeSourceIndex)" [value]="referenceType.id">
{{referenceType.code}}
@ -285,7 +285,7 @@
</div>
<div class="col-6" *ngIf="case.get('referenceTypeId').value">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.SOURCE-KEY' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.SOURCE-KEY' | translate}}</mat-label>
<mat-select name='referenceTypeSourceKey' [formControl]="case.get('referenceTypeSourceKey')">
<mat-option *ngFor="let sourceKey of sourceKeysMap.get(case.get('referenceTypeId').value)" [value]="sourceKey">
{{sourceKey}}
@ -298,7 +298,7 @@
</div>
</div>
<div class="col-auto d-flex">
<button mat-icon-button class="action-list-icon" matTooltip="{{'REFERENCE-TYPE-EDITOR.ACTIONS.REMOVE-CASE' | translate}}" (click)="removeCase(queryIndex, caseIndex)" [disabled]="formGroup.disabled">
<button mat-icon-button class="action-list-icon" matTooltip="{{'EXTERNAL-FETCHER-SOURCE-EDITOR.ACTIONS.REMOVE-CASE' | translate}}" (click)="removeCase(queryIndex, caseIndex)" [disabled]="formGroup.disabled">
<mat-icon>delete</mat-icon>
</button>
</div>
@ -311,24 +311,40 @@
</div>
</div>
</div>
<!-- Options -->
<!-- Static Items -->
<div class="row" *ngIf="formGroup.get('type').value == externalFetcherSourceType.STATIC">
<h3 class="col-12">{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.STATIC-ITEMS' | translate}}
<button mat-button class="action-btn" type="button" (click)="addStaticItem()" [disabled]="formGroup.disabled">{{'EXTERNAL-FETCHER-SOURCE-EDITOR.ACTIONS.ADD-STATIC-ITEM' | translate}}</button>
</h3>
<div class="col-12">
<h3 class="col-12">{{'REFERENCE-TYPE-EDITOR.FIELDS.OPTIONS' | translate}}</h3>
<div *ngFor="let option of formGroup.get('options').controls; let optionsIndex=index;" class="row mb-3">
<div *ngFor="let staticItem of formGroup.get('items').controls; let staticIndex=index;" class="row mb-3">
<div class="col-12">
<mat-card-header>
<div class="row mb-3 d-flex align-items-center">
<div class="col-auto d-flex">
<h4 class="col-12">{{'REFERENCE-TYPE-EDITOR.FIELDS.OPTION' | translate}} {{optionsIndex + 1}}</h4>
<h4 class="col-12">{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.STATIC-ITEM' | translate}} {{staticIndex + 1}}</h4>
</div>
</div>
<div class="col-auto d-flex">
<button mat-icon-button class="action-list-icon" matTooltip="{{'EXTERNAL-FETCHER-SOURCE-EDITOR.ACTIONS.REMOVE-STATIC-ITEM' | translate}}" (click)="removeStaticItem(staticIndex)" [disabled]="formGroup.disabled">
<mat-icon>delete</mat-icon>
</button>
</div>
</mat-card-header>
<mat-card-content>
<!-- Static Options -->
<div *ngFor="let option of staticItem.get('options').controls; let optionIndex=index;" class="row">
<div class="col-12">
<div class="row mb d-flex align-items-center">
<div class="col-auto d-flex">
<span>{{optionIndex + 1}}</span>
</div>
<div class="col">
<div class="row">
<div class="col-6">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.CODE' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.CODE' | translate}}</mat-label>
<input matInput type="text" [readonly]="option.get('code').disabled" name="code" [formControl]="option.get('code')">
<mat-error *ngIf="option.get('code').hasError('backendError')">{{option.get('code').getError('backendError').message}}</mat-error>
<mat-error *ngIf="option.get('code').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -336,16 +352,23 @@
</div>
<div class="col-6">
<mat-form-field class="w-100">
<mat-label>{{'REFERENCE-TYPE-EDITOR.FIELDS.VALUE' | translate}}</mat-label>
<mat-label>{{'EXTERNAL-FETCHER-SOURCE-EDITOR.FIELDS.VALUE' | translate}}</mat-label>
<input matInput type="text" name="value" [formControl]="option.get('value')">
<mat-error *ngIf="option.get('value').hasError('backendError')">{{option.get('value').getError('backendError').message}}</mat-error>
<mat-error *ngIf="option.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
</div>
</div>
</div>
</div>
</mat-card-content>
</div>
</div>
</div>
<mat-error *ngIf="formGroup.get('items').dirty && formGroup.get('items').hasError('required')">{{'EXTERNAL-FETCHER-SOURCE-EDITOR.STATIC-ITEMS-REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="formGroup.get('items').hasError('backendError')">{{formGroup.get('items').getError('backendError').message}}</mat-error>
</div>
</div>

View File

@ -0,0 +1,18 @@
.action-btn {
border-radius: 30px;
background-color: var(--secondary-color);
border: 1px solid transparent;
padding-left: 2em;
padding-right: 2em;
box-shadow: 0px 3px 6px #1E202029;
transition-property: background-color, color;
transition-duration: 200ms;
transition-delay: 50ms;
transition-timing-function: ease-in-out;
&:disabled{
background-color: #CBCBCB;
color: #FFF;
border: 0px;
}
}

View File

@ -6,7 +6,7 @@ import { ReferenceType } from '@app/core/model/reference-type/reference-type';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { BaseComponent } from '@common/base/base.component';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { ExternalFetcherBaseSourceConfigurationEditorModel, QueryCaseConfigEditorModel, QueryConfigEditorModel, StaticOptionEditorModel } from './external-fetcher-source-editor.model';
import { ExternalFetcherBaseSourceConfigurationEditorModel, QueryCaseConfigEditorModel, QueryConfigEditorModel, StaticEditorModel, StaticOptionEditorModel } from './external-fetcher-source-editor.model';
import { Guid } from '@common/types/guid';
@Component({
@ -17,6 +17,7 @@ import { Guid } from '@common/types/guid';
export class ExternalFetcherSourceComponent extends BaseComponent implements OnInit {
@Input() formGroup: UntypedFormGroup = null;
@Input() fieldsForm: any;
@Input() validationErrorModel: ValidationErrorModel = null;
@Input() validationRootPath: string = null;
@Input() referenceTypeSourceIndex: number = null;
@ -34,6 +35,7 @@ export class ExternalFetcherSourceComponent extends BaseComponent implements OnI
) { super(); }
ngOnInit() {
if (this.referenceTypeSourceIndex != null && (this.formGroup.get('items') as FormArray).length == 0) this.addStaticItem();
}
private reApplyValidators(){
@ -80,26 +82,52 @@ export class ExternalFetcherSourceComponent extends BaseComponent implements OnI
formArray.markAsDirty();
}
// static item
addStaticItem(): void {
const formArray = this.formGroup.get('items') as FormArray;
const staticItem = new StaticEditorModel(this.validationErrorModel);
formArray.push(staticItem.buildForm({rootPath: this.validationRootPath + 'items[' + formArray.length + '].'}));
this.addOption(formArray.length -1 , "reference_id");
this.addOption(formArray.length -1, "label");
this.addOption(formArray.length -1, "description");
const fieldsFormArray = (this.fieldsForm as FormArray);
if (fieldsFormArray && fieldsFormArray.length > 0) {
for (let i = 0; i < fieldsFormArray.length; i++) {
this.addOption(formArray.length - 1, fieldsFormArray.at(i).get('code').value);
}
}
}
removeStaticItem(staticIndex: number): void {
const formArray = this.formGroup.get('items') as FormArray;
formArray.removeAt(staticIndex);
this.reApplyValidators();
formArray.markAsDirty();
}
// Options
addOption(code: string): void {
const optionsSize = (this.formGroup.get('options') as FormArray).length;
addOption(staticIndex: number, code: string): void {
const optionsFormArray = (this.formGroup.get('items') as FormArray).at(staticIndex).get('options') as FormArray;
if (optionsSize > 0) {
for (let i = 0; i < optionsSize; i++) {
if ((this.formGroup.get('options') as FormArray).at(i).get('code').getRawValue() == code) {
if (optionsFormArray && optionsFormArray.length > 0) {
for (let i = 0; i < optionsFormArray.length; i++) {
if (optionsFormArray.at(i).get('code').getRawValue() == code) {
return;
}
}
}
const option = new StaticOptionEditorModel(this.validationErrorModel);
(this.formGroup.get('options') as FormArray).push(option.buildForm());
(this.formGroup.get('options') as FormArray).at(optionsSize).get('code').patchValue(code);
optionsFormArray.push(option.buildForm({rootPath: this.validationRootPath + 'items[' + staticIndex + '].options[' + optionsFormArray.length + '].'}));
optionsFormArray.at(optionsFormArray.length -1 ).get('code').patchValue(code);
}
removeOption(optionIndex: number): void {
const formArray = (this.formGroup.get('options') as FormArray);
removeOption(staticIndex: number, optionIndex: number): void {
const formArray = (this.formGroup.get('items') as FormArray).at(staticIndex).get('options') as FormArray;
formArray.removeAt(optionIndex);
this.reApplyValidators();
formArray.markAsDirty();

View File

@ -1135,10 +1135,34 @@
},
"REFERENCE-TYPE-EDITOR": {
"NEW": "New Reference Type",
"SOURCES-REQUIRED": "Required",
"FIELDS": {
"SOURCE-CONFIGURATION": "Source Configuration",
"FIELDS": "Fields",
"SOURCES": "Sources",
"NAME": "Name",
"CODE": "Code",
"DATA-TYPE": "Data Type",
"KEY": "Key",
"LABEL": "Label",
"DESCRIPTION": "Description"
},
"ACTIONS": {
"SAVE": "Save",
"CANCEL": "Cancel",
"DELETE": "Delete",
"ADD-FIELD": "Add Field",
"REMOVE-FIELD": "Remove Field",
"ADD-SOURCE": "Add Source",
"REMOVE-SOURCE": "Remove Source",
"SUBMIT-FIELDS": "Update Fields"
},
"CONFIRM-DELETE-DIALOG": {}
},
"EXTERNAL-FETCHER-SOURCE-EDITOR": {
"FIELDS": {
"SOURCE-CONFIGURATION": "Source Configuration",
"RESULTS": "Results",
"FIELDS": "Fields",
"SOURCES": "Sources",
"FIELD-MAPPINGS": "Field Mappings",
"AUTHENTICATION": "Authentication",
@ -1146,6 +1170,8 @@
"QUERY": "Query",
"OPTIONS": "Options",
"OPTION": "Option",
"STATIC-ITEMS": "Static Items",
"STATIC-ITEM": "Item",
"NAME": "Name",
"CODE": "Code",
"VALUE": "Value",
@ -1175,20 +1201,14 @@
"SOURCE-KEY": "Source Key"
},
"ACTIONS": {
"SAVE": "Save",
"CANCEL": "Cancel",
"DELETE": "Delete",
"ADD-FIELD": "Add Field",
"REMOVE-FIELD": "Remove Field",
"ADD-SOURCE": "Add Source",
"REMOVE-SOURCE": "Remove Source",
"ADD-QUERY": "Add Query",
"REMOVE-QUERY": "Remove Query",
"ADD-CASE": "Add Case",
"REMOVE-CASE": "Remove Case",
"SUBMIT-FIELDS": "Update Fields"
"ADD-STATIC-ITEM": "Add Item",
"REMOVE-STATIC-ITEM": "Remove Item"
},
"CONFIRM-DELETE-DIALOG": {}
"STATIC-REQUIRED": "Required"
},
"TENANT-EDITOR": {
"NEW": "New Tenant",