tags field changes

This commit is contained in:
Efstratios Giannopoulos 2024-05-21 18:08:27 +03:00
parent dadef8297c
commit 0a4cef782e
28 changed files with 248 additions and 94 deletions

View File

@ -68,10 +68,14 @@ public enum FieldType implements DatabaseEnum<String> {
}
public static boolean isTextListType(FieldType fieldType){
return fieldType.equals(FieldType.SELECT) || fieldType.equals(FieldType.TAGS) || fieldType.equals(FieldType.INTERNAL_ENTRIES_DMPS) ||
return fieldType.equals(FieldType.SELECT) || fieldType.equals(FieldType.INTERNAL_ENTRIES_DMPS) ||
fieldType.equals(FieldType.INTERNAL_ENTRIES_DESCRIPTIONS);
}
public static boolean isTagType(FieldType fieldType){
return fieldType.equals(FieldType.TAGS);
}
public static boolean isDateType(FieldType fieldType){
return fieldType.equals(FieldType.DATE_PICKER);
}

View File

@ -1,16 +1,15 @@
package org.opencdmp.data;
import jakarta.persistence.*;
import org.opencdmp.commons.enums.DescriptionStatus;
import org.opencdmp.commons.enums.IsActive;
import org.opencdmp.data.converters.enums.DescriptionStatusConverter;
import org.opencdmp.data.converters.enums.IsActiveConverter;
import org.opencdmp.data.tenant.TenantScopedBaseEntity;
import jakarta.persistence.*;
import java.time.Instant;
import java.util.*;
import java.util.UUID;
@Entity
@ -86,7 +85,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
public UUID getId() {
return id;
return this.id;
}
public void setId(UUID id) {
@ -94,7 +93,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
}
public String getLabel() {
return label;
return this.label;
}
public void setLabel(String label) {
@ -102,7 +101,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
}
public String getProperties() {
return properties;
return this.properties;
}
public void setProperties(String properties) {
@ -110,7 +109,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
}
public DescriptionStatus getStatus() {
return status;
return this.status;
}
public void setStatus(DescriptionStatus status) {
@ -118,7 +117,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
}
public String getDescription() {
return description;
return this.description;
}
public void setDescription(String description) {
@ -126,7 +125,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
}
public Instant getCreatedAt() {
return createdAt;
return this.createdAt;
}
public void setCreatedAt(Instant createdAt) {
@ -134,7 +133,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
}
public Instant getUpdatedAt() {
return updatedAt;
return this.updatedAt;
}
public void setUpdatedAt(Instant updatedAt) {
@ -142,7 +141,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
}
public IsActive getIsActive() {
return isActive;
return this.isActive;
}
public void setIsActive(IsActive isActive) {
@ -150,7 +149,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
}
public Instant getFinalizedAt() {
return finalizedAt;
return this.finalizedAt;
}
public void setFinalizedAt(Instant finalizedAt) {
@ -158,7 +157,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
}
public UUID getCreatedById() {
return createdById;
return this.createdById;
}
public void setCreatedById(UUID createdById) {
@ -166,7 +165,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
}
public UUID getDmpDescriptionTemplateId() {
return dmpDescriptionTemplateId;
return this.dmpDescriptionTemplateId;
}
public void setDmpDescriptionTemplateId(UUID dmpDescriptionTemplateId) {
@ -174,7 +173,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
}
public UUID getDmpId() {
return dmpId;
return this.dmpId;
}
public void setDmpId(UUID dmpId) {
@ -182,7 +181,7 @@ public class DescriptionEntity extends TenantScopedBaseEntity {
}
public UUID getDescriptionTemplateId() {
return descriptionTemplateId;
return this.descriptionTemplateId;
}
public void setDescriptionTemplateId(UUID descriptionTemplateId) {

View File

@ -18,7 +18,7 @@ public class Prefilling {
public static final String _tag = "tag";
public String getId() {
return id;
return this.id;
}
public void setId(String id) {
@ -26,7 +26,7 @@ public class Prefilling {
}
public String getLabel() {
return label;
return this.label;
}
public void setLabel(String label) {
@ -34,7 +34,7 @@ public class Prefilling {
}
public Map<String, String> getData() {
return data;
return this.data;
}
public void setData(Map<String, String> data) {
@ -42,7 +42,7 @@ public class Prefilling {
}
public String getKey() {
return key;
return this.key;
}
public void setKey(String key) {
@ -50,7 +50,7 @@ public class Prefilling {
}
public String getTag() {
return tag;
return this.tag;
}
public void setTag(String tag) {

View File

@ -85,7 +85,7 @@ public class FieldCommonModelBuilder extends BaseCommonModelBuilder<FieldModel,
if (data == null || data.isEmpty()) return new ArrayList<>();
FieldType fieldType = this.fieldEntity != null && this.fieldEntity.getData() != null ? this.fieldEntity.getData().getFieldType() : FieldType.FREE_TEXT;
Map<UUID, ReferenceModel> referenceItemsMap = FieldType.isReferenceType(fieldType) ? this.collectReferences(data) : null;
List<CommonModelBuilderItemResponse<FieldModel, FieldEntity>> models = new ArrayList<>();

View File

@ -13,11 +13,14 @@ import org.opencdmp.commons.types.description.FieldEntity;
import org.opencdmp.commons.types.descriptiontemplate.fielddata.LabelAndMultiplicityDataEntity;
import org.opencdmp.commons.types.descriptiontemplate.fielddata.SelectDataEntity;
import org.opencdmp.convention.ConventionService;
import org.opencdmp.model.Tag;
import org.opencdmp.model.builder.BaseBuilder;
import org.opencdmp.model.builder.TagBuilder;
import org.opencdmp.model.builder.reference.ReferenceBuilder;
import org.opencdmp.model.description.Field;
import org.opencdmp.model.reference.Reference;
import org.opencdmp.query.ReferenceQuery;
import org.opencdmp.query.TagQuery;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@ -67,6 +70,9 @@ public class FieldBuilder extends BaseBuilder<Field, FieldEntity> {
FieldSet referenceFields = fields.extractPrefixed(this.asPrefix(Field._references));
Map<UUID, Reference> referenceItemsMap = FieldType.isReferenceType(fieldType) ? this.collectReferences(referenceFields, data) : null;
FieldSet tagFields = fields.extractPrefixed(this.asPrefix(Field._tags));
Map<UUID, Tag> tagsItemsMap = FieldType.isTagType(fieldType) ? this.collectTags(tagFields, data) : null;
List<Field> models = new ArrayList<>();
for (FieldEntity d : data) {
Field m = new Field();
@ -75,7 +81,9 @@ public class FieldBuilder extends BaseBuilder<Field, FieldEntity> {
if (fields.hasField(this.asIndexer(Field._textValue)) && FieldType.isTextType(fieldType)) m.setTextValue(d.getTextValue());
if (fields.hasField(this.asIndexer(Field._textListValue)) && FieldType.isTextListType(fieldType)) {
boolean isMultiSelect = true;
if(this.fieldEntity != null && this.fieldEntity.getData() != null && (this.fieldEntity.getData().getFieldType().equals(FieldType.SELECT) || this.fieldEntity.getData().getFieldType().equals(FieldType.INTERNAL_ENTRIES_DMPS) || this.fieldEntity.getData().getFieldType().equals(FieldType.INTERNAL_ENTRIES_DESCRIPTIONS))){
if(this.fieldEntity != null && this.fieldEntity.getData() != null && (this.fieldEntity.getData().getFieldType().equals(FieldType.SELECT)
|| this.fieldEntity.getData().getFieldType().equals(FieldType.INTERNAL_ENTRIES_DMPS)
|| this.fieldEntity.getData().getFieldType().equals(FieldType.INTERNAL_ENTRIES_DESCRIPTIONS))){
if (this.fieldEntity.getData() instanceof SelectDataEntity) isMultiSelect = ((SelectDataEntity) this.fieldEntity.getData()).getMultipleSelect();
else if (this.fieldEntity.getData() instanceof LabelAndMultiplicityDataEntity) isMultiSelect = ((LabelAndMultiplicityDataEntity) this.fieldEntity.getData()).getMultipleSelect();
@ -94,6 +102,13 @@ public class FieldBuilder extends BaseBuilder<Field, FieldEntity> {
if (referenceItemsMap.containsKey(referenceId)) m.getReferences().add(referenceItemsMap.get(referenceId));
}
}
if (!tagFields.isEmpty() && FieldType.isTagType(fieldType) && tagsItemsMap != null && d.getTextListValue() != null && !d.getTextListValue().isEmpty()) {
m.setTags(new ArrayList<>());
for (UUID tagId : d.getTextListValue().stream().map(UUID::fromString).toList()){
if (tagsItemsMap.containsKey(tagId)) m.getTags().add(tagsItemsMap.get(tagId));
}
}
if (!externalIdentifierFields.isEmpty() && d.getExternalIdentifier() != null && FieldType.isExternalIdentifierType(fieldType)) m.setExternalIdentifier(this.builderFactory.builder(ExternalIdentifierBuilder.class).authorize(this.authorize).build(externalIdentifierFields, d.getExternalIdentifier()));
models.add(m);
@ -122,7 +137,7 @@ public class FieldBuilder extends BaseBuilder<Field, FieldEntity> {
for (FieldEntity field: data) {
if (field.getTextListValue() != null) {
for (String value: field.getTextListValue()) {
if (value != null && !ids.contains(value)) ids.add(UUID.fromString(value));
if (value != null && !ids.contains(UUID.fromString(value))) ids.add(UUID.fromString(value));
}
}
}
@ -140,4 +155,43 @@ public class FieldBuilder extends BaseBuilder<Field, FieldEntity> {
return itemMap;
}
private Map<UUID, Tag> collectTags(FieldSet fields, List<FieldEntity> data) throws MyApplicationException {
if (fields.isEmpty() || data.isEmpty())
return null;
this.logger.debug("checking related - {}", Tag.class.getSimpleName());
Map<UUID, Tag> itemMap;
if (!fields.hasOtherField(this.asIndexer(Tag._id))) {
itemMap = this.asEmpty(
data.stream().map(FieldEntity::getTextListValue).flatMap(List::stream).map(UUID::fromString).distinct().collect(Collectors.toList()),
x -> {
Tag item = new Tag();
item.setId(x);
return item;
},
Tag::getId);
} else {
List<UUID> ids = new ArrayList<>();
for (FieldEntity field: data) {
if (field.getTextListValue() != null) {
for (String value: field.getTextListValue()) {
if (value != null && !ids.contains(UUID.fromString(value))) ids.add(UUID.fromString(value));
}
}
}
FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(Tag._id);
TagQuery q = this.queryFactory.query(TagQuery.class).disableTracking().authorize(this.authorize).ids(ids);
itemMap = this.builderFactory.builder(TagBuilder.class).authorize(this.authorize).asForeignKey(q, clone, Tag::getId);
}
if (!fields.hasField(Tag._id)) {
itemMap.forEach((id, item) -> {
if (item != null)
item.setId(null);
});
}
return itemMap;
}
}

View File

@ -1,6 +1,7 @@
package org.opencdmp.model.description;
import org.opencdmp.model.Tag;
import org.opencdmp.model.reference.Reference;
import java.time.Instant;
@ -23,6 +24,9 @@ public class Field {
private List<Reference> references;
public static final String _references = "references";
private List<Tag> tags;
public static final String _tags = "tags";
private ExternalIdentifier externalIdentifier;
public static final String _externalIdentifier = "externalIdentifier";
@ -66,6 +70,14 @@ public class Field {
this.references = references;
}
public List<Tag> getTags() {
return this.tags;
}
public void setTags(List<Tag> tags) {
this.tags = tags;
}
public ExternalIdentifier getExternalIdentifier() {
return this.externalIdentifier;
}

View File

@ -1,8 +1,8 @@
package org.opencdmp.model.persist;
import org.opencdmp.commons.validation.BaseValidator;
import gr.cite.tools.validation.specification.Specification;
import org.opencdmp.commons.validation.BaseValidator;
import org.opencdmp.convention.ConventionService;
import org.opencdmp.data.TagEntity;
import org.opencdmp.errorcode.ErrorThesaurusProperties;
@ -22,7 +22,7 @@ public class TagPersist {
public final static String _id = "id";
private String label = null;
private String label;
public final static String _label = "label";
@ -31,7 +31,7 @@ public class TagPersist {
public final static String _hash = "hash";
public UUID getId() {
return id;
return this.id;
}
public void setId(UUID id) {
@ -39,7 +39,7 @@ public class TagPersist {
}
public String getLabel() {
return label;
return this.label;
}
public void setLabel(String label) {
@ -47,7 +47,7 @@ public class TagPersist {
}
public String getHash() {
return hash;
return this.hash;
}
public void setHash(String hash) {
@ -55,7 +55,7 @@ public class TagPersist {
}
@Component(TagPersistValidator.ValidatorName)
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public static class TagPersistValidator extends BaseValidator<TagPersist> {
public static final String ValidatorName = "TagPersistValidator";
@ -77,18 +77,18 @@ public class TagPersist {
this.spec()
.iff(() -> this.isValidGuid(item.getId()))
.must(() -> this.isValidHash(item.getHash()))
.failOn(TagPersist._hash).failWith(messageSource.getMessage("Validation_Required", new Object[]{TagPersist._hash}, LocaleContextHolder.getLocale())),
.failOn(TagPersist._hash).failWith(this.messageSource.getMessage("Validation_Required", new Object[]{TagPersist._hash}, LocaleContextHolder.getLocale())),
this.spec()
.iff(() -> !this.isValidGuid(item.getId()))
.must(() -> !this.isValidHash(item.getHash()))
.failOn(TagPersist._hash).failWith(messageSource.getMessage("Validation_OverPosting", new Object[]{}, LocaleContextHolder.getLocale())),
.failOn(TagPersist._hash).failWith(this.messageSource.getMessage("Validation_OverPosting", new Object[]{}, LocaleContextHolder.getLocale())),
this.spec()
.must(() -> !this.isEmpty(item.getLabel()))
.failOn(TagPersist._label).failWith(messageSource.getMessage("Validation_Required", new Object[]{TagPersist._label}, LocaleContextHolder.getLocale())),
.failOn(TagPersist._label).failWith(this.messageSource.getMessage("Validation_Required", new Object[]{TagPersist._label}, LocaleContextHolder.getLocale())),
this.spec()
.iff(() -> !this.isEmpty(item.getLabel()))
.must(() -> this.lessEqualLength(item.getLabel(), TagEntity._labelLength))
.failOn(TagPersist._label).failWith(messageSource.getMessage("Validation_MaxLength", new Object[]{TagPersist._label}, LocaleContextHolder.getLocale()))
.failOn(TagPersist._label).failWith(this.messageSource.getMessage("Validation_MaxLength", new Object[]{TagPersist._label}, LocaleContextHolder.getLocale()))
);
}
}

View File

@ -10,6 +10,7 @@ import org.opencdmp.commons.validation.BaseValidator;
import org.opencdmp.convention.ConventionService;
import org.opencdmp.errorcode.ErrorThesaurusProperties;
import org.opencdmp.model.persist.ReferencePersist;
import org.opencdmp.model.persist.TagPersist;
import org.opencdmp.service.visibility.VisibilityService;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
@ -42,6 +43,9 @@ public class FieldPersist {
private ReferencePersist reference;
public static final String _reference = "reference";
private List<String> tags;
public static final String _tags = "tags";
private ExternalIdentifierPersist externalIdentifier;
public static final String _externalIdentifier = "externalIdentifier";
@ -101,6 +105,14 @@ public class FieldPersist {
this.externalIdentifier = externalIdentifier;
}
public List<String> getTags() {
return this.tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
@Component(PersistValidator.ValidatorName)
public static class PersistValidator extends BaseValidator<FieldPersist> {
@ -153,12 +165,12 @@ public class FieldPersist {
.must(() -> !this.isNull(item.getExternalIdentifier()))
.failOn(FieldPersist._externalIdentifier).failWith(this.messageSource.getMessage("Validation_Required", new Object[]{FieldPersist._externalIdentifier}, LocaleContextHolder.getLocale())),
this.spec()
.iff(()-> FieldType.isTextListType(fieldType) && DescriptionStatus.Finalized.equals(this.status) && isVisible && required && !fieldType.equals(FieldType.TAGS))
.iff(()-> FieldType.isTextListType(fieldType) && DescriptionStatus.Finalized.equals(this.status) && isVisible && required)
.must(() -> !this.isListNullOrEmpty(item.getTextListValue()) || !this.isEmpty(item.getTextValue()))
.failOn(FieldPersist._textListValue).failWith(this.messageSource.getMessage("Validation_Required", new Object[]{FieldPersist._textListValue}, LocaleContextHolder.getLocale())),
this.spec()
.iff(()-> fieldType.equals(FieldType.TAGS) && DescriptionStatus.Finalized.equals(this.status) && isVisible && required)
.must(() -> !this.isListNullOrEmpty(item.getTextListValue()))
.iff(()-> FieldType.isTagType(fieldType) && DescriptionStatus.Finalized.equals(this.status) && isVisible && required)
.must(() -> !this.isListNullOrEmpty(item.getTags()))
.failOn(FieldPersist._textListValue).failWith(this.messageSource.getMessage("Validation_Required", new Object[]{FieldPersist._textListValue}, LocaleContextHolder.getLocale())),
this.spec()
.iff(()-> FieldType.isReferenceType(fieldType) && DescriptionStatus.Finalized.equals(this.status) && isVisible && required)
@ -168,6 +180,11 @@ public class FieldPersist {
.iff(()-> !this.isNull(item.getTextListValue()) && (fieldType.equals(FieldType.INTERNAL_ENTRIES_DMPS) || fieldType.equals(FieldType.INTERNAL_ENTRIES_DESCRIPTIONS)))
.must(() -> item.getTextListValue().stream().allMatch(this::isUUID))
.failOn(FieldPersist._textListValue).failWith(this.messageSource.getMessage("Validation_UnexpectedValue", new Object[]{FieldPersist._textListValue}, LocaleContextHolder.getLocale())),
this.navSpec()
.iff(() -> FieldType.isTagType(fieldType) && !this.isListNullOrEmpty(item.getTags()))
.on(FieldPersist._tags)
.over(item.getTags())
.using((itm) -> this.validatorFactory.validator(TagPersist.TagPersistValidator.class)),
this.navSpec()
.iff(() -> FieldType.isReferenceType(fieldType) && !this.isListNullOrEmpty(item.getReferences()))
.on(FieldPersist._references)

View File

@ -30,7 +30,8 @@ import org.opencdmp.commons.types.descriptionreference.DescriptionReferenceDataE
import org.opencdmp.commons.types.descriptiontemplate.FieldSetEntity;
import org.opencdmp.commons.types.descriptiontemplate.fielddata.ReferenceTypeDataEntity;
import org.opencdmp.commons.types.descriptiontemplate.fielddata.UploadDataEntity;
import org.opencdmp.commons.types.descriptiontemplate.importexport.*;
import org.opencdmp.commons.types.descriptiontemplate.importexport.DescriptionTemplateFieldImportExport;
import org.opencdmp.commons.types.descriptiontemplate.importexport.DescriptionTemplateImportExport;
import org.opencdmp.commons.types.descriptiontemplate.importexport.fielddata.ReferenceTypeDataImportExport;
import org.opencdmp.commons.types.notification.*;
import org.opencdmp.commons.types.reference.DefinitionEntity;
@ -43,10 +44,7 @@ import org.opencdmp.integrationevent.outbox.annotationentityremoval.AnnotationEn
import org.opencdmp.integrationevent.outbox.annotationentitytouch.AnnotationEntityTouchedIntegrationEventHandler;
import org.opencdmp.integrationevent.outbox.notification.NotifyIntegrationEvent;
import org.opencdmp.integrationevent.outbox.notification.NotifyIntegrationEventHandler;
import org.opencdmp.model.DescriptionValidationResult;
import org.opencdmp.model.DmpDescriptionTemplate;
import org.opencdmp.model.StorageFile;
import org.opencdmp.model.UserContactInfo;
import org.opencdmp.model.*;
import org.opencdmp.model.builder.description.DescriptionBuilder;
import org.opencdmp.model.deleter.DescriptionDeleter;
import org.opencdmp.model.deleter.DescriptionReferenceDeleter;
@ -68,6 +66,7 @@ import org.opencdmp.service.filetransformer.FileTransformerService;
import org.opencdmp.service.responseutils.ResponseUtilsService;
import org.opencdmp.service.storage.StorageFileProperties;
import org.opencdmp.service.storage.StorageFileService;
import org.opencdmp.service.tag.TagService;
import org.opencdmp.service.visibility.VisibilityService;
import org.opencdmp.service.visibility.VisibilityServiceImpl;
import org.slf4j.LoggerFactory;
@ -128,6 +127,7 @@ public class DescriptionServiceImpl implements DescriptionService {
private final TenantScope tenantScope;
private final ResponseUtilsService responseUtilsService;
private final DescriptionTemplateService descriptionTemplateService;
private final TagService tagService;
@Autowired
public DescriptionServiceImpl(
@ -142,7 +142,7 @@ public class DescriptionServiceImpl implements DescriptionService {
QueryFactory queryFactory,
JsonHandlingService jsonHandlingService,
UserScope userScope,
XmlHandlingService xmlHandlingService, NotifyIntegrationEventHandler eventHandler, NotificationProperties notificationProperties, FileTransformerService fileTransformerService, ElasticService elasticService, ValidatorFactory validatorFactory, StorageFileProperties storageFileConfig, StorageFileService storageFileService, AuthorizationContentResolver authorizationContentResolver, AnnotationEntityTouchedIntegrationEventHandler annotationEntityTouchedIntegrationEventHandler, AnnotationEntityRemovalIntegrationEventHandler annotationEntityRemovalIntegrationEventHandler, TenantScope tenantScope, ResponseUtilsService responseUtilsService, DescriptionTemplateService descriptionTemplateService) {
XmlHandlingService xmlHandlingService, NotifyIntegrationEventHandler eventHandler, NotificationProperties notificationProperties, FileTransformerService fileTransformerService, ElasticService elasticService, ValidatorFactory validatorFactory, StorageFileProperties storageFileConfig, StorageFileService storageFileService, AuthorizationContentResolver authorizationContentResolver, AnnotationEntityTouchedIntegrationEventHandler annotationEntityTouchedIntegrationEventHandler, AnnotationEntityRemovalIntegrationEventHandler annotationEntityRemovalIntegrationEventHandler, TenantScope tenantScope, ResponseUtilsService responseUtilsService, DescriptionTemplateService descriptionTemplateService, TagService tagService) {
this.entityManager = entityManager;
this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory;
@ -168,6 +168,7 @@ public class DescriptionServiceImpl implements DescriptionService {
this.tenantScope = tenantScope;
this.responseUtilsService = responseUtilsService;
this.descriptionTemplateService = descriptionTemplateService;
this.tagService = tagService;
}
@Override
@ -574,13 +575,28 @@ public class DescriptionServiceImpl implements DescriptionService {
}
if (fieldType.equals(FieldType.SELECT) && this.conventionService.isListNullOrEmpty(persist.getTextListValue()) && !this.conventionService.isNullOrEmpty(persist.getTextValue())){
data.setTextListValue(List.of(persist.getTextValue()));
} else if (fieldType.equals(FieldType.SELECT) || fieldType.equals(FieldType.TAGS)){
} else if (fieldType.equals(FieldType.SELECT)){
data.setTextListValue(persist.getTextListValue());
}
}
else if (FieldType.isReferenceType(fieldType) && fieldEntity != null ) {
} else if (FieldType.isReferenceType(fieldType) && fieldEntity != null ) {
List<UUID> referenceIds = fieldToReferenceMap.getOrDefault(fieldEntity.getId(), null);
if (referenceIds != null) data.setTextListValue(referenceIds.stream().map(UUID::toString).toList());
} else if (FieldType.isTagType(fieldType)) {
if (!this.conventionService.isListNullOrEmpty(persist.getTags())){
List<TagEntity> existingTags = this.queryFactory.query(TagQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).disableTracking().tags(persist.getTags().stream().distinct().toList()).collectAs(new BaseFieldSet().ensure(Tag._id).ensure(Tag._label));
List<String> values = new ArrayList<>();
for (String tag : persist.getTags().stream().distinct().toList()){
TagEntity existingTag = existingTags.stream().filter(x-> x.getLabel().equalsIgnoreCase(tag)).findFirst().orElse(null);
if (existingTag == null) {
TagPersist tagPersist = new TagPersist();
tagPersist.setLabel(tag);
values.add(this.tagService.persist(tagPersist, new BaseFieldSet().ensure(Tag._id)).getId().toString());
} else values.add(existingTag.getId().toString());
}
if (!this.conventionService.isListNullOrEmpty(values)) data.setTextListValue(values);
}
}
else if (FieldType.isDateType(fieldType)) data.setDateValue(persist.getDateValue());
else if (FieldType.isBooleanType(fieldType)) data.setBooleanValue(persist.getBooleanValue());
@ -1032,6 +1048,18 @@ public class DescriptionServiceImpl implements DescriptionService {
}
}
}
else if (FieldType.isTagType(fieldType) && fieldEntity != null ) {
if (!this.conventionService.isListNullOrEmpty(data.getTextListValue()) && !this.conventionService.isListNullOrEmpty(references)){
List<UUID> tagIdsInField = data.getTextListValue().stream().filter(x -> this.conventionService.isValidGuid(UUID.fromString(x))).toList().stream().map(UUID::fromString).collect(Collectors.toList());
if (!this.conventionService.isListNullOrEmpty(tagIdsInField)){
List<TagEntity> tagsInField = this.queryFactory.query(TagQuery.class).isActive(IsActive.Active).ids(tagIdsInField).disableTracking().authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).collect();
if (!this.conventionService.isListNullOrEmpty(tagsInField)){
persist.setTags(tagsInField.stream().map(TagEntity::getLabel).toList());
}
}
}
}
return persist;
}
@ -1107,7 +1135,7 @@ public class DescriptionServiceImpl implements DescriptionService {
descriptionTagQuery.isActive(IsActive.Active);
List<TagEntity> tagsEntities = this.queryFactory.query(TagQuery.class).disableTracking().descriptionTagSubQuery(descriptionTagQuery).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).isActive(IsActive.Active).collect();
if (!this.conventionService.isListNullOrEmpty(tagsEntities)) xml.setTags(tagsEntities.stream().map(x -> x.getLabel()).collect(Collectors.toList()));
if (!this.conventionService.isListNullOrEmpty(tagsEntities)) xml.setTags(tagsEntities.stream().map(TagEntity::getLabel).collect(Collectors.toList()));
DescriptionTemplateEntity descriptionTemplateEntity = this.queryFactory.query(DescriptionTemplateQuery.class).disableTracking().ids(data.getDescriptionTemplateId()).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).isActive(IsActive.Active).first();
if (descriptionTemplateEntity != null) {
@ -1358,7 +1386,7 @@ public class DescriptionServiceImpl implements DescriptionService {
}
}
}
}else {
} else {
persist.setBooleanValue(importXml.getBooleanValue());
persist.setDateValue(importXml.getDateValue());
persist.setTextValue(importXml.getTextValue());

View File

@ -396,12 +396,14 @@ public class DescriptionTemplateServiceImpl implements DescriptionTemplateServic
if (FieldType.UPLOAD.equals(fieldType) && !this.conventionService.isNullOrEmpty(persist.getTextValue())) throw new NotImplementedException("Upload not supported");
if (FieldType.INTERNAL_ENTRIES_DMPS.equals(fieldType) && !this.conventionService.isNullOrEmpty(persist.getTextValue())) throw new NotImplementedException("dmps not supported");
if (FieldType.INTERNAL_ENTRIES_DESCRIPTIONS.equals(fieldType) && !this.conventionService.isNullOrEmpty(persist.getTextValue())) throw new NotImplementedException("descriptions not supported");
if (FieldType.TAGS.equals(fieldType) && !this.conventionService.isNullOrEmpty(persist.getTextValue())) throw new NotImplementedException("tags not supported");
data.setTextValue(persist.getTextValue());
}
else if (FieldType.isReferenceType(fieldType) ) {
throw new NotImplementedException("reference not supported");
}
else if (FieldType.isTagType(fieldType) ) {
throw new NotImplementedException("tags not supported");
}
else if (FieldType.isDateType(fieldType)) data.setDateValue(persist.getDateValue());
else if (FieldType.isBooleanType(fieldType)) data.setBooleanValue(persist.getBooleanValue());
@ -419,13 +421,15 @@ public class DescriptionTemplateServiceImpl implements DescriptionTemplateServic
if (FieldType.UPLOAD.equals(fieldType) && !this.conventionService.isNullOrEmpty(persist.getTextValue())) throw new NotImplementedException("Upload not supported");
if (FieldType.INTERNAL_ENTRIES_DMPS.equals(fieldType) && !this.conventionService.isNullOrEmpty(persist.getTextValue())) throw new NotImplementedException("dmps not supported");
if (FieldType.INTERNAL_ENTRIES_DESCRIPTIONS.equals(fieldType) && !this.conventionService.isNullOrEmpty(persist.getTextValue())) throw new NotImplementedException("descriptions not supported");
if (FieldType.TAGS.equals(fieldType) && !this.conventionService.isNullOrEmpty(persist.getTextValue())) throw new NotImplementedException("tags not supported");
data.setTextValue(persist.getTextValue());
}
else if (FieldType.isReferenceType(fieldType) ) {
throw new NotImplementedException("reference not supported");
}
else if (FieldType.isTagType(fieldType) ) {
throw new NotImplementedException("tags not supported");
}
else if (FieldType.isDateType(fieldType)) data.setDateValue(persist.getDateValue());
else if (FieldType.isBooleanType(fieldType)) data.setBooleanValue(persist.getBooleanValue());
else if (FieldType.isExternalIdentifierType(fieldType)){

View File

@ -32,6 +32,7 @@ import org.opencdmp.commons.types.prefillingsource.PrefillingSourceDefinitionFix
import org.opencdmp.convention.ConventionService;
import org.opencdmp.data.DescriptionTemplateEntity;
import org.opencdmp.data.PrefillingSourceEntity;
import org.opencdmp.data.TagEntity;
import org.opencdmp.data.TenantEntityManager;
import org.opencdmp.errorcode.ErrorThesaurusProperties;
import org.opencdmp.model.DescriptionTag;
@ -57,6 +58,7 @@ import org.opencdmp.model.reference.Definition;
import org.opencdmp.model.reference.Reference;
import org.opencdmp.model.referencetype.ReferenceType;
import org.opencdmp.query.PrefillingSourceQuery;
import org.opencdmp.query.TagQuery;
import org.opencdmp.query.lookup.ReferenceSearchLookup;
import org.opencdmp.service.externalfetcher.ExternalFetcherService;
import org.opencdmp.service.externalfetcher.criteria.ExternalReferenceCriteria;
@ -542,16 +544,33 @@ public class PrefillingSourceServiceImpl implements PrefillingSourceService {
}
case TAGS -> {
String[] valuesParsed = this.tryParseJsonAsObjectString(String[].class, value);
field.setTextListValue(valuesParsed == null ? List.of(value) : Arrays.stream(valuesParsed).toList()); //TODO Tags, Currency is ids
List<String> finalValue = valuesParsed == null ? List.of(value) : Arrays.stream(valuesParsed).toList();
List<TagEntity> existingTags = this.queryFactory.query(TagQuery.class).isActive(IsActive.Active).tags(finalValue).disableTracking().authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).collect();
List<Tag> tags = new ArrayList<>();
for (String like : finalValue) {
Tag tag = new Tag();
tag.setLabel(like);
TagEntity existingTag = existingTags.stream().filter(x-> like.equalsIgnoreCase(x.getLabel())).findFirst().orElse(null);
if (existingTag != null) {
tag.setId(existingTag.getId());
tag.setCreatedAt(existingTag.getCreatedAt());
tag.setIsActive(IsActive.Active);
tag.setUpdatedAt(existingTag.getUpdatedAt());
tag.setHash(this.conventionService.hashValue(existingTag.getUpdatedAt()));
}
tags.add(tag);
}
field.setTags(tags);
}
case REFERENCE_TYPES -> {
String[] valuesParsed = this.tryParseJsonAsObjectString(String[].class, value);
List<String> finalValue = valuesParsed == null ? List.of(value) : Arrays.stream(valuesParsed).toList();
ReferenceTypeDataEntity selectDataEntity = (ReferenceTypeDataEntity) fieldEntity.getData();
if (selectDataEntity == null) throw new MyApplicationException("Can not cast fieldEntity data");
field.setReferences(new ArrayList<>());
for (String like : finalValue){
for (String like : finalValue) {
ReferenceSearchLookup externalReferenceCriteria = new ReferenceSearchLookup();
externalReferenceCriteria.setLike(like);
externalReferenceCriteria.setTypeId(selectDataEntity.getReferenceTypeId());
@ -574,8 +593,8 @@ public class PrefillingSourceServiceImpl implements PrefillingSourceService {
.ensure(Reference._hash)
);
List<Reference> references = this.referenceService.searchReferenceData(externalReferenceCriteria);
for (Reference reference : references){
for (Reference reference : references) {
if (reference.getReference().equals(like) || reference.getLabel().toUpperCase(Locale.ROOT).contains(like.toUpperCase(Locale.ROOT))) {
field.getReferences().add(reference);
DescriptionReference descriptionReference = new DescriptionReference();

View File

@ -55,6 +55,9 @@ public class Field {
}
if (persist.getReferences() != null && !persist.getReferences().isEmpty()){
tempTextListValue = persist.getReferences().stream().filter(x-> x.getId() != null).map(x-> x.getId().toString()).toList();
}
if (persist.getTags() != null && !persist.getTags().isEmpty()){
tempTextListValue = persist.getTags();
}
this.textListValue = tempTextListValue;
}

View File

@ -422,13 +422,15 @@ public class VisibilityServiceImpl implements VisibilityService {
else if (rule.getTextValue() != null &&org.opencdmp.commons.enums.FieldType.isTextListType(fieldType) && field.getTextListValue() != null && !field.getTextListValue().isEmpty()) {
if (FieldType.INTERNAL_ENTRIES_DMPS.equals(fieldType)) throw new NotImplementedException("dmps not supported");
if (FieldType.INTERNAL_ENTRIES_DESCRIPTIONS.equals(fieldType)) throw new NotImplementedException("descriptions not supported");
if (FieldType.TAGS.equals(fieldType)) throw new NotImplementedException("tags not supported");
return new HashSet<>(field.getTextListValue()).contains(rule.getTextValue());
}
else if (org.opencdmp.commons.enums.FieldType.isReferenceType(fieldType)) {
throw new NotImplementedException("Reference rule not supported");
}
else if (org.opencdmp.commons.enums.FieldType.isTagType(fieldType)) {
throw new NotImplementedException("tags not supported");
}
else if (org.opencdmp.commons.enums.FieldType.isDateType(fieldType) && field.getDateValue() != null) return field.getDateValue().equals(rule.getDateValue());
else if (org.opencdmp.commons.enums.FieldType.isBooleanType(fieldType) && field.getBooleanValue() != null) return field.getBooleanValue().equals(rule.getBooleanValue());
else if (org.opencdmp.commons.enums.FieldType.isExternalIdentifierType(fieldType) && field.getExternalIdentifier() != null) {

View File

@ -4,7 +4,7 @@ import { Guid } from "@common/types/guid";
import { DescriptionTemplate } from "../description-template/description-template";
import { Dmp, DmpDescriptionTemplate, PublicDmp } from "../dmp/dmp";
import { Reference, ReferencePersist } from "../reference/reference";
import { Tag } from "../tag/tag";
import { Tag, TagPersist } from "../tag/tag";
import { User } from "../user/user";
import { AppPermission } from "@app/core/common/enum/permission.enum";
@ -45,6 +45,7 @@ export interface DescriptionField {
booleanValue: boolean;
externalIdentifier?: DescriptionExternalIdentifier;
references: Reference[];
tags: Tag[];
}
export interface DescriptionExternalIdentifier {
@ -103,6 +104,7 @@ export interface DescriptionFieldPersist {
references: ReferencePersist[];
reference: ReferencePersist;
externalIdentifier?: DescriptionExternalIdentifierPersist;
tags: string[];
}
export interface DescriptionExternalIdentifierPersist {

View File

@ -4,7 +4,6 @@ import { DescriptionTemplateFieldType } from "../common/enum/description-templat
import { DescriptionTemplateField, DescriptionTemplateLabelAndMultiplicityData, DescriptionTemplateRadioBoxData, DescriptionTemplateReferenceTypeData, DescriptionTemplateSelectData } from "../model/description-template/description-template";
import { DescriptionFieldPersist } from "../model/description/description";
import { Observable, map, of } from "rxjs";
import { TagService } from "../services/tag/tag.service";
import { Guid } from "@common/types/guid";
import { DmpService } from "../services/dmp/dmp.service";
import { DescriptionService } from "../services/description/description.service";
@ -19,7 +18,6 @@ import { TranslateService } from "@ngx-translate/core";
export class FieldValuePipe implements PipeTransform {
constructor(private date: DatePipe,
private tagService: TagService,
private dmpService: DmpService,
private storageFileService: StorageFileService,
private descriptionService: DescriptionService,
@ -70,8 +68,8 @@ export class FieldValuePipe implements PipeTransform {
break;
}
case DescriptionTemplateFieldType.TAGS: {
if (controlValue.textListValue && controlValue.textListValue.length > 0) {
return this.tagService.query(this.tagService.buildAutocompleteLookup(null, null, controlValue.textListValue.map(x => Guid.parse(x)))).pipe(map(x => x.items?.map(y=> y.label).join(',')));
if (controlValue.tags) {
return of(controlValue.tags.join(','));
}
break;
}

View File

@ -74,8 +74,8 @@ export class TagService {
initialItems: (excludedItems: any[], data?: any) => this.query(this.buildAutocompleteLookup(null, excludedItems ? excludedItems : null)).pipe(map(x => x.items)),
filterFn: (searchQuery: string, excludedItems: any[]) => this.query(this.buildAutocompleteLookup(searchQuery, excludedItems)).pipe(map(x => x.items)),
getSelectedItems: (selectedItems: any[]) => this.query(this.buildAutocompleteLookup(null, null, selectedItems)).pipe(map(x => x.items)),
displayFn: (item: Tag) => item.label,
titleFn: (item: Tag) => item.label,
displayFn: (item: Tag) => JSON.stringify(item),
titleFn: (item: Tag) => JSON.stringify(item),
valueAssign: (item: Tag) => item.id,
};

View File

@ -46,7 +46,7 @@ export class DescriptionTemplateEditorRuleComponent implements OnInit {
}
isTextListType(type: DescriptionTemplateFieldType){
return type == DescriptionTemplateFieldType.TAGS || type == DescriptionTemplateFieldType.INTERNAL_ENTRIES_DMPS ||
return type == DescriptionTemplateFieldType.INTERNAL_ENTRIES_DMPS ||
type == DescriptionTemplateFieldType.INTERNAL_ENTRIES_DESCRIPTIONS || type == DescriptionTemplateFieldType.SELECT;
}
@ -62,6 +62,10 @@ export class DescriptionTemplateEditorRuleComponent implements OnInit {
return type == DescriptionTemplateFieldType.REFERENCE_TYPES;
}
isTagType(type: DescriptionTemplateFieldType){
return type == DescriptionTemplateFieldType.TAGS;
}
isExternalIdentifierType(type: DescriptionTemplateFieldType){
return type == DescriptionTemplateFieldType.VALIDATION || type == DescriptionTemplateFieldType.DATASET_IDENTIFIER;;
}

View File

@ -38,7 +38,7 @@
<div class="col-12">
<div class="heading">{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS' | translate}}</div>
<div class="profile-form">
<app-tags-field-component [form]="formGroup.get('tags')"></app-tags-field-component>
<app-tags-field-component label="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS' | translate}}" placeholder="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS-PLACEHOLDER' | translate}}" [form]="formGroup.get('tags')"></app-tags-field-component>
</div>
</div>
</div>

View File

@ -650,7 +650,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
}
registerFormListeners() {
this.formGroup.get('descriptionTemplateId').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(descriptionTemplateId => {
@ -799,4 +799,4 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
}
});
}
}
}

View File

@ -225,7 +225,8 @@ export class DescriptionPropertyDefinitionEditorModel implements DescriptionProp
dateValue: definitionField.defaultValue ? definitionField.defaultValue.dateValue : undefined,
booleanValue: definitionField.defaultValue ? definitionField.defaultValue.booleanValue : undefined,
externalIdentifier: undefined,
references: undefined
references: undefined,
tags: undefined
});
})
fieldSetValue.items = [{
@ -247,7 +248,8 @@ export class DescriptionPropertyDefinitionEditorModel implements DescriptionProp
dateValue: undefined,
booleanValue: undefined,
externalIdentifier: undefined,
references: undefined
references: undefined,
tags: undefined
};
}
}
@ -437,6 +439,7 @@ export class DescriptionFieldEditorModel implements DescriptionFieldPersist {
booleanValue: boolean;
references: ReferencePersist[] = [];
reference: ReferencePersist;
tags: string[] = [];
externalIdentifier?: DescriptionExternalIdentifierEditorModel = new DescriptionExternalIdentifierEditorModel(this.validationErrorModel);
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
@ -451,6 +454,7 @@ export class DescriptionFieldEditorModel implements DescriptionFieldPersist {
this.textListValue = item.textListValue;
this.dateValue = item.dateValue;
this.booleanValue = item.booleanValue;
this.tags = item.tags?.map(x => x.label);
const references = descriptionReferences?.filter(x => x.data?.fieldId == descriptionTemplateField?.id && x.isActive == IsActive.Active).map(x => {
return {
@ -501,6 +505,7 @@ export class DescriptionFieldEditorModel implements DescriptionFieldPersist {
booleanValue: [{ value: this.booleanValue, disabled: disabled }, context.getValidation('booleanValue').validators],
references: [{ value: this.references, disabled: disabled }, context.getValidation('references').validators],
reference: [{ value: this.reference, disabled: disabled }, context.getValidation('reference').validators],
tags: [{ value: this.tags, disabled: disabled }, context.getValidation('tags').validators],
externalIdentifier: this.externalIdentifier.buildForm({
rootPath: `${rootPath}externalIdentifier.`
}),
@ -521,6 +526,7 @@ export class DescriptionFieldEditorModel implements DescriptionFieldPersist {
baseValidationArray.push({ key: 'booleanValue', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}booleanValue`)] });
baseValidationArray.push({ key: 'references', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}references`)] });
baseValidationArray.push({ key: 'reference', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}references`)] });
baseValidationArray.push({ key: 'tags', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}tags`)] });
baseValidationArray.push({ key: 'externalIdentifier', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}externalIdentifier`)] });
baseContext.validation = baseValidationArray;
return baseContext;
@ -748,7 +754,7 @@ export class DescriptionFieldIndicator {
else this.type = "textValue";
break;
case DescriptionTemplateFieldType.TAGS:
this.type = "textListValue";
this.type = "tags";
break;
}
}

View File

@ -75,6 +75,10 @@ export class DescriptionEditorResolver extends BaseEditorResolver {
[nameof<Description>(x => x.properties), nameof<DescriptionPropertyDefinition>(x => x.fieldSets), nameof<DescriptionPropertyDefinitionFieldSet>(x => x.items), nameof<DescriptionPropertyDefinitionFieldSetItem>(x => x.fields), nameof<DescriptionField>(x => x.references), nameof<Reference>(x => x.type), nameof<ReferenceType>(x => x.id)].join('.'),
[nameof<Description>(x => x.properties), nameof<DescriptionPropertyDefinition>(x => x.fieldSets), nameof<DescriptionPropertyDefinitionFieldSet>(x => x.items), nameof<DescriptionPropertyDefinitionFieldSetItem>(x => x.fields), nameof<DescriptionField>(x => x.references), nameof<Reference>(x => x.reference)].join('.'),
[nameof<Description>(x => x.properties), nameof<DescriptionPropertyDefinition>(x => x.fieldSets), nameof<DescriptionPropertyDefinitionFieldSet>(x => x.items), nameof<DescriptionPropertyDefinitionFieldSetItem>(x => x.fields), nameof<DescriptionField>(x => x.references), nameof<Reference>(x => x.isActive)].join('.'),
[nameof<Description>(x => x.properties), nameof<DescriptionPropertyDefinition>(x => x.fieldSets), nameof<DescriptionPropertyDefinitionFieldSet>(x => x.items), nameof<DescriptionPropertyDefinitionFieldSetItem>(x => x.fields), nameof<DescriptionField>(x => x.tags), nameof<Tag>(x => x.id)].join('.'),
[nameof<Description>(x => x.properties), nameof<DescriptionPropertyDefinition>(x => x.fieldSets), nameof<DescriptionPropertyDefinitionFieldSet>(x => x.items), nameof<DescriptionPropertyDefinitionFieldSetItem>(x => x.fields), nameof<DescriptionField>(x => x.tags), nameof<Tag>(x => x.label)].join('.'),
[nameof<Description>(x => x.properties), nameof<DescriptionPropertyDefinition>(x => x.fieldSets), nameof<DescriptionPropertyDefinitionFieldSet>(x => x.items), nameof<DescriptionPropertyDefinitionFieldSetItem>(x => x.fields), nameof<DescriptionField>(x => x.tags), nameof<Tag>(x => x.isActive)].join('.'),
[nameof<Description>(x => x.properties), nameof<DescriptionPropertyDefinition>(x => x.fieldSets), nameof<DescriptionPropertyDefinitionFieldSet>(x => x.items), nameof<DescriptionPropertyDefinitionFieldSetItem>(x => x.fields), nameof<DescriptionField>(x => x.tags), nameof<Tag>(x => x.hash)].join('.'),
[nameof<Description>(x => x.descriptionTags), nameof<DescriptionTag>(x => x.id),].join('.'),
[nameof<Description>(x => x.descriptionTags), nameof<DescriptionTag>(x => x.tag), nameof<Tag>(x => x.label)].join('.'),

View File

@ -164,13 +164,7 @@
</mat-form-field>
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.TAGS" class="col-12">
<div class="row">
<mat-form-field class="col-md-12">
<mat-label>{{ field.data.label }}</mat-label>
<app-multiple-auto-complete [configuration]="tagService.multipleAutocompleteConfiguration" [formControl]="propertiesFormGroup?.get(field.id).get('textListValue')" placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}"></app-multiple-auto-complete>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textListValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<app-tags-field-component [label]="field.data.label" [placeholder]="(field.data.label | translate) + (isRequired? ' *': '')" [form]="propertiesFormGroup?.get(field.id).get('tags')"></app-tags-field-component>
</div>
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.DATASET_IDENTIFIER" class="col-12">

View File

@ -1,12 +1,10 @@
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, SimpleChanges } from '@angular/core';
import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { MatCheckboxChange } from '@angular/material/checkbox';
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from "@angular/material/dialog";
import { DescriptionTemplateFieldType } from '@app/core/common/enum/description-template-field-type';
import { DescriptionTemplateFieldValidationType } from '@app/core/common/enum/description-template-field-validation-type';
import { ValidatorURL } from '@app/core/common/enum/validation-type';
import { DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateLabelAndMultiplicityData, DescriptionTemplateUploadData } from '@app/core/model/description-template/description-template';
import { StorageFile } from '@app/core/model/storage-file/storage-file';
import { DescriptionService } from '@app/core/services/description/description.service';
@ -24,8 +22,7 @@ import { FormValidationErrorsDialogComponent } from '@common/forms/form-validati
import { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { Observable } from 'rxjs';
import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators';
import { distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
@Component({

View File

@ -14,6 +14,7 @@ import { DescriptionFormFieldComponent } from './components/form-field/form-fiel
import { DescriptionFormSectionComponent } from './components/form-section/form-section.component';
import { DescriptionFormComponent } from './description-form.component';
import { DescriptionFormAnnotationService } from './description-form-annotation.service';
import { TagsFieldModule } from '@app/ui/tag/tags-field/tags-field.module';
@NgModule({
@ -25,7 +26,8 @@ import { DescriptionFormAnnotationService } from './description-form-annotation.
NgxDropzoneModule,
FormattingModule,
ReferenceFieldModule,
AnnotationDialogModule
AnnotationDialogModule,
TagsFieldModule
],
declarations: [
DescriptionFormComponent,

View File

@ -19,7 +19,7 @@ export class FormProgressIndicationComponent extends BaseComponent implements On
progressSoFar: number;
total: number;
percent: number;
fieldTypes: string[] = ['dateValue', 'booleanValue', 'externalIdentifier.identifier', 'externalIdentifier.type', 'reference', 'references', 'textListValue', 'textValue'];
fieldTypes: string[] = ['dateValue', 'booleanValue', 'externalIdentifier.identifier', 'externalIdentifier.type', 'reference', 'references' , 'tags', 'textListValue', 'textValue'];
constructor(private visibilityRulesService: VisibilityRulesService) { super(); }

View File

@ -1,5 +1,5 @@
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { UntypedFormArray, UntypedFormGroup } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ReferenceType } from '@app/core/model/reference-type/reference-type';
import { ReferenceService } from '@app/core/services/reference/reference.service';
@ -10,9 +10,7 @@ import { BaseComponent } from '@common/base/base.component';
import { takeUntil } from 'rxjs/operators';
import { ReferenceDialogEditorComponent } from './editor/reference-dialog-editor.component';
import { Reference, ReferencePersist } from '@app/core/model/reference/reference';
import { ReferenceSearchLookup } from '@app/core/query/reference-search.lookup';
import { Guid } from '@common/types/guid';
import { nameof } from 'ts-simple-nameof';
import { Subscription } from 'rxjs';
import { FormService } from '@common/forms/form-service';

View File

@ -1,5 +1,5 @@
<mat-form-field class="w-100">
<mat-label>{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS' | translate}}</mat-label>
<mat-label>{{label}}</mat-label>
<mat-chip-grid #chipGrid [disabled]="form.disabled">
<mat-chip-row *ngFor="let tag of tags" (removed)="remove(tag)">
{{tag}}
@ -8,10 +8,13 @@
</button>
</mat-chip-row>
</mat-chip-grid>
<input placeholder="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS-PLACEHOLDER' | translate}}" #tagInput [formControl]="form" [matChipInputFor]="chipGrid" [matAutocomplete]="auto" [matChipInputSeparatorKeyCodes]="separatorKeysCodes" (matChipInputTokenEnd)="add($event)" [readOnly]="form.disabled"/>
<input placeholder="{{placeholder}}" #tagInput [formControl]="tagsCtrl" [matChipInputFor]="chipGrid" [matAutocomplete]="auto" [matChipInputSeparatorKeyCodes]="separatorKeysCodes" (matChipInputTokenEnd)="add($event)" [readOnly]="form.disabled"/>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
<mat-option *ngFor="let tag of filteredTags | async" [value]="tag">
{{tag}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-error *ngIf="form.hasError('backendError')">{{ form.getError('backendError')?.message}}</mat-error>
<mat-error *ngIf="form.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>

View File

@ -1,6 +1,6 @@
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { Component, ElementRef, Input, OnInit, SimpleChanges, ViewChild } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { FormControl, UntypedFormBuilder, UntypedFormControl } from '@angular/forms';
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { MatChipInputEvent } from '@angular/material/chips';
import { Tag } from '@app/core/model/tag/tag';
@ -18,6 +18,8 @@ import { map, mergeMap, startWith } from 'rxjs/operators';
export class TagsComponent extends BaseComponent implements OnInit {
@Input() form: UntypedFormControl = null;
@Input() label: string;
@Input() placeholder: string;
separatorKeysCodes: number[] = [ENTER, COMMA];
filteredTags: Observable<string[]>;
@ -25,6 +27,8 @@ export class TagsComponent extends BaseComponent implements OnInit {
@ViewChild('tagInput') tagInput: ElementRef<HTMLInputElement>;
tagsCtrl = new FormControl();
constructor(
private tagService: TagService
) {
@ -40,7 +44,7 @@ export class TagsComponent extends BaseComponent implements OnInit {
applyTags(){
this.tags = this.form.value || [];
this.filteredTags = this.form.valueChanges.pipe(
this.filteredTags = this.tagsCtrl.valueChanges.pipe(
startWith(null),
mergeMap((tag: string | null) => (this.tagService.query(this.tagService.buildAutocompleteLookup(tag)))),
map((queryResult: QueryResult<Tag>) => queryResult.items.map(x => x.label)),
@ -65,7 +69,7 @@ export class TagsComponent extends BaseComponent implements OnInit {
remove(tag: string): void {
if(this.form.disabled == true) return;
const index = this.tags.indexOf(tag);
if (index >= 0) {