#8855 - #8856 - #8901 - #8902 [wip] implementing dmp blueprints

This commit is contained in:
Bernaldo Mihasi 2023-07-25 15:51:29 +03:00
parent 128b47d9c3
commit 09d6528f8f
34 changed files with 3102 additions and 51 deletions

View File

@ -0,0 +1,6 @@
package eu.eudat.data.dao.criteria;
import eu.eudat.data.entities.DMPProfile;
public class DataManagementPlanBlueprintCriteria extends Criteria<DMPProfile> {
}

View File

@ -1,6 +1,7 @@
package eu.eudat.data.dao.entities;
import eu.eudat.data.dao.DatabaseAccessLayer;
import eu.eudat.data.dao.criteria.DataManagementPlanBlueprintCriteria;
import eu.eudat.data.dao.criteria.DataManagementPlanProfileCriteria;
import eu.eudat.data.entities.DMP;
import eu.eudat.data.entities.DMPProfile;
@ -15,4 +16,6 @@ public interface DMPProfileDao extends DatabaseAccessLayer<DMPProfile, UUID> {
QueryableList<DMPProfile> getWithCriteria(DataManagementPlanProfileCriteria criteria);
QueryableList<DMPProfile> getWithCriteriaBlueprint(DataManagementPlanBlueprintCriteria criteria);
}

View File

@ -1,6 +1,7 @@
package eu.eudat.data.dao.entities;
import eu.eudat.data.dao.DatabaseAccess;
import eu.eudat.data.dao.criteria.DataManagementPlanBlueprintCriteria;
import eu.eudat.data.dao.criteria.DataManagementPlanProfileCriteria;
import eu.eudat.data.dao.databaselayer.service.DatabaseService;
import eu.eudat.data.entities.DMPProfile;
@ -65,4 +66,13 @@ public class DMPProfileDaoImpl extends DatabaseAccess<DMPProfile> implements DMP
query.where(((builder, root) -> builder.notEqual(root.get("status"), DMPProfile.Status.DELETED.getValue())));
return query;
}
@Override
public QueryableList<DMPProfile> getWithCriteriaBlueprint(DataManagementPlanBlueprintCriteria criteria){
QueryableList<DMPProfile> query = getDatabaseService().getQueryable(DMPProfile.class);
if (criteria.getLike() != null && !criteria.getLike().isEmpty())
query.where((builder, root) -> builder.like(builder.upper(root.get("label")), "%" + criteria.getLike().toUpperCase() + "%"));
query.where(((builder, root) -> builder.notEqual(root.get("status"), DMPProfile.Status.DELETED.getValue())));
return query;
}
}

View File

@ -0,0 +1,25 @@
package eu.eudat.data.query.items.dmpblueprint;
import eu.eudat.data.dao.criteria.DataManagementPlanBlueprintCriteria;
import eu.eudat.data.entities.DMPProfile;
import eu.eudat.data.query.PaginationService;
import eu.eudat.data.query.definition.TableQuery;
import eu.eudat.queryable.QueryableList;
import java.util.UUID;
public class DataManagementPlanBlueprintTableRequest extends TableQuery<DataManagementPlanBlueprintCriteria, DMPProfile, UUID> {
@Override
public QueryableList<DMPProfile> applyCriteria() {
QueryableList<DMPProfile> query = this.getQuery();
if (this.getCriteria().getLike() != null && !this.getCriteria().getLike().isEmpty())
query.where((builder, root) -> builder.like(root.get("label"), "%" + this.getCriteria().getLike() + "%"));
return query;
}
@Override
public QueryableList<DMPProfile> applyPaging(QueryableList<DMPProfile> items) {
return PaginationService.applyPaging(items, this);
}
}

View File

@ -3,6 +3,7 @@ package eu.eudat.controllers;
import eu.eudat.data.dao.criteria.RequestItem;
import eu.eudat.data.entities.DMPProfile;
import eu.eudat.data.entities.DescriptionTemplate;
import eu.eudat.data.query.items.dmpblueprint.DataManagementPlanBlueprintTableRequest;
import eu.eudat.data.query.items.table.dmpprofile.DataManagementPlanProfileTableRequest;
import eu.eudat.logic.managers.DataManagementProfileManager;
import eu.eudat.logic.security.claims.ClaimedAuthorities;
@ -11,6 +12,7 @@ import eu.eudat.models.data.helpermodels.Tuple;
import eu.eudat.models.data.helpers.common.AutoCompleteLookupItem;
import eu.eudat.models.data.helpers.common.DataTableData;
import eu.eudat.models.data.helpers.responses.ResponseItem;
import eu.eudat.models.data.listingmodels.DataManagementPlanBlueprintListingModel;
import eu.eudat.models.data.listingmodels.DataManagementPlanProfileListingModel;
import eu.eudat.models.data.security.Principal;
import eu.eudat.types.ApiMessageCode;
@ -52,6 +54,14 @@ public class DMPProfileController extends BaseController {
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DMPProfile>().status(ApiMessageCode.SUCCESS_MESSAGE).message("Created"));
}
@Transactional
@RequestMapping(method = RequestMethod.POST, value = {"/blueprint"}, consumes = "application/json", produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<DMPProfile>> createOrUpdateBlueprint(@RequestBody DataManagementPlanBlueprintListingModel dataManagementPlan, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) throws Exception {
this.dataManagementProfileManager.createOrUpdateBlueprint(dataManagementPlan, principal);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DMPProfile>().status(ApiMessageCode.SUCCESS_MESSAGE).message("Created"));
}
@RequestMapping(method = RequestMethod.GET, value = {"/getSingle/{id}"}, produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<DataManagementPlanProfileListingModel>> getSingle(@PathVariable String id, Principal principal) throws IllegalAccessException, InstantiationException {
@ -59,6 +69,13 @@ public class DMPProfileController extends BaseController {
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DataManagementPlanProfileListingModel>().status(ApiMessageCode.NO_MESSAGE).payload(dataManagementPlanProfileListingModel));
}
@RequestMapping(method = RequestMethod.GET, value = {"/getSingleBlueprint/{id}"}, produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<DataManagementPlanBlueprintListingModel>> getSingleBlueprint(@PathVariable String id, Principal principal) throws IllegalAccessException, InstantiationException {
DataManagementPlanBlueprintListingModel dataManagementPlanBlueprintListingModel = this.dataManagementProfileManager.getSingleBlueprint(id, principal);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DataManagementPlanBlueprintListingModel>().status(ApiMessageCode.NO_MESSAGE).payload(dataManagementPlanBlueprintListingModel));
}
@RequestMapping(method = RequestMethod.POST, value = {"/getPaged"}, consumes = "application/json", produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<DataTableData<DataManagementPlanProfileListingModel>>> getPaged(@Valid @RequestBody DataManagementPlanProfileTableRequest dataManagementPlanProfileTableRequest, Principal principal) throws Exception {
@ -66,6 +83,13 @@ public class DMPProfileController extends BaseController {
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DataTableData<DataManagementPlanProfileListingModel>>().status(ApiMessageCode.NO_MESSAGE).payload(dataTable));
}
@RequestMapping(method = RequestMethod.POST, value = {"/getPagedBlueprint"}, consumes = "application/json", produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<DataTableData<DataManagementPlanBlueprintListingModel>>> getPagedBlueprint(@Valid @RequestBody DataManagementPlanBlueprintTableRequest dataManagementPlanBlueprintTableRequest, Principal principal) throws Exception {
DataTableData<DataManagementPlanBlueprintListingModel> dataTable = this.dataManagementProfileManager.getPagedBlueprint(dataManagementPlanBlueprintTableRequest, principal);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DataTableData<DataManagementPlanBlueprintListingModel>>().status(ApiMessageCode.NO_MESSAGE).payload(dataTable));
}
@RequestMapping(method = RequestMethod.GET, value = {"/getXml/{id}"}, produces = "application/json")
public @ResponseBody
ResponseEntity getXml( @RequestHeader("Content-Type") String contentType, @PathVariable String id, Principal principal) throws IllegalAccessException, InstantiationException, IOException {

View File

@ -5,6 +5,7 @@ import com.jayway.jsonpath.JsonPath;
import eu.eudat.data.dao.criteria.RequestItem;
import eu.eudat.data.dao.entities.DMPProfileDao;
import eu.eudat.data.entities.DMPProfile;
import eu.eudat.data.query.items.dmpblueprint.DataManagementPlanBlueprintTableRequest;
import eu.eudat.data.query.items.item.dmpprofile.DataManagementPlanProfileCriteriaRequest;
import eu.eudat.data.query.items.table.dmpprofile.DataManagementPlanProfileTableRequest;
import eu.eudat.logic.services.operations.DatabaseRepository;
@ -17,6 +18,7 @@ import eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition.Field;
import eu.eudat.models.data.helpermodels.Tuple;
import eu.eudat.models.data.helpers.common.AutoCompleteLookupItem;
import eu.eudat.models.data.helpers.common.DataTableData;
import eu.eudat.models.data.listingmodels.DataManagementPlanBlueprintListingModel;
import eu.eudat.models.data.listingmodels.DataManagementPlanProfileListingModel;
import eu.eudat.models.data.security.Principal;
import eu.eudat.queryable.QueryableList;
@ -78,6 +80,20 @@ public class DataManagementProfileManager {
return dataTable;
}
public DataTableData<DataManagementPlanBlueprintListingModel> getPagedBlueprint(DataManagementPlanBlueprintTableRequest dataManagementPlanBlueprintTableRequest, Principal principal) throws Exception {
QueryableList<DMPProfile> items = apiContext.getOperationsContext().getDatabaseRepository().getDmpProfileDao().getWithCriteriaBlueprint(dataManagementPlanBlueprintTableRequest.getCriteria());
QueryableList<DMPProfile> pagedItems = PaginationManager.applyPaging(items, dataManagementPlanBlueprintTableRequest);
DataTableData<DataManagementPlanBlueprintListingModel> dataTable = new DataTableData<>();
CompletableFuture itemsFuture = pagedItems
.selectAsync(item -> new DataManagementPlanBlueprintListingModel().fromDataModel(item)).whenComplete((resultList, throwable) -> dataTable.setData(resultList));
CompletableFuture countFuture = items.countAsync().whenComplete((count, throwable) -> dataTable.setTotalCount(count));
CompletableFuture.allOf(itemsFuture, countFuture).join();
return dataTable;
}
public DataManagementPlanProfileListingModel getSingle(String id, Principal principal) throws InstantiationException, IllegalAccessException {
DMPProfile dmpProfile = databaseRepository.getDmpProfileDao().find(UUID.fromString(id));
DataManagementPlanProfileListingModel dataManagementPlanProfileListingModel = new DataManagementPlanProfileListingModel();
@ -85,6 +101,13 @@ public class DataManagementProfileManager {
return dataManagementPlanProfileListingModel;
}
public DataManagementPlanBlueprintListingModel getSingleBlueprint(String id, Principal principal) throws InstantiationException, IllegalAccessException {
DMPProfile dmpProfile = databaseRepository.getDmpProfileDao().find(UUID.fromString(id));
DataManagementPlanBlueprintListingModel dataManagementPlanBlueprintListingModel = new DataManagementPlanBlueprintListingModel();
dataManagementPlanBlueprintListingModel.fromDataModel(dmpProfile);
return dataManagementPlanBlueprintListingModel;
}
public List<DataManagementPlanProfileListingModel> getWithCriteria(DataManagementPlanProfileCriteriaRequest dataManagementPlanProfileCriteriaRequest) throws IllegalAccessException, InstantiationException {
QueryableList<DMPProfile> items = databaseRepository.getDmpProfileDao().getWithCriteria(dataManagementPlanProfileCriteriaRequest.getCriteria());
List<DataManagementPlanProfileListingModel> datamanagementPlans = items.select(item -> new DataManagementPlanProfileListingModel().fromDataModel(item));
@ -96,6 +119,11 @@ public class DataManagementProfileManager {
apiContext.getOperationsContext().getDatabaseRepository().getDmpProfileDao().createOrUpdate(dmpProfile);
}
public void createOrUpdateBlueprint(DataManagementPlanBlueprintListingModel dataManagementPlanBlueprintListingModel, Principal principal) throws Exception {
DMPProfile dmpProfile = dataManagementPlanBlueprintListingModel.toDataModel();
apiContext.getOperationsContext().getDatabaseRepository().getDmpProfileDao().createOrUpdate(dmpProfile);
}
public ResponseEntity<byte[]> getDocument(DataManagementPlanProfileListingModel dmpProfile, String label) throws IllegalAccessException, IOException, InstantiationException {
FileEnvelope envelope = getXmlDocument(dmpProfile, label);
InputStream resource = new FileInputStream(envelope.getFile());

View File

@ -0,0 +1,50 @@
package eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition;
import eu.eudat.logic.utilities.builders.XmlBuilder;
import eu.eudat.logic.utilities.interfaces.XmlSerializable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.LinkedList;
import java.util.List;
public class DataManagementPlanBlueprint implements XmlSerializable<DataManagementPlanBlueprint> {
private List<Section> sections;
public List<Section> getSections() {
return sections;
}
public void setSections(List<Section> sections) {
this.sections = sections;
}
@Override
public Element toXml(Document doc) {
Element root = doc.createElement("root");
Element sections = doc.createElement("sections");
for (Section section : this.sections) {
sections.appendChild(section.toXml(doc));
}
root.appendChild(sections);
return root;
}
@Override
public DataManagementPlanBlueprint fromXml(Element item) {
this.sections = new LinkedList<>();
Element sections = (Element) XmlBuilder.getNodeFromListByTagName(item.getChildNodes(), "sections");
if (sections != null) {
NodeList sectionElements = sections.getChildNodes();
for (int temp = 0; temp < sectionElements.getLength(); temp++) {
Node sectionElement = sectionElements.item(temp);
if (sectionElement.getNodeType() == Node.ELEMENT_NODE) {
this.sections.add(new Section().fromXml((Element) sectionElement));
}
}
}
return this;
}
}

View File

@ -0,0 +1,72 @@
package eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition;
import eu.eudat.logic.utilities.interfaces.XmlSerializable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.util.UUID;
public class DescriptionTemplate implements XmlSerializable<DescriptionTemplate> {
private UUID id;
private UUID descriptionTemplateId;
private String label;
private Integer minMultiplicity;
private Integer maxMultiplicity;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public UUID getDescriptionTemplateId() {
return descriptionTemplateId;
}
public void setDescriptionTemplateId(UUID descriptionTemplateId) {
this.descriptionTemplateId = descriptionTemplateId;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public Integer getMinMultiplicity() {
return minMultiplicity;
}
public void setMinMultiplicity(Integer minMultiplicity) {
this.minMultiplicity = minMultiplicity;
}
public Integer getMaxMultiplicity() {
return maxMultiplicity;
}
public void setMaxMultiplicity(Integer maxMultiplicity) {
this.maxMultiplicity = maxMultiplicity;
}
@Override
public Element toXml(Document doc) {
Element rootElement = doc.createElement("descriptionTemplate");
rootElement.setAttribute("id", this.getId().toString());
rootElement.setAttribute("descriptionTemplateId", this.getDescriptionTemplateId().toString());
rootElement.setAttribute("label", this.label);
rootElement.setAttribute("minMultiplicity", String.valueOf(this.minMultiplicity));
rootElement.setAttribute("maxMultiplicity", String.valueOf(this.maxMultiplicity));
return rootElement;
}
@Override
public DescriptionTemplate fromXml(Element item) {
this.id = UUID.fromString(item.getAttribute("id"));
this.descriptionTemplateId = UUID.fromString(item.getAttribute("descriptionTemplateId"));
this.label = item.getAttribute("label");
this.minMultiplicity = Integer.valueOf(item.getAttribute("minMultiplicity"));
this.maxMultiplicity = Integer.valueOf(item.getAttribute("maxMultiplicity"));
return this;
}
}

View File

@ -0,0 +1,93 @@
package eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition;
import eu.eudat.logic.utilities.interfaces.XmlSerializable;
import eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition.types.ExtraFieldType;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.util.UUID;
public class ExtraField implements XmlSerializable<ExtraField> {
private UUID id;
private String label;
private String description;
private String placeholder;
private ExtraFieldType type;
private Boolean required;
private Integer ordinal;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getPlaceholder() {
return placeholder;
}
public void setPlaceholder(String placeholder) {
this.placeholder = placeholder;
}
public ExtraFieldType getType() {
return type;
}
public void setType(ExtraFieldType type) {
this.type = type;
}
public Boolean getRequired() {
return required;
}
public void setRequired(Boolean required) {
this.required = required;
}
public Integer getOrdinal() {
return ordinal;
}
public void setOrdinal(Integer ordinal) {
this.ordinal = ordinal;
}
@Override
public Element toXml(Document doc) {
Element rootElement = doc.createElement("extraField");
rootElement.setAttribute("id", this.getId().toString());
rootElement.setAttribute("label", this.label);
rootElement.setAttribute("description", this.description);
rootElement.setAttribute("placeholder", this.placeholder);
rootElement.setAttribute("type", String.valueOf(this.type.getValue()));
rootElement.setAttribute("required", String.valueOf(this.required));
rootElement.setAttribute("ordinal", String.valueOf(this.ordinal));
return rootElement;
}
@Override
public ExtraField fromXml(Element item) {
this.id = UUID.fromString(item.getAttribute("id"));
this.label = item.getAttribute("label");
this.description = item.getAttribute("description");
this.placeholder = item.getAttribute("placeholder");
this.type = ExtraFieldType.fromInteger(Integer.parseInt(item.getAttribute("type")));
this.required = Boolean.parseBoolean(item.getAttribute("required"));
this.ordinal = Integer.valueOf(item.getAttribute("ordinal"));
return this;
}
}

View File

@ -0,0 +1,140 @@
package eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition;
import eu.eudat.logic.utilities.builders.XmlBuilder;
import eu.eudat.logic.utilities.interfaces.XmlSerializable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
public class Section implements XmlSerializable<Section> {
private UUID id;
private String label;
private String description;
private Integer ordinal;
private List<SystemField> systemFields;
private List<DescriptionTemplate> descriptionTemplates;
private List<ExtraField> extraFields;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getOrdinal() {
return ordinal;
}
public void setOrdinal(Integer ordinal) {
this.ordinal = ordinal;
}
public List<SystemField> getSystemFields() {
return systemFields;
}
public void setSystemFields(List<SystemField> systemFields) {
this.systemFields = systemFields;
}
public List<DescriptionTemplate> getDescriptionTemplates() {
return descriptionTemplates;
}
public void setDescriptionTemplates(List<DescriptionTemplate> descriptionTemplates) {
this.descriptionTemplates = descriptionTemplates;
}
public List<ExtraField> getExtraFields() {
return extraFields;
}
public void setExtraFields(List<ExtraField> extraFields) {
this.extraFields = extraFields;
}
@Override
public Element toXml(Document doc) {
Element rootElement = doc.createElement("section");
rootElement.setAttribute("id", this.getId().toString());
rootElement.setAttribute("label", this.label);
rootElement.setAttribute("description", this.description);
rootElement.setAttribute("ordinal", String.valueOf(this.ordinal));
Element systemFields = doc.createElement("systemFields");
for (SystemField systemField : this.systemFields) {
systemFields.appendChild(systemField.toXml(doc));
}
rootElement.appendChild(systemFields);
Element descriptionTemplates = doc.createElement("descriptionTemplates");
for (DescriptionTemplate descriptionTemplate : this.descriptionTemplates) {
descriptionTemplates.appendChild(descriptionTemplate.toXml(doc));
}
rootElement.appendChild(descriptionTemplates);
Element extraFields = doc.createElement("extraFields");
for (ExtraField extraField : this.extraFields) {
extraFields.appendChild(extraField.toXml(doc));
}
rootElement.appendChild(extraFields);
return rootElement;
}
@Override
public Section fromXml(Element item) {
this.id = UUID.fromString(item.getAttribute("id"));
this.label = item.getAttribute("label");
this.description = item.getAttribute("description");
this.ordinal = Integer.valueOf(item.getAttribute("ordinal"));
this.systemFields = new LinkedList<>();
Element systemFields = (Element) XmlBuilder.getNodeFromListByTagName(item.getChildNodes(), "systemFields");
if (systemFields != null) {
NodeList systemFieldElements = systemFields.getChildNodes();
for (int temp = 0; temp < systemFieldElements.getLength(); temp++) {
Node systemFieldElement = systemFieldElements.item(temp);
if (systemFieldElement.getNodeType() == Node.ELEMENT_NODE) {
this.systemFields.add(new SystemField().fromXml((Element) systemFieldElement));
}
}
}
this.descriptionTemplates = new LinkedList<>();
Element descriptionTemplates = (Element) XmlBuilder.getNodeFromListByTagName(item.getChildNodes(), "descriptionTemplates");
if (descriptionTemplates != null) {
NodeList descriptionTemplateElements = descriptionTemplates.getChildNodes();
for (int temp = 0; temp < descriptionTemplateElements.getLength(); temp++) {
Node descriptionTemplateElement = descriptionTemplateElements.item(temp);
if (descriptionTemplateElement.getNodeType() == Node.ELEMENT_NODE) {
this.descriptionTemplates.add(new DescriptionTemplate().fromXml((Element) descriptionTemplateElement));
}
}
}
this.extraFields = new LinkedList<>();
Element extraFields = (Element) XmlBuilder.getNodeFromListByTagName(item.getChildNodes(), "extraFields");
if (extraFields != null) {
NodeList extraFieldElements = extraFields.getChildNodes();
for (int temp = 0; temp < extraFieldElements.getLength(); temp++) {
Node extraFieldElement = extraFieldElements.item(temp);
if (extraFieldElement.getNodeType() == Node.ELEMENT_NODE) {
this.extraFields.add(new ExtraField().fromXml((Element) extraFieldElement));
}
}
}
return this;
}
}

View File

@ -0,0 +1,94 @@
package eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition;
import eu.eudat.logic.utilities.interfaces.XmlSerializable;
import eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition.types.SystemFieldType;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.util.UUID;
public class SystemField implements XmlSerializable<SystemField> {
private UUID id;
private SystemFieldType type;
private String label;
private String placeholder;
private String description;
private boolean required;
private Integer ordinal;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public SystemFieldType getType() {
return type;
}
public void setType(SystemFieldType type) {
this.type = type;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getPlaceholder() {
return placeholder;
}
public void setPlaceholder(String placeholder) {
this.placeholder = placeholder;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean isRequired() {
return required;
}
public void setRequired(boolean required) {
this.required = required;
}
public Integer getOrdinal() {
return ordinal;
}
public void setOrdinal(Integer ordinal) {
this.ordinal = ordinal;
}
@Override
public Element toXml(Document doc) {
Element rootElement = doc.createElement("systemField");
rootElement.setAttribute("id", this.getId().toString());
rootElement.setAttribute("type", String.valueOf(this.type.getType()));
rootElement.setAttribute("label", this.label);
rootElement.setAttribute("placeholder", this.placeholder);
rootElement.setAttribute("description", this.description);
rootElement.setAttribute("required", String.valueOf(this.required));
rootElement.setAttribute("ordinal", String.valueOf(this.ordinal));
return rootElement;
}
@Override
public SystemField fromXml(Element item) {
this.id = UUID.fromString(item.getAttribute("id"));
this.type = SystemFieldType.fromInteger(Integer.parseInt(item.getAttribute("type")));
this.label = item.getAttribute("label");
this.placeholder = item.getAttribute("placeholder");
this.description = item.getAttribute("description");
this.required = Boolean.parseBoolean(item.getAttribute("required"));
this.ordinal = Integer.valueOf(item.getAttribute("ordinal"));
return this;
}
}

View File

@ -0,0 +1,30 @@
package eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition.types;
public enum ExtraFieldType {
TEXT(0), RICH_TEXT(1), DATE(2), NUMBER(3);
private Integer value;
private ExtraFieldType(Integer value) {
this.value = value;
}
public Integer getValue() {
return value;
}
public static ExtraFieldType fromInteger(Integer value) {
switch (value) {
case 0:
return TEXT;
case 1:
return RICH_TEXT;
case 2:
return DATE;
case 3:
return NUMBER;
default:
throw new RuntimeException("Unsupported ExtraFieldType Type");
}
}
}

View File

@ -0,0 +1,58 @@
package eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition.types;
public enum SystemFieldType {
TEXT(0),
HTML_TEXT(1),
RESEARCHERS(2),
ORGANIZATIONS(3),
LANGUAGE(4),
CONTACT(5),
FUNDER(6),
GRANT(7),
PROJECT(8),
LICENSE(9),
ACCESS_RIGHTS(10),
DESCRIPTION_TEMPLATES(11);
private int type;
SystemFieldType(int type) {
this.type = type;
}
public int getType() {
return type;
}
public static SystemFieldType fromInteger(int type) {
switch (type) {
case 0:
return TEXT;
case 1:
return HTML_TEXT;
case 2:
return RESEARCHERS;
case 3:
return ORGANIZATIONS;
case 4:
return LANGUAGE;
case 5:
return CONTACT;
case 6:
return FUNDER;
case 7:
return GRANT;
case 8:
return PROJECT;
case 9:
return LICENSE;
case 10:
return ACCESS_RIGHTS;
case 11:
return DESCRIPTION_TEMPLATES;
default:
throw new RuntimeException("Unsupported System Field Type");
}
}
}

View File

@ -0,0 +1,93 @@
package eu.eudat.models.data.listingmodels;
import eu.eudat.data.entities.DMPProfile;
import eu.eudat.logic.utilities.builders.XmlBuilder;
import eu.eudat.models.DataModel;
import eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition.DataManagementPlanBlueprint;
import org.w3c.dom.Document;
import java.util.Date;
import java.util.UUID;
public class DataManagementPlanBlueprintListingModel implements DataModel<DMPProfile, DataManagementPlanBlueprintListingModel> {
private UUID id;
private String label;
private DataManagementPlanBlueprint definition;
private int status;
private Date created = null;
private Date modified = new Date();
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public DataManagementPlanBlueprint getDefinition() {
return definition;
}
public void setDefinition(DataManagementPlanBlueprint definition) {
this.definition = definition;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getModified() {
return modified;
}
public void setModified(Date modified) {
this.modified = modified;
}
@Override
public DataManagementPlanBlueprintListingModel fromDataModel(DMPProfile entity) {
this.id = entity.getId();
this.created = entity.getCreated();
this.definition = new DataManagementPlanBlueprint().fromXml(XmlBuilder.fromXml(entity.getDefinition()).getDocumentElement());
this.modified = entity.getModified();
this.label = entity.getLabel();
this.status = entity.getStatus();
return this;
}
@Override
public DMPProfile toDataModel() throws Exception {
Document document = XmlBuilder.getDocument();
document.appendChild(this.definition.toXml(document));
DMPProfile dmpProfile = new DMPProfile();
dmpProfile.setCreated(this.created == null ? new Date() : this.created);
dmpProfile.setDefinition(XmlBuilder.generateXml(document));
dmpProfile.setId(this.id);
dmpProfile.setLabel(this.label);
dmpProfile.setStatus(this.status);
dmpProfile.setModified(this.modified == null ? new Date() : this.modified);
return dmpProfile;
}
@Override
public String getHint() {
return null;
}
}

View File

@ -0,0 +1,10 @@
import { DmpBlueprintDefinition } from "./dmp-blueprint";
export interface DmpBlueprintListing {
id: string;
label: string;
definition: DmpBlueprintDefinition;
status: number;
created: Date;
modified: Date;
}

View File

@ -0,0 +1,72 @@
export interface DmpBlueprint {
id: string;
label: string;
definition: DmpBlueprintDefinition;
status: number;
created: Date;
modified: Date;
description: string;
}
export interface DmpBlueprintDefinition {
sections: SectionDmpBlueprint[];
}
export interface SectionDmpBlueprint {
id: string;
label: string;
description: string;
ordinal: number;
systemFields: SystemFieldInSection[];
descriptionTemplates?: DescriptionTemplatesInSection[];
extraFields?: ExtraFieldInSection[];
}
export interface SystemFieldInSection {
id: string;
type: SystemFieldType;
label: string;
placeholder: string;
description: string;
required: boolean;
ordinal: number;
}
export enum SystemFieldType {
TEXT = 0,
HTML_TEXT = 1,
RESEARCHERS= 2,
ORGANIZATIONS = 3,
LANGUAGE = 4,
CONTACT = 5,
FUNDER = 6,
GRANT = 7,
PROJECT = 8,
LICENSE = 9,
ACCESS_RIGHTS = 10
}
export interface DescriptionTemplatesInSection {
id: string;
descriptionTemplateId: string;
label: string;
minMultiplicity: number;
maxMultiplicity: number;
}
export interface ExtraFieldInSection {
id: string;
label: string;
description: string;
placeholder: string;
type: ExtraFieldType;
required: boolean;
ordinal: number;
}
export enum ExtraFieldType {
TEXT = 0,
RICH_TEXT = 1,
DATE = 2,
NUMBER = 3
}

View File

@ -0,0 +1,5 @@
import { BaseCriteria } from "../base-criteria";
export class DmpBlueprintCriteria extends BaseCriteria {
}

View File

@ -14,6 +14,9 @@ import { BaseHttpParams } from '../../../../common/http/base-http-params';
import { InterceptorType } from '../../../../common/http/interceptors/interceptor-type';
import { DmpProfileExternalAutocompleteCriteria } from '../../query/dmp/dmp-profile-external-autocomplete-criteria';
import { ConfigurationService } from '../configuration/configuration.service';
import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria';
import { DmpBlueprintListing } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint-listing';
import { DmpBlueprint } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint';
@Injectable()
export class DmpProfileService {
@ -29,14 +32,26 @@ export class DmpProfileService {
return this.http.post<DataTableData<DmpProfileListing>>(this.actionUrl + 'getPaged', dataTableRequest, { headers: this.headers });
}
getPagedBlueprint(dataTableRequest: DataTableRequest<DmpBlueprintCriteria>): Observable<DataTableData<DmpBlueprintListing>> {
return this.http.post<DataTableData<DmpBlueprintListing>>(this.actionUrl + 'getPagedBlueprint', dataTableRequest, { headers: this.headers });
}
getSingle(id: String): Observable<DmpProfile> {
return this.http.get<DmpProfile>(this.actionUrl + 'getSingle/' + id, { headers: this.headers });
}
getSingleBlueprint(id: String): Observable<DmpBlueprintListing> {
return this.http.get<DmpBlueprintListing>(this.actionUrl + 'getSingleBlueprint/' + id, { headers: this.headers });
}
createDmp(dataManagementPlanModel: DmpProfile): Observable<DmpProfile> {
return this.http.post<DmpProfile>(this.actionUrl, dataManagementPlanModel, { headers: this.headers });
}
createBlueprint(dmpBlueprint: DmpBlueprint): Observable<DmpProfile> {
return this.http.post<DmpProfile>(this.actionUrl + 'blueprint', dmpBlueprint, { headers: this.headers });
}
public downloadXML(id: string): Observable<HttpResponse<Blob>> {
let headerXml: HttpHeaders = this.headers.set('Content-Type', 'application/xml')
return this.httpClient.get(this.actionUrl + 'getXml/' + id, { responseType: 'blob', observe: 'response', headers: headerXml });

View File

@ -7,8 +7,8 @@ import { AdminAuthGuard } from '@app/core/admin-auth-guard.service';
const routes: Routes = [
{ path: '', component: DmpProfileListingComponent, canActivate: [AdminAuthGuard] },
{ path: 'new', component: DmpProfileEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DMP-PROFILE-NEW' } },
{ path: ':id', component: DmpProfileEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DMP-PROFILE-EDIT' } },
{ path: 'new', component: DmpProfileEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DMP-BLUEPRINT-NEW' } },
{ path: ':id', component: DmpProfileEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DMP-BLUEPRINT-EDIT' } },
];
@NgModule({

View File

@ -0,0 +1,192 @@
import { FormBuilder, FormGroup } from "@angular/forms";
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, ExtraFieldInSection, ExtraFieldType, SectionDmpBlueprint, SystemFieldInSection, SystemFieldType } from "@app/core/model/dmp/dmp-blueprint/dmp-blueprint";
export class DmpBlueprintEditor {
public id: string;
public label: string;
public definition: DmpBlueprintDefinitionEditor = new DmpBlueprintDefinitionEditor();
public status: number;
public created: Date;
public modified: Date;
fromModel(item: DmpBlueprint): DmpBlueprintEditor {
this.id = item.id;
this.label = item.label;
this.definition = new DmpBlueprintDefinitionEditor().fromModel(item.definition);
this.status = item.status;
this.created = item.created;
this.modified = item.modified;
return this;
}
buildForm(): FormGroup {
const formGroup = new FormBuilder().group({
id: [this.id],
label: [this.label],
status: [this.status],
created: [this.created],
modified: [this.modified]
});
formGroup.addControl('definition', this.definition.buildForm());
return formGroup;
}
}
export class DmpBlueprintDefinitionEditor {
public sections: SectionDmpBlueprintEditor[] = new Array<SectionDmpBlueprintEditor>();
fromModel(item: DmpBlueprintDefinition): DmpBlueprintDefinitionEditor {
if (item.sections) { item.sections.map(x => this.sections.push(new SectionDmpBlueprintEditor().fromModel(x))); }
return this;
}
buildForm(): FormGroup {
const formBuilder = new FormBuilder();
const formGroup = formBuilder.group({});
const sectionsFormArray = new Array<FormGroup>();
this.sections.forEach(item => {
const form: FormGroup = item.buildForm();
sectionsFormArray.push(form);
});
formGroup.addControl('sections', formBuilder.array(sectionsFormArray));
return formGroup;
}
}
export class SectionDmpBlueprintEditor {
public id: string;
public label: string;
public description: string;
public ordinal: number;
public systemFields: SystemFieldInSectionEditor[] = new Array<SystemFieldInSectionEditor>();
public descriptionTemplates: DescriptionTemplatesInSectionEditor[] = new Array<DescriptionTemplatesInSectionEditor>();
fromModel(item: SectionDmpBlueprint): SectionDmpBlueprintEditor {
this.id = item.id;
this.label = item.label;
this.description = item.description;
this.ordinal = item.ordinal;
if (item.systemFields) { item.systemFields.map(x => this.systemFields.push(new SystemFieldInSectionEditor().fromModel(x))); }
if (item.descriptionTemplates) { item.descriptionTemplates.map(x => this.descriptionTemplates.push(new DescriptionTemplatesInSectionEditor().fromModel(x))); }
debugger;
return this;
}
buildForm(): FormGroup {
const formGroup = new FormBuilder().group({
id: [this.id],
label: [this.label],
description: [this.description],
ordinal: [this.ordinal]
});
const formBuilder = new FormBuilder();
const systemFieldsFormArray = new Array<FormGroup>();
this.systemFields.forEach(item => {
const form: FormGroup = item.buildForm();
systemFieldsFormArray.push(form);
});
formGroup.addControl('systemFields', formBuilder.array(systemFieldsFormArray));
const descriptionTemplatesFormArray = new Array<FormGroup>();
this.descriptionTemplates.forEach(item => {
const form: FormGroup = item.buildForm();
descriptionTemplatesFormArray.push(form);
});
formGroup.addControl('descriptionTemplates', formBuilder.array(descriptionTemplatesFormArray));
return formGroup;
}
}
export class SystemFieldInSectionEditor {
public id: string;
public type: SystemFieldType;
public placeholder: string;
public description: string;
public required: boolean;
public ordinal: number;
fromModel(item: SystemFieldInSection): SystemFieldInSectionEditor {
this.id = item.id;
this.type = item.type;
this.placeholder = item.placeholder;
this.description = item.description;
this.required = item.required;
this.ordinal = item.ordinal;
return this;
}
buildForm(): FormGroup {
const formGroup = new FormBuilder().group({
id: [this.id],
type: [this.type],
placeholder: [this.placeholder],
description: [this.description],
required: [this.required],
ordinal: [this.ordinal]
});
return formGroup;
}
}
export class DescriptionTemplatesInSectionEditor {
public id: string;
public descriptionTemplateId: string;
public label: string;
public minMultiplicity: number;
public maxMultiplicity: number;
fromModel(item: DescriptionTemplatesInSection): DescriptionTemplatesInSectionEditor {
this.id = item.id;
this.descriptionTemplateId = item.descriptionTemplateId;
this.label = item.label;
this.minMultiplicity = item.minMultiplicity;
this.maxMultiplicity = item.maxMultiplicity;
return this;
}
buildForm(): FormGroup {
const formGroup = new FormBuilder().group({
id: [this.id],
descriptionTemplateId: [this.descriptionTemplateId],
label: [this.label],
minMultiplicity: [this.minMultiplicity],
maxMultiplicity: [this.maxMultiplicity]
});
return formGroup;
}
}
export class ExtraFieldsInSectionEditor {
public id: string;
public label: string;
public description: string;
public placeholder: string;
public type: ExtraFieldType;
public required: boolean;
public ordinal: number;
fromModel(item: ExtraFieldInSection): ExtraFieldsInSectionEditor {
this.id = item.id;
this.label = item.label;
this.description = item.description;
this.placeholder = item.placeholder;
this.type = item.type;
this.required = item.required;
this.ordinal = item.ordinal;
return this;
}
buildForm(): FormGroup {
const formGroup = new FormBuilder().group({
id: [this.id],
label: [this.label],
description: [this.description],
placeholder: [this.placeholder],
type: [this.type],
required: [this.required],
ordinal: [this.ordinal]
});
return formGroup;
}
}

View File

@ -18,10 +18,10 @@
</div>
<div *ngIf="formGroup.get('status').value!=1" class="col-auto">
<button mat-button class="finalize-btn" (click)="finalize()"
[disabled]="!formGroup.valid" type="button">{{'DMP-PROFILE-EDITOR.ACTIONS.FINALIZE' | translate }}</button>
[disabled]="true" type="button">{{'DMP-PROFILE-EDITOR.ACTIONS.FINALIZE' | translate }}</button>
</div>
</div>
<form *ngIf="formGroup" (ngSubmit)="formSubmit()" [formGroup]="formGroup">
<form *ngIf="dmpBlueprintsFormGroup" (ngSubmit)="onSubmitTest()" [formGroup]="dmpBlueprintsFormGroup">
<mat-card style="padding: 2em;">
<!-- <mat-card-header>
<mat-card-title *ngIf="isNew">
@ -36,14 +36,224 @@
<mat-form-field class="col-lg-6" appearance="legacy">
<input matInput placeholder="{{'DMP-PROFILE-EDITOR.FIELDS.LABEL' | translate}}" type="text" name="label" formControlName="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')">
<mat-error *ngIf="dmpBlueprintsFormGroup.get('label').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<h4 class="col-12">{{'DMP-PROFILE-EDITOR.FIELDS.TITLE' | translate}}</h4>
<h4 class="col-12">Sections</h4>
<ng-container formArrayName="sections">
<div *ngFor="let section of sectionsArray().controls; let sectionIndex=index;" class="section-input" style="width: 100%;">
<ng-container [formGroupName]="sectionIndex">
<div class="col-12">
<div class="row">
<mat-card class="col-11" style="width: 100%;">
<mat-card-header>
<mat-card-title>Section {{sectionIndex + 1}}</mat-card-title>
</mat-card-header>
<div class="col-12">
<div class="row">
<div class="col-6">
<mat-form-field>
<mat-label>Section name</mat-label>
<input matInput type="text" name="label" formControlName="label" required>
<mat-error *ngIf="section.get('label').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<mat-form-field>
<mat-label>Section description</mat-label>
<input matInput type="text" name="description" formControlName="description" required>
<mat-error *ngIf="section.get('description').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
</div>
<div class="col-12">
<div class="row">
<div class="col-12">
<mat-form-field>
<mat-label>System fields</mat-label>
<mat-select multiple>
<mat-option *ngFor="let f of fieldList" [disabled]="systemFieldDisabled(f.type, sectionIndex)" [value]="f.type" (click)="selectedFieldType(f.label, f.type, sectionIndex)">{{f.label}}</mat-option>
</mat-select>
<mat-error *ngIf="systemFieldsArray(sectionIndex).hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
</div>
<ng-container formArrayName="systemFields">
<div *ngFor="let systemField of systemFieldsArray(sectionIndex).controls; let systemFieldIndex=index;">
<ng-container [formGroupName]="systemFieldIndex">
<div class="col-12" *ngIf="systemFieldsArray(sectionIndex).length > 0">
<!-- <div *ngFor="let systemField of systemFieldsArray(sectionIndex).value; let i=index;" class="section-input" style="width: 100%;"> -->
<div class="row">
<div class="col-3">
<mat-form-field>
<mat-label>System Field</mat-label>
<input matInput disabled value="{{transfromEnumToString(systemField.get('type').value)}}" type="text" name="name">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Label</mat-label>
<input matInput type="text" name="label" formControlName="label">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Placeholder</mat-label>
<input matInput type="text" name="placeholder" formControlName="placeholder">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Description</mat-label>
<input matInput type="text" name="description" formControlName="description">
</mat-form-field>
</div>
<!-- <div class="col-3">
<mat-checkbox style="margin-top: 4%;" formControlName="required">Required</mat-checkbox>
</div> -->
</div>
<!-- </div> -->
</div>
</ng-container>
</div>
</ng-container>
<ng-container formArrayName="extraFields">
<div class="col-12">
<div class="row" *ngFor="let extraField of extraFieldsArray(sectionIndex).controls; let extraFieldIndex=index;">
<ng-container [formGroupName]="extraFieldIndex">
<mat-form-field class="col-3">
<mat-label>Label</mat-label>
<input matInput type="text" name="label" formControlName="label" required>
</mat-form-field>
<mat-form-field class="col-3">
<mat-label>Description</mat-label>
<input matInput type="text" name="description" formControlName="description">
</mat-form-field>
<mat-form-field class="col-3">
<mat-label>Type</mat-label>
<mat-select placeholder="Type" formControlName="type" required>
<mat-option *ngFor="let extraFieldType of getExtraFieldTypes()" [value]="extraFieldType">
{{getExtraFieldTypeValue(extraFieldType)}}
</mat-option>
</mat-select>
</mat-form-field>
<div class="centered-row-item col-1">
<mat-checkbox formControlName="required">
Required
</mat-checkbox>
</div>
<div class="extra-field-delete col-1" (click)="removeExtraField(sectionIndex, extraFieldIndex)">
<mat-icon class="extra-field-delete-icon">delete</mat-icon>
<span class="extra-field-delete-text">{{'DATASET-PROFILE-EDITOR.STEPS.TOOLKIT.DELETE' | translate}}</span>
</div>
</ng-container>
</div>
</div>
<div class="col-12">
<div class="row">
<div class="col-auto">
<button mat-button class="action-btn" type="button" (click)="addExtraField(sectionIndex)">Add extra field</button>
</div>
</div>
</div>
</ng-container>
<div class="col-12">
<div class="row">
<div class="col-12">
<!-- <mat-form-field>
<mat-label>Description Templates</mat-label>
<mat-select (selectionChange)="addDescriptionTemplate($event, sectionIndex)" multiple>
<mat-option *ngFor="let descTemplate of descriptionsList">{{descTemplate}}</mat-option>
</mat-select>
</mat-form-field> -->
<mat-form-field>
<mat-label>Description Templates</mat-label>
<app-multiple-auto-complete placeholder="Description Templates2" [hidePlaceholder]="true" required='false' [formControl]="section.get('descriptionTemplates')" [configuration]="profilesAutoCompleteConfiguration" (optionRemoved)="onRemoveTemplate($event, sectionIndex)" (optionActionClicked)="onPreviewTemplate($event, sectionIndex)" (optionSelected)="onOptionSelected(sectionIndex)">
</app-multiple-auto-complete>
<!-- <button matSuffix class="input-btn" (click)="allAvailableProfiles($event)">
<mat-icon class="icon-btn">view_list</mat-icon>
</button> -->
</mat-form-field>
</div>
</div>
</div>
<!-- <ng-container formArrayName="descriptionTemplates">
<div *ngFor="let descriptionTemplate of descriptionTemplatesArray(sectionIndex).controls; let j=index;" class="section-input" style="width: 100%;">
<ng-container [formGroupName]="j">
<div class="col-12" *ngIf="descriptionTemplatesArray(sectionIndex).length > 0">
<div class="row">
<div class="col-6">
<mat-form-field>
<mat-label>Label</mat-label>
<input matInput type="text" name="name" formControlName="label">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Min Multiplicity</mat-label>
<input matInput type="number" name="minMultiplicity" formControlName="minMultiplicity">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Max Multiplicity</mat-label>
<input matInput type="number" name="maxMultiplicity" formControlName="maxMultiplicity">
</mat-form-field>
</div>
</div>
</div>
</ng-container>
</div>
</ng-container> -->
</mat-card>
<div class="col-1">
<div class="row">
<!-- <div class="col-auto dlt-section-btn">
<button mat-button class="action-btn" type="button" click="removeSection(sectionIndex)">Delete</button>
</div> -->
<div class="action-list-item col-auto dlt-section-btn" (click)="removeSection(sectionIndex)">
<mat-icon class="action-list-icon">delete</mat-icon>
<span class="action-list-text">{{'DATASET-PROFILE-EDITOR.STEPS.TOOLKIT.DELETE' | translate}}</span>
</div>
</div>
</div>
</div>
</div>
</ng-container>
<!-- <div class="arrows mt-2">
<ul class="list-unstyled list-inline d-flex align-items-center">
<li *ngIf="canGoUp(i)" class="text-muted">
<mat-icon style="cursor: pointer;" [matTooltip]="'DATASET-PROFILE-EDITOR.ACTIONS.FIELD.MOVE-UP' | translate">keyboard_arrow_up</mat-icon>
</li>
<li *ngIf="canGoDown(i)" class="text-muted">
<mat-icon style="cursor: pointer;" [matTooltip]="'DATASET-PROFILE-EDITOR.ACTIONS.FIELD.MOVE-DOWN' | translate">keyboard_arrow_down</mat-icon>
</li>
</ul>
</div> -->
</div>
</ng-container>
<div class="col-12">
<div class="row">
<div class="col-auto">
<button mat-button class="action-btn" type="button" (click)="addSection()">Add section</button>
</div>
</div>
</div>
<!-- <div class="col-12">
<div class="row" *ngFor="let fieldFormGroup of formGroup.get('definition').get('fields')['controls'];let i=index">
<div class="col-10">
<div class="row">
@ -118,7 +328,7 @@
</div>
</div>
</div>
</div>
</div> -->
</div>
<div class="row mt-4">
<div class="col-auto">
@ -139,7 +349,7 @@
</div> -->
<div class="col-auto" *ngIf="!viewOnly">
<button mat-button class="action-btn" type="submit" [disabled]="!formGroup.valid">
<button mat-button class="action-btn" type="submit" [disabled]="!dmpBlueprintsFormGroup.valid">
{{'DMP-PROFILE-EDITOR.ACTIONS.SAVE' | translate}}
</button>
</div>

View File

@ -60,4 +60,62 @@
color: #FFF;
border: 0px;
}
}
.dlt-section-btn {
margin: 0;
position: absolute;
top: 50%;
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
.section-input {
position: relative;
}
.section-input .arrows {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
}
.action-list-item{
display: flex;
align-items: center;
cursor: pointer;
.action-list-icon{
font-size: 1.2em;
// padding-right: 1em;
width: 14px;
margin-right: 0.5em;
margin-left: -.09em;
height: auto;
color: var(--primary-color);
}
.action-list-text{
font-size: 1em;
color: var(--primary-color);
}
}
.extra-field-delete{
align-items: center;
display: flex;
cursor: pointer;
.extra-field-delete-icon{
font-size: 1.2em;
width: 14px;
color: var(--primary-color);
}
.extra-field-delete-text{
font-size: 1em;
margin-left: 0.5em;
color: var(--primary-color);
}
}

View File

@ -1,6 +1,6 @@
import { AfterViewInit, Component } from '@angular/core';
import { FormArray, FormGroup } from '@angular/forms';
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { DmpProfileFieldDataType } from '@app/core/common/enum/dmp-profile-field-type';
import { DmpProfileStatus } from '@app/core/common/enum/dmp-profile-status';
@ -25,6 +25,17 @@ import { HttpClient } from '@angular/common/http';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { MatDialog } from '@angular/material/dialog';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { AvailableProfilesComponent } from '@app/ui/dmp/editor/available-profiles/available-profiles.component';
import { DatasetPreviewDialogComponent } from '@app/ui/dmp/dataset-preview/dataset-preview-dialog.component';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { DmpBlueprint, DmpBlueprintDefinition, ExtraFieldType, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint';
import { DmpBlueprintEditor } from './dmp-blueprint-editor.model';
import { Guid } from '@common/types/guid';
@Component({
@ -37,19 +48,41 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie
isNew = true;
viewOnly = false;
dmpProfileModel: DmpProfileEditorModel;
dmpBlueprintModel: DmpBlueprintEditor;
formGroup: FormGroup = null;
host: string;
dmpProfileId: string;
breadCrumbs: Observable<BreadcrumbItem[]>;
dmpBlueprintsFormGroup: FormGroup = null;
profilesAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
fieldList = [
{label: 'Title', type: SystemFieldType.TEXT},
{label: 'Description', type: SystemFieldType.HTML_TEXT},
{label: 'Researchers', type: SystemFieldType.RESEARCHERS},
{label: 'Organizations', type: SystemFieldType.ORGANIZATIONS},
{label: 'Language', type: SystemFieldType.LANGUAGE},
{label: 'Contact', type: SystemFieldType.CONTACT},
{label: 'Funder', type: SystemFieldType.FUNDER},
{label: 'Grant', type: SystemFieldType.GRANT},
{label: 'Project', type: SystemFieldType.PROJECT},
{label: 'License', type: SystemFieldType.LICENSE},
{label: 'Access Rights', type: SystemFieldType.ACCESS_RIGHTS}
];
selectedSystemFields: string[] = [];
constructor(
private dmpProfileService: DmpProfileService,
private _service: DmpService,
private route: ActivatedRoute,
private router: Router,
private language: TranslateService,
private enumUtils: EnumUtils,
private uiNotificationService: UiNotificationService,
private formService: FormService,
private fb: FormBuilder,
private configurationService: ConfigurationService,
private httpClient: HttpClient,
private matomoService: MatomoService,
@ -61,6 +94,16 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie
ngAfterViewInit() {
this.matomoService.trackPageView('Admin: DMP Profile Edit');
this.profilesAutoCompleteConfiguration = {
filterFn: this.filterProfiles.bind(this),
initialItems: (excludedItems: any[]) => this.filterProfiles('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
subtitleFn: (item) => item['description'],
popupItemActionIcon: 'visibility'
};
this.route.params
.pipe(takeUntil(this._destroyed))
.subscribe((params: Params) => {
@ -85,9 +128,11 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie
});
} else {
this.dmpProfileModel = new DmpProfileEditorModel();
this.dmpBlueprintModel = new DmpBlueprintEditor();
setTimeout(() => {
this.formGroup = this.dmpProfileModel.buildForm();
this.addField();
// this.formGroup = this.dmpProfileModel.buildForm();
// this.addField();
this.formGroup = this.dmpBlueprintModel.buildForm();
});
this.breadCrumbs = observableOf([{
parentComponentName: 'DmpProfileListingComponent',
@ -96,6 +141,282 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie
}]);
}
});
this.initDmpBlueptintForm();
}
filterProfiles(value: string): Observable<DatasetProfileModel[]> {
const request = new DataTableRequest<DatasetProfileCriteria>(null, null, { fields: ['+label'] });
const criteria = new DatasetProfileCriteria();
criteria.like = value;
request.criteria = criteria;
return this._service.searchDMPProfiles(request);
}
initDmpBlueptintForm(): void {
this.dmpBlueprintsFormGroup = this.fb.group({
label: this.fb.control(''),
sections: this.fb.array([])
});
}
sectionsArray(): FormArray {
return this.dmpBlueprintsFormGroup.get('sections') as FormArray;
}
initSection(ordinal: number): FormGroup {
return this.fb.group({
id: this.fb.control(Guid.create().toString()),
label: this.fb.control(''),
description: this.fb.control(''),
ordinal: this.fb.control(ordinal),
systemFields: this.fb.array([]),
descriptionTemplates: this.fb.control(''),
// this.fb.array([this.initDescriptionTemplate()]),
extraFields: this.fb.array([])
});
}
addSection(): void {
this.sectionsArray().push(this.initSection(this.sectionsArray().length));
}
removeSection(sectionIndex: number): void {
this.sectionsArray().removeAt(sectionIndex);
}
systemFieldsArray(sectionIndex: number): FormArray {
return this.sectionsArray().at(sectionIndex).get('systemFields') as FormArray;
}
initSystemField(systemField?: SystemFieldType): FormGroup {
return this.fb.group({
id: this.fb.control(Guid.create().toString()),
type: this.fb.control(systemField),
label: this.fb.control(''),
placeholder: this.fb.control(''),
description: this.fb.control(''),
required: this.fb.control(true),
ordinal: this.fb.control('')
});
}
addSystemField(sectionIndex: number, systemField?: SystemFieldType): void {
this.systemFieldsArray(sectionIndex).push(this.initSystemField(systemField));
}
transfromEnumToString(type: SystemFieldType): string{
return this.fieldList.find(f => f.type == type).label;
}
selectedFieldType(systemField: string, type: SystemFieldType, sectionIndex: number): void {
let index = this.selectedSystemFields.indexOf(systemField);
if (index == -1) {
this.selectedSystemFields.push(systemField);
this.addSystemField(sectionIndex, type);
}
else {
this.selectedSystemFields.splice(index, 1);
this.removeSystemField(sectionIndex, type);
}
}
systemFieldDisabled(systemField: SystemFieldType, sectionIndex: number) {
let i = 0;
for (let s in this.sectionsArray().controls) {
if (i != sectionIndex) {
for (let f of this.systemFieldsArray(i).controls) {
if (f.get('type').value == systemField) {
return true;
}
}
}
i++;
}
return false;
}
removeSystemFieldWithIndex(sectionIndex: number, fieldIndex: number): void {
this.systemFieldsArray(sectionIndex).removeAt(fieldIndex);
}
removeSystemField(sectionIndex: number, systemField: SystemFieldType): void {
let i = 0;
for(let sf of this.systemFieldsArray(sectionIndex).controls){
if(sf.get('type').value == systemField){
this.systemFieldsArray(sectionIndex).removeAt(i);
return;
}
i++;
}
}
descriptionTemplatesArray(sectionIndex: number): FormArray {
return this.sectionsArray().at(sectionIndex).get('descriptionTemplates') as FormArray;
}
initDescriptionTemplate(): FormGroup {
return this.fb.group({
descriptionTemplateId: this.fb.control(''),
label: this.fb.control(''),
minMultiplicity: this.fb.control(''),
maxMultiplicity: this.fb.control('')
});
}
addDescriptionTemplate(descriptionTemplate, sectionIndex: number): void {
this.descriptionTemplatesArray(sectionIndex).push(this.fb.group({
label: this.fb.control(descriptionTemplate.value)
}));
}
removeDescriptionTemplate(sectionIndex: number, templateIndex: number): void {
this.descriptionTemplatesArray(sectionIndex).removeAt(templateIndex);
}
extraFieldsArray(sectionIndex: number): FormArray {
return this.sectionsArray().at(sectionIndex).get('extraFields') as FormArray;
}
initExtraField(): FormGroup {
return this.fb.group({
id: this.fb.control(Guid.create().toString()),
label: this.fb.control(''),
placeholder: this.fb.control(''),
description: this.fb.control(''),
type: this.fb.control(''),
required: this.fb.control(false),
ordinal: this.fb.control('')
});
}
addExtraField(sectionIndex: number): void {
this.extraFieldsArray(sectionIndex).push(this.initExtraField());
}
removeExtraField(sectionIndex: number, extraFieldIndex: number): void {
this.extraFieldsArray(sectionIndex).removeAt(extraFieldIndex);
}
getExtraFieldTypes(): Number[] {
let keys: string[] = Object.keys(ExtraFieldType);
keys = keys.slice(0, keys.length / 2);
const values: Number[] = keys.map(Number);
return values;
}
getExtraFieldTypeValue(extraFieldType: ExtraFieldType): string {
switch (extraFieldType) {
case ExtraFieldType.TEXT: return 'Text';
case ExtraFieldType.RICH_TEXT: return 'Rich Text';
case ExtraFieldType.DATE: return 'Date';
case ExtraFieldType.NUMBER: return 'Number';
}
}
onSubmitTest(): void {
}
drop(event: CdkDragDrop<string[]>) {
this.moveItemInFormArray(
this.systemFieldsArray(0),
event.previousIndex,
event.currentIndex
);
}
moveItemInFormArray(formArray: FormArray, fromIndex: number, toIndex: number): void {
const dir = toIndex > fromIndex ? 1 : -1;
const item = formArray.at(fromIndex);
for (let i = fromIndex; i * dir < toIndex * dir; i = i + dir) {
const current = formArray.at(i + dir);
formArray.setControl(i, current);
}
formArray.setControl(toIndex, item);
}
// clearForm(): void{
// this.dmpBlueprintsFormGroup.reset();
// }
canGoUp(index: number): boolean {
return index > 0;
}
canGoDown(index: number): boolean {
return index < (this.sectionsArray().length - 1);
}
onRemoveTemplate(event, sectionIndex: number) {
// let found = false;
// const profiles = this.descriptionTemplatesArray(sectionIndex).value;//this.formGroup.get('profiles').value;
// this.formGroup.get('datasets')['controls'].forEach(element => {
// if (element.get('profile').value.id === event.id) {
// found = true;
// this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-REMOVE-TEMPLATE'), SnackBarNotificationLevel.Success);
// }
// });
// if (found) {
// this.formGroup.get('profiles').setValue(profiles);
// this.profilesAutoCompleteConfiguration = {
// filterFn: this.filterProfiles.bind(this),
// initialItems: (excludedItems: any[]) => this.filterProfiles('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
// displayFn: (item) => item['label'],
// titleFn: (item) => item['label'],
// subtitleFn: (item) => item['description'],
// popupItemActionIcon: 'visibility'
// };
// }
}
onPreviewTemplate(event, sectionIndex: number) {
const dialogRef = this.dialog.open(DatasetPreviewDialogComponent, {
width: '590px',
minHeight: '200px',
restoreFocus: false,
data: {
template: event
},
panelClass: 'custom-modalbox'
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
let profiles = this.descriptionTemplatesArray(sectionIndex).value;//this.formGroup.get('profiles').value;
profiles.push(event);
this.descriptionTemplatesArray(sectionIndex).setValue(profiles);//this.formGroup.get('profiles').setValue(profiles);
this.profilesAutoCompleteConfiguration = {
filterFn: this.filterProfiles.bind(this),
initialItems: (excludedItems: any[]) => this.filterProfiles('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
subtitleFn: (item) => item['description'],
popupItemActionIcon: 'visibility'
};
}
});
}
onOptionSelected(sectionIndex: number){
try{
const profiles = this.descriptionTemplatesArray(sectionIndex).value as {id:string, label:string}[];//this.formGroup.get('profiles').value as {id:string, label:string}[];
const profileCounts: Map<String, number> = new Map<String, number>();
profiles.forEach((value) => profileCounts.set(value.id, (profileCounts.get(value.id) !== undefined ? profileCounts.get(value.id): 0 ) + 1));
const duplicateProfiles = profiles.filter((value) => {
let isOk = profileCounts.get(value.id) > 1;
if (isOk) {
profileCounts.set(value.id, 0);
}
return isOk;
});
duplicateProfiles.forEach((value) => profiles.splice(profiles.lastIndexOf(value), 1));
profiles.sort((a,b)=> a.label.localeCompare(b.label));
}
catch{
console.info('Could not sort Dataset Templates')
}
}
formSubmit(): void {

View File

@ -13,7 +13,7 @@
</button>
<button mat-raised-button class="create-btn ml-md-3" [routerLink]="['/dmp-profiles/new'] ">
<span class="button-text">
{{'DMP-PROFILE-LISTING.CREATE-DMP-TEMPLATE' | translate}}
{{'DMP-PROFILE-LISTING.CREATE-DMP-BLUEPRINT' | translate}}
</span>
</button>
</div>

View File

@ -71,7 +71,7 @@ export class DmpProfileListingComponent extends BaseComponent implements OnInit
this.criteria.setRefreshCallback(() => this.refresh());
this.breadCrumbs = observableOf([{
parentComponentName: null,
label: this.languageService.instant('NAV-BAR.DMP-TEMPLATES'),
label: this.languageService.instant('NAV-BAR.DMP-BLUEPRINTS-CAPS'),
url: '/dmp-profiles'
}]);
});

View File

@ -0,0 +1,271 @@
<div class="main-content">
<div class="container-fluid">
<div class="form-container">
<!-- DMP Header -->
<div [hidden]="false" class="fixed-editor-header">
<div class="card editor-header">
<div class="col">
<div class="row">
<div class="col-auto info">
<div class="title">{{'DMP-EDITOR.TITLE.EDIT-DMP' | translate}}</div>
<!-- <div class="subtitle">{{ formGroup.get('label').value }} <span *ngIf="isDirty()" class="changes">({{'DMP-EDITOR.CHANGES' | translate}})</span></div> -->
</div>
<div class="ml-auto d-flex flex-row">
<!-- <mat-divider *ngIf="formGroup.get('id').value && (isDirty() || isNew || (!isNew && formGroup.enabled && !lockStatus) || lockStatus)"
[vertical]="true" class="ml-2 mr-2">
</mat-divider> -->
<div class="col-auto d-flex align-items-center">
<!-- <button [disabled]="saving" *ngIf="isDirty()" type="button" mat-raised-button class="discard-btn mr-3" (click)="discard()">
{{'DMP-EDITOR.ACTIONS.DISCARD' | translate}}
</button> -->
<button [disabled]="saving" *ngIf="isNew" mat-raised-button type="button" (click)="save()" class="save-btn">
{{'DMP-EDITOR.ACTIONS.SAVE' | translate}}
</button>
<!-- <div *ngIf="!isNew && formGroup.enabled && !lockStatus">
<button [disabled]="saving" *ngIf="!isFinalized" mat-raised-button (click)="formSubmit()" class="save-btn">
{{'DMP-EDITOR.ACTIONS.SAVE' | translate}}
</button>
</div> -->
<!-- <button *ngIf="lockStatus" mat-raised-button disabled class="dataset-save-btn cursor-default" type="button">{{ 'DMP-OVERVIEW.LOCKED' | translate}}</button> -->
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-auto dmp-stepper">
<div class="stepper-title">DMP Blueprint</div>
<div class="stepper-options">
<ol class="stepper-list" start="0">
<li (click)="changeStep(0)" [ngClass]="{'active': this.step === 0}">Select Blueprint</li>
<div *ngIf="selectedDmpBlueprintDefinition && this.step !== 0">
<li (click)="changeStep(i + 1)" *ngFor="let section of selectedDmpBlueprintDefinition.sections; let i=index" [ngClass]="{'active': this.step === (i + 1)}">{{section.label}}</li>
</div>
</ol>
</div>
<div class="stepper-actions" *ngIf="this.step !== 0">
<div mat-raised-button type="button" class="col-auto previous stepper-btn mr-2 ml-auto" [ngClass]="{'previous-disabled': this.step === 0}" (click)="previousStep()">
<span class="material-icons">chevron_left</span>
<div>{{'DMP-EDITOR.STEPPER.PREVIOUS' | translate}}</div>
</div>
<div *ngIf="this.step < this.maxStep" mat-raised-button type="button" class="col-auto stepper-btn ml-auto" [ngClass]="{ 'next-disabled': this.step === this.maxStep, 'next': this.step < stepsBeforeDatasets, 'dataset-next': this.step >= stepsBeforeDatasets }" (click)="nextStep()">
<div>{{'DMP-EDITOR.STEPPER.NEXT' | translate}}</div>
<span class="material-icons">chevron_right</span>
</div>
<!-- <div *ngIf="this.step >= 3 && hasProfile() && !isFinalized" mat-raised-button type="button" class="col-auto stepper-btn add-dataset-btn ml-auto" (click)="addDataset()" target="_blank"> -->
<button [disabled]="saving" *ngIf="this.step >= this.maxStep && !isFinalized" mat-raised-button type="button" class="col-auto stepper-btn add-dataset-btn ml-auto" (click)="addDataset()" target="_blank">
<!-- <mat-icon>add</mat-icon> -->
{{'DMP-EDITOR.ACTIONS.SAVE' | translate}} & {{'DMP-LISTING.ACTIONS.ADD-DESCRIPTION-SHORT' | translate}}
</button>
</div>
<div class="col-auto pr-0" *ngIf="this.step !== 0">
<app-form-progress-indication class="col-12" *ngIf="formGroup && !formGroup.disabled && !lockStatus" [formGroup]="formGroup" [isDmpEditor]="true"></app-form-progress-indication>
</div>
</div>
<div class="col-auto form" id="editor-form">
<div class="col-12 blueprint-section" [hidden]="this.step !== 0">
<div class="dmp-blueprint-form">
<mat-form-field>
<app-single-auto-complete [required]="false" [formControl]="formGroup.get('profile')" placeholder="Select blueprint" [configuration]="dmpBlueprintAutoCompleteConfiguration">
</app-single-auto-complete>
</mat-form-field>
</div>
<div class="row">
<div class="col-5">
<button mat-button class="action-btn" [disabled]="selectedDmpBlueprintDefinition == null" (click)="selectBlueprint()">Next</button>
</div>
<div class="col-7" *ngIf="formGroup.get('profile').value == null || (formGroup.get('profile').value && formGroup.get('profile').value.id !== '86635178-36a6-484f-9057-a934e4eeecd5')">
<div class="row">
<div class="col-6">
<p>or continue with</p>
</div>
<div class="col-6">
<button mat-button class="action-btn" style="float: right;" (click)="selectDefaultBlueprint()">Default Blueprint</button>
</div>
</div>
</div>
</div>
</div>
<div *ngIf="selectedDmpBlueprintDefinition">
<div *ngFor="let section of selectedDmpBlueprintDefinition.sections; let i=index">
<div class="section-info" [hidden]="this.step !== (i + 1)">
<div class="col-12 intro">
{{section.description}}
</div>
<div class="col-12 card">
<div class="row">
<div class="col-12">
<div *ngFor="let field of section.systemFields; let j=index">
<div class="heading">{{i + 1}}.{{j + 1}} {{field.label}}<span *ngIf="field.required">*</span></div>
<div *ngIf="field.description != null && field.description.length > 0" class="hint">{{field.description}}</div>
<div class="input-form">
<div *ngIf="field.type == 'TEXT'">
<mat-form-field>
<input matInput placeholder="{{'DMP-EDITOR.FIELDS.NAME' | translate}}" 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> -->
</mat-form-field>
</div>
<div *ngIf="field.type == 'HTML_TEXT'">
<rich-text-editor-component [parentFormGroup]="formGroup" [controlName]="'description'"
[placeholder]="'DMP-EDITOR.PLACEHOLDER.DESCRIPTION'">
</rich-text-editor-component>
</div>
<div *ngIf="field.type == 'RESEARCHERS'">
<mat-form-field>
<mat-label>{{'DMP-EDITOR.PLACEHOLDER.RESEARCHERS' | translate}}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('researchers')" [configuration]="researchersAutoCompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('researchers').hasError('backendError')">
{{formGroup.get('researchers').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('researchers').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<!-- <button matSuffix class="input-btn" [disabled]="formGroup.get('researchers').disabled" type="button" (click)="addResearcher($event)">
<mat-icon class="icon-btn">add_circle</mat-icon>
</button> -->
</mat-form-field>
<div class="mb-4">
<span *ngIf="!formGroup.get('researchers').disabled" class="not-found">{{'DMP-EDITOR.FUNDING-INFO.FIND' | translate}}</span>
<span *ngIf="!formGroup.get('researchers').disabled" class="insert-manually" (click)="addResearcher($event)">{{'DMP-EDITOR.ACTIONS.INSERT-MANUALLY' | translate}}</span>
</div>
</div>
<div *ngIf="field.type == 'ORGANIZATIONS'">
<mat-form-field>
<mat-label>{{'DMP-EDITOR.PLACEHOLDER.ORGANIZATION' | translate}}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('organisations')" [configuration]="organisationsAutoCompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('organisations').hasError('backendError')">
{{formGroup.get('organisations').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('organisations').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<!-- <button *ngIf="showOrganizationCreator()" matSuffix class="input-btn" [disabled]="cantAddOrganizations()" type="button" (click)="addOrganization($event)">
<mat-icon class="icon-btn">add_circle</mat-icon>
</button> -->
</mat-form-field>
<div *ngIf="showOrganizationCreator()" class="mb-4">
<span *ngIf="!cantAddOrganizations()" class="not-found">{{'DMP-EDITOR.FUNDING-INFO.FIND' | translate}}</span>
<span *ngIf="!cantAddOrganizations()" class="insert-manually" (click)="addOrganization($event)">{{'DMP-EDITOR.ACTIONS.INSERT-MANUALLY' | translate}}</span>
</div>
</div>
<div *ngIf="field.type == 'LANGUAGE'">
<mat-form-field>
<mat-select [formControl]="formGroup.get('extraProperties').get('language')" placeholder="{{'DMP-EDITOR.FIELDS.LANGUAGE' | translate}}" required>
<mat-option *ngFor="let lang of getLanguageInfos()" [value]="lang.code">
{{ lang.name }}
</mat-option>
</mat-select>
<mat-error *ngIf="formGroup.get('extraProperties').get('language').hasError('backendError')">
{{formGroup.get('extraProperties').get('language').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('extraProperties').get('language').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div *ngIf="field.type == 'CONTACT'">
<div class="contact-form">
<mat-form-field>
<mat-select [formControl]="formGroup.get('extraProperties').get('contact')" placeholder="{{'DMP-EDITOR.FIELDS.CONTACT' | translate}}">
<mat-option *ngFor="let vis of getAssociates()" [value]="vis.id">
{{vis.name | translate}}
</mat-option>
</mat-select>
<mat-error *ngIf="formGroup.get('extraProperties').get('contact').hasError('backendError')">
{{formGroup.get('extraProperties').get('contact').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('extraProperties').get('contact').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
<div *ngIf="field.type == 'FUNDER'">
<funding-info [formGroup]="formGroup" [grantformGroup]="formGroup.get('grant')" [projectFormGroup]="formGroup.get('project')" [funderFormGroup]="formGroup.get('funder')" [isFinalized]="false" [isNew]="true" [isUserOwner]="true" [type]="1" (onFormChanged)="formChanged()"></funding-info>
</div>
<div *ngIf="field.type == 'GRANT'">
<funding-info [formGroup]="formGroup" [grantformGroup]="formGroup.get('grant')" [projectFormGroup]="formGroup.get('project')" [funderFormGroup]="formGroup.get('funder')" [isFinalized]="false" [isNew]="true" [isUserOwner]="true" [type]="2" (onFormChanged)="formChanged()"></funding-info>
</div>
<div *ngIf="field.type == 'PROJECT'">
<funding-info [formGroup]="formGroup" [grantformGroup]="formGroup.get('grant')" [projectFormGroup]="formGroup.get('project')" [funderFormGroup]="formGroup.get('funder')" [isFinalized]="false" [isNew]="true" [isUserOwner]="true" [type]="3" (onFormChanged)="formChanged()"></funding-info>
</div>
<div *ngIf="field.type == 'LICENSE'">
<mat-form-field>
<app-single-auto-complete [formControl]="formGroup.get('extraProperties').get('license')" placeholder="{{'DMP-EDITOR.FIELDS.LICENSE' | translate}}" [configuration]="licenseAutoCompleteConfiguration">
</app-single-auto-complete>
<mat-error *ngIf="formGroup.get('extraProperties').get('license').hasError('backendError')">
{{formGroup.get('extraProperties').get('license').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('extraProperties').get('license').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div *ngIf="field.type == 'ACCESS_RIGHTS'">
<mat-form-field>
<mat-select [formControl]="formGroup.get('extraProperties').get('visible')" placeholder="{{'DMP-EDITOR.FIELDS.VISIBILITY' | translate}}">
<mat-option *ngFor="let vis of visibles" [value]="vis.value">
{{vis.name | translate}}
</mat-option>
</mat-select>
<mat-error *ngIf="formGroup.get('extraProperties').get('visible').hasError('backendError')">
{{formGroup.get('extraProperties').get('visible').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('extraProperties').get('visible').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div *ngIf="field.type == 'DESCRIPTION_TEMPLATES'">
<mat-form-field>
<mat-label>{{'DMP-EDITOR.FIELDS.SELECT-TEMPLATE' | translate}}</mat-label>
<app-multiple-auto-complete placeholder="{{'DMP-EDITOR.FIELDS.SELECT-TEMPLATE' | translate}}" [hidePlaceholder]="true" required='true' [formControl]="formGroup.get('profiles')" [configuration]="profilesAutoCompleteConfiguration" (optionRemoved)="onRemoveTemplate($event)" (optionActionClicked)="onPreviewTemplate($event)" (optionSelected)="onOptionSelected()">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('profiles').hasError('backendError')">
{{formGroup.get('profiles').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('profiles').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<button matSuffix class="input-btn" [disabled]="formGroup.get('profiles').disabled" (click)="allAvailableProfiles($event)">
<mat-icon class="icon-btn">view_list</mat-icon>
</button>
</mat-form-field>
<div class="col pl-0 pt-2 pb-3 d-flex">
<span class="not-found">{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.SECOND-STEP.FIELDS.HELP' | translate}}</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-12">
<div *ngFor="let extraField of section.extraFields; let k=index">
<div class="heading">{{i + 1}}.{{k + 1}} {{extraField.label}}<span *ngIf="extraField.required">*</span></div>
<div *ngIf="extraField.description != null && extraField.description.length > 0" class="hint">{{extraField.description}}</div>
<div class="input-form">
<div *ngIf="extraField.type == 'TEXT'">
<mat-form-field>
<input matInput placeholder="extraField.placeholder" type="text" name="label" [formControl]="label" [required]="extraField.required">
</mat-form-field>
</div>
<div *ngIf="extraField.type == 'RICH_TEXT'">
<mat-form-field>
<!-- <rich-text-editor-component [parentFormGroup]="formGroup" [controlName]="'label'"
[placeholder]="extraField.placeholder">
</rich-text-editor-component> -->
</mat-form-field>
</div>
<div *ngIf="extraField.type == 'DATE'">
<mat-form-field>
<input matInput placeholder="extraField.placeholder" type="date" name="label" [formControl]="label" [required]="extraField.required">
</mat-form-field>
</div>
<div *ngIf="extraField.type == 'NUMBER'">
<mat-form-field>
<input matInput placeholder="extraField.placeholder" type="number" name="label" [formControl]="label" [required]="extraField.required">
</mat-form-field>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,378 @@
@media (max-width: 768px) {
.main-content {
padding: 30px 0px;
}
button {
font-size: small;
}
}
.form-container {
height: calc(100vh - 124px);
margin-top: 6rem;
}
.fixed-editor-header {
// position: fixed;
// width: calc(100% - 310px);
z-index: 3;
background-color: whitesmoke;
}
.editor-header {
height: 64px;
background: var(--unnamed-color-var(--primary-color)) 0% 0% no-repeat padding-box;
background: var(--primary-color) 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #00000029;
padding: 0.6rem;
margin: 30px 0px 0px 0px;
border-radius: 4px;
opacity: 1;
.info {
flex: 2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.title {
text-align: left;
font-weight: 400;
font-size: 14px;
color: #ffffff;
opacity: 0.75;
}
.subtitle {
text-align: left;
color: #ffffff;
font-weight: 700;
font-size: 16px;
opacity: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.save-btn, .dmp-export-btn {
background: #ffffff 0% 0% no-repeat padding-box !important;
border-radius: 30px;
opacity: 1;
width: 110px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
font-weight: 700;
color: var(--primary-color);
}
.dmp-stepper {
position: fixed;
// height: 100%;
display: flex;
flex-direction: column;
height: calc(100vh - 190px);
overflow-y: auto;
}
.stepper-title {
text-align: left;
font-weight: 300;
font-size: 20px;
letter-spacing: 0px;
color: #212121;
opacity: 0.6;
margin: 2.875rem 0rem 2.875rem 0rem;
padding-left: 1rem;
}
.stepper-list li {
text-align: left;
font-weight: 400;
letter-spacing: 0px;
color: #212121;
padding: 0.3rem 0.1rem;
opacity: 0.6;
cursor: pointer;
max-width: 290px;
}
.stepper-list li:hover {
background-color: #ececec;
border-radius: 6px;
}
.stepper-list .active {
color: #212121;
font-weight: 700;
opacity: 1;
}
.stepper-list .active-dataset {
color: #212121;
font-weight: 700;
opacity: 1;
.label {
width: 100%;
height: 27px;
line-height: 27px;
background-color: var(--secondary-color);
color: #5d5d5d;
border-radius: 4px;
font-weight: 400;
font-size: 14px;
justify-content: left;
display: flex;
align-items: center;
padding-left: 0.625rem;
padding-right: 0.625rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
}
}
mat-icon.size-16 {
width: 16px;
height: 16px;
line-height: 16px;
font-size: 16px;
margin-top: 0.4rem;
}
.remove-dataset {
color: #f16868;
}
.remove-dataset:hover {
color: #f16868;
}
.stepper-actions {
display: flex;
padding-left: 1rem;
margin-top: auto;
margin-bottom: 0.5rem;
// margin-top: 5rem;
// flex-grow: 8;
}
.stepper-btn {
border-radius: 30px;
opacity: 1;
width: 154px;
min-height: 40px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
}
.previous {
color: #212121;
background: #f5f5f5 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #1e202029;
border: 2px solid #212121;
font-weight: 500;
cursor: pointer;
}
.add-dataset-btn {
background: var(--secondary-color) 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #1e202029;
font-weight: 500;
white-space: normal;
word-wrap: break-word;
line-height: normal;
text-align: left;
font-size: 13.8px;
}
.add-dataset-action {
display: flex;
align-items: center;
cursor: pointer;
}
.next {
background: var(--primary-color) 0% 0% no-repeat padding-box;
color: white;
box-shadow: 0px 3px 6px #1e202029;
font-weight: 400;
cursor: pointer;
}
.dataset-next {
background: var(--secondary-color) 0% 0% no-repeat padding-box;
color: #212121;
box-shadow: 0px 3px 6px #1e202029;
font-weight: 700;
cursor: pointer;
}
.previous-disabled,
.add-dataset-btn-disabled {
border: 1px solid #b5b5b5;
color: #b5b5b5 !important;
cursor: auto !important;
}
.next-disabled {
background: #cbcbcb 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #1e202029;
color: white;
cursor: auto !important;
}
.form {
// position: relative;
// left: 362px;
// width: calc(100% - 366px);
position: relative;
left: 362px;
width: calc(100% - 366px);
overflow-y: auto;
height: calc(100vh - 218px);
}
.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;
}
}
.blueprint-section {
text-align: left;
font-weight: 400;
letter-spacing: 0px;
color: #212121;
opacity: 1;
margin: 3rem 0rem 3rem 0rem;
}
a {
color: #000000;
}
a:hover {
color: var(--primary-color-3);
}
.main-content {
height: 100vh !important;
margin-top: -80px;
}
.dmp-blueprint-form {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0.15px;
color: #7d7d7d;
opacity: 1;
margin-bottom: 1rem;
}
.section-info {
.intro {
text-align: left;
font-weight: 400;
letter-spacing: 0px;
color: #212121;
opacity: 1;
margin: 3rem 0rem 3rem 0rem;
}
.heading {
text-align: left;
font-weight: 700;
font-size: 18px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-top: 1.625rem;
margin-bottom: 0.625rem;
}
.hint {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-bottom: 2.125rem;
}
.input-form {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0.15px;
color: #7d7d7d;
opacity: 1;
margin-bottom: 1rem;
}
.insert-manually {
text-decoration: underline;
color: var(--primary-color-3);
cursor: pointer;
font-size: 1rem;
font-weight: 400;
}
.not-found {
// cursor: pointer;
font-size: 1rem;
font-weight: 400;
padding: 0rem 0.5rem 0rem 0rem;
}
.disabled-toggle {
font-size: 1rem;
font-weight: 400;
padding: 0rem 0.5rem 0rem 0rem;
color: #e0e0e0 !important;
text-decoration: none;
}
.input-btn {
border: none;
color: #aaaaaa;
background-color: #ffffff00;
cursor: pointer;
}
.input-btn :hover {
color: var(--primary-color-3) !important;
}
}
::ng-deep .input-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .input-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}

View File

@ -0,0 +1,777 @@
import { Component, OnInit } from '@angular/core';
import { AbstractControl, FormArray, FormControl, FormGroup, Validators } from '@angular/forms';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DmpBlueprintDefinition, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint';
import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria';
import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { DmpBlueprintEditor } from '@app/ui/admin/dmp-profile/editor/dmp-blueprint-editor.model';
import { debounceTime, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators';
import { DmpEditorModel } from '../editor/dmp-editor.model';
import { ExtraPropertiesFormModel } from '../editor/general-tab/extra-properties-form.model';
import { FunderFormModel } from '../editor/grant-tab/funder-form-model';
import { GrantTabModel } from '../editor/grant-tab/grant-tab-model';
import { ProjectFormModel } from '../editor/grant-tab/project-form-model';
import { AuthService } from '@app/core/services/auth/auth.service';
import { BaseComponent } from '@common/base/base.component';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { LanguageInfoService } from '@app/core/services/culture/language-info-service';
import { LanguageInfo } from '@app/core/model/language-info';
import { UserModel } from '@app/core/model/user/user';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { TranslateService } from '@ngx-translate/core';
import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service';
import { Observable } from 'rxjs';
import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item';
import { OrganisationService } from '@app/core/services/organisation/organisation.service';
import { MatDialog } from '@angular/material/dialog';
import { AddResearcherComponent } from '../editor/add-researcher/add-researcher.component';
import { AddOrganizationComponent } from '../editor/add-organization/add-organization.component';
import { RequestItem } from '@app/core/query/request-item';
import { LicenseCriteria } from '@app/core/query/license/license-criteria';
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { AvailableProfilesComponent } from '../editor/available-profiles/available-profiles.component';
import { DatasetPreviewDialogComponent } from '../dataset-preview/dataset-preview-dialog.component';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { Router } from '@angular/router';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { DmpToDatasetDialogComponent } from '../dmp-to-dataset/dmp-to-dataset-dialog.component';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { FormService } from '@common/forms/form-service';
interface Visible {
value: boolean;
name: string;
}
@Component({
selector: 'app-dmp-editor-blueprint',
templateUrl: './dmp-editor-blueprint.component.html',
styleUrls: ['./dmp-editor-blueprint.component.scss']
})
export class DmpEditorBlueprintComponent extends BaseComponent implements OnInit {
saving = false;
isNew = true;
isUserOwner: boolean = true;
isNewVersion = false;
isFinalized = false;
isClone = false;
hasChanges = false;
isDiscarded = false;
isCreateNew = false;
isCreateNewProject = false;
isCreateNewFunder = false;
dmp: DmpEditorModel;
formGroup: FormGroup = null;
formGroupRawValue: any;
associatedUsers: Array<UserModel>;
people: Array<UserInfoListingModel>;
lockStatus: Boolean = false;
step: number = 0;
stepsBeforeDatasets: number = 4;
maxStep: number = 4;
scrollTop: number;
hintErrors: boolean = false;
selectedDmpBlueprintDefinition: DmpBlueprintDefinition = null;
private associates: UserModel[] = [];
visibles: Visible[] = [
{ value: true, name: 'DMP-EDITOR.VISIBILITY.PUBLIC' },
{ value: false, name: 'DMP-EDITOR.VISIBILITY.RESTRICTED' }
]
licenseAutoCompleteConfiguration: SingleAutoCompleteConfiguration = {
filterFn: this.licenseSearch.bind(this),
initialItems: (excludedItems: any[]) => this.licenseSearch('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['name'],
titleFn: (item) => item['name']
};
profilesAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
constructor(
private dmpProfileService: DmpProfileService,
private authService: AuthService,
private router: Router,
private configurationService: ConfigurationService,
private languageInfoService: LanguageInfoService,
private language: TranslateService,
private externalSourcesService: ExternalSourcesService,
private organizationService: OrganisationService,
private dmpService: DmpService,
private uiNotificationService: UiNotificationService,
private formService: FormService,
private dialog: MatDialog
) {
super();
}
ngOnInit(): void {
this.dmp = new DmpEditorModel();
this.dmp.grant = new GrantTabModel();
this.dmp.project = new ProjectFormModel();
this.dmp.funder = new FunderFormModel();
this.dmp.extraProperties = new ExtraPropertiesFormModel();
this.dmp.extraProperties.visible = false;
this.dmp.extraProperties.contact = this.authService.current().id;
this.formGroup = this.dmp.buildForm();
this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
if (this.formGroup.get('profile')) { this.selectedDmpBlueprintDefinition = this.formGroup.get('profile').value; }
this.registerFormEventsForDmpBlueprint();
if (!this.isUserOwner) {
this.formGroup.disable();
}
if (isNullOrUndefined(this.formGroup.get('extraProperties').get('publicDate').value)) {
this.formGroup.get('extraProperties').get('publicDate').patchValue(new Date());
}
const principal = this.authService.current();
let associate: UserModel = {
id: principal.id,
name: principal.name,
appRoles: principal.authorities,
email: principal.email
};
this.associates.push(associate);
if (isNullOrUndefined(this.formGroup.get('extraProperties').get('contact').value)) {
this.formGroup.get('extraProperties').get('contact').patchValue(associate.id);
}
if (isNullOrUndefined(this.formGroup.get('extraProperties').get('language').value)) {
this.formGroup.get('extraProperties').get('language').patchValue('en');
}
try{
const profiles = this.formGroup.get('profiles').value as {id:string, label:string}[];
profiles.sort((a,b)=>a.label.localeCompare(b.label));
}catch{
console.info('Could not sort profiles');
}
this.profilesAutoCompleteConfiguration = {
filterFn: this.filterProfiles.bind(this),
initialItems: (excludedItems: any[]) => this.filterProfiles('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
subtitleFn: (item) => item['description'],
popupItemActionIcon: 'visibility'
};
}
save() {
this.formSubmit(true);
}
formSubmit(addNew?: boolean, showAddDatasetDialog?: boolean): void {
this.saving = true;
this.formService.touchAllFormFields(this.formGroup);
if(!this._isDMPDescriptionValid()){
const errmess = this._buildDMPDescriptionErrorMessages();
this.showValidationErrorsDialog(undefined, errmess);
this.hintErrors = true;
this.saving = false;
return;
}
this.onSubmit(addNew, showAddDatasetDialog);
}
public formChanged() {
if (!this.isDiscarded) {
this.hasChanges = true;
}
}
selectDefaultBlueprint() {
this.dmpProfileService.getSingleBlueprint('86635178-36a6-484f-9057-a934e4eeecd5')
.pipe(takeUntil(this._destroyed))
.subscribe(result => {
this.selectedDmpBlueprintDefinition = result.definition;
this.formGroup.get('profile').setValue(result);
this.maxStep = this.selectedDmpBlueprintDefinition.sections.length;
this.nextStep();
});
}
selectBlueprint() {
this.maxStep = this.selectedDmpBlueprintDefinition.sections.length;
this.nextStep();
}
nextStep() {
this.step = this.step < this.maxStep ? this.step + 1 : this.step;
this.resetScroll();
// if (this.step >= this.stepsBeforeDatasets) {
// this.datasetId = this.datasets.at(this.step - this.stepsBeforeDatasets).get('id').value;
// }
}
previousStep() {
this.step = this.step !== 0 ? this.step - 1 : this.step;
this.resetScroll();
// if (this.step >= this.stepsBeforeDatasets) {
// this.datasetId = this.datasets.at(this.step - this.stepsBeforeDatasets).get('id').value;
// }
}
changeStep(index: number, dataset?: FormControl) {
this.step = index;
this.resetScroll();
// if (dataset) { this.datasetId = dataset.get('id').value };
}
private resetScroll() {
document.getElementById('editor-form').scrollTop = 0;
}
addDataset() {
this.saving = true;
if(!this._isDMPDescriptionValid()){
const errmess = this._buildDMPDescriptionErrorMessages();
this.showValidationErrorsDialog(undefined, errmess);
this.hintErrors = true;
this.saving = false;
return;
}
// const showDialog = this.hasProfile() && this.isNew;
this.onSubmit(true, false);
// this.formSubmit(true, false);
// Add dataset to list
// if (!this.formGroup.get('datasets')) {
// this.formGroup.addControl('datasets', new FormBuilder().array(new Array<FormControl>()));
// }
// this.formGroup.get('datasets')['controls'].push(new DatasetWizardEditorModel().buildForm());
// this.datasets = this.formGroup.get('datasets') as FormArray;
// this.step = this.stepsBeforeDatasets + this.formGroup.get('datasets')['controls'].length - 1;
// this.maxStep = this.maxStep + this.formGroup.get('datasets')['controls'].length - 1;
}
onSubmit(addNew?: boolean, showAddDatasetDialog?: boolean): void {
this.scrollTop = document.getElementById('editor-form').scrollTop;
// return;
this.dmpService.createDmp(this.formGroup.getRawValue())
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => {
this.formGroup.get('id').setValue(complete.id);
this.formGroup.get('modified').setValue(complete.modified);
this.hasChanges = false;
if (showAddDatasetDialog) {
this.addDatasetOpenDialog(complete);
}
if (addNew) {
this.onCallbackSuccessAddNew(complete);
}
else { this.onCallbackSuccess(complete) }
},
error => {
this.formGroup.get('status').setValue(DmpStatus.Draft);
this.onCallbackError(error);
}
);
// this.dmpService.createDmpWithDatasets(this.formGroup.getRawValue())
// .pipe(takeUntil(this._destroyed))
// .subscribe(
// complete => {
// if (showAddDatasetDialog) {
// this.addDatasetOpenDialog(complete);
// }
// else if (this.step < this.stepsBeforeDatasets) { this.onCallbackSuccess(complete) }
// else { this.onCallbackSuccess(complete, this.datasetId) }
// },
// error => {
// this.formGroup.get('status').setValue(DmpStatus.Draft);
// this.onCallbackError(error);
// }
// )
}
addDatasetOpenDialog(dmp: DmpModel) {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
maxWidth: '500px',
restoreFocus: false,
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ADD-DATASET'),
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.NO'),
isDeleteConfirmation: false
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
// this.router.navigate(['datasets/new/' + id]);
this.addDataset();
} else {
dmp.id != null ? this.router.navigate(['/plans', 'edit', dmp.id]) : this.router.navigate(['/plans']);
}
});
}
onCallbackSuccess(dmp?: DmpModel, datasetId?: string): void {
// On save keep editor position
this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
if (dmp) {
let dmpEditorModel: DmpEditorModel;
dmpEditorModel = new DmpEditorModel();
dmpEditorModel.grant = new GrantTabModel();
dmpEditorModel.project = new ProjectFormModel();
dmpEditorModel.funder = new FunderFormModel();
dmpEditorModel.extraProperties = new ExtraPropertiesFormModel();
dmpEditorModel.fromModel(dmp);
this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
this.associatedUsers = dmp.associatedUsers;
this.people = dmp.users;
setTimeout(() => { this.formGroup = null; });
setTimeout(() => {
this.formGroup = dmpEditorModel.buildForm();
this.formGroup.valueChanges.pipe(takeUntil(this._destroyed))
.subscribe(x => {
this.formChanged();
});});
setTimeout(() => { document.getElementById('editor-form').scrollTop = this.scrollTop; });
this.saving = false;
this.isNew = false;
} else {
this.router.navigate(['/reload']).then(() => { this.router.navigate(['/plans']); });
}
// Uncomment to not keep editor position on save
// if (dmp.id != null) {
// datasetId ? this.router.navigate(['/reload']).then(() => { this.router.navigate(['/plans', 'edit', dmp.id], { queryParams: { dataset: datasetId } }); }) : this.router.navigate(['/reload']).then(() => { this.router.navigate(['/plans', 'edit', dmp.id]); })
// } else {
// this.router.navigate(['/reload']).then(() => { this.router.navigate(['/plans']); });
// }
}
onCallbackError(error: any) {
this.uiNotificationService.snackBarNotification(error.error.message, SnackBarNotificationLevel.Error);
this.setErrorModel(error.error);
this.saving = false;
//this.validateAllFormFields(this.formGroup);
}
public setErrorModel(validationErrorModel: ValidationErrorModel) {
Object.keys(validationErrorModel).forEach(item => {
(<any>this.dmp.validationErrorModel)[item] = (<any>validationErrorModel)[item];
});
}
onCallbackSuccessAddNew(dmp?: DmpModel) {
// this.editDataset(dmp.id, true, this.isNew && !this.formGroup.get('datasets').value.length);
this.editDataset(dmp.id, true, false);
this.saving = false;
}
editDataset(id: string, isNew: boolean, showModal:boolean = false) {
if(showModal){
const dialogRef = this.dialog.open(DmpToDatasetDialogComponent, {
width: '500px',
autoFocus: false,
restoreFocus: false,
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
if (isNew) {
this.router.navigate(['/datasets', 'new', id]);
} else {
this.router.navigate(['/datasets', 'edit', id]);
}
}
});
}else{
if (isNew) {
this.router.navigate(['/datasets', 'new', id]);
} else {
this.router.navigate(['/datasets', 'edit', id]);
}
}
}
//checks if the dpm is valid not taking into account the datasets validity
private _isDMPDescriptionValid():boolean{
const form: FormGroup = this.formGroup;
if(form.controls){
return Object.keys(form.controls)
.map(controlName=>{//get validity of each control
if(controlName === 'datasets'){//we dont care if datasets are valid
return true;
}
return !form.get(controlName).invalid;//!! in case the control is disabled, we consider it valid
})
.reduce((isFormValid,isControlValid)=>{//aggregate validities
return isControlValid && isFormValid;
}, true);
}
return true;
}
private showValidationErrorsDialog(projectOnly?: boolean, errmess?: string[]) {
if(errmess){
const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, {
disableClose: true,
autoFocus: false,
restoreFocus: false,
data: {
errorMessages:errmess,
projectOnly: projectOnly
},
});
}else{
const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, {
disableClose: true,
autoFocus: false,
restoreFocus: false,
data: {
formGroup: this.formGroup,
projectOnly: projectOnly
},
});
}
}
private _buildDMPDescriptionErrorMessages(): string[]{//not including datasets
const errmess: string[] = [];
Object.keys(this.formGroup.controls).forEach(controlName=>{
if(controlName != 'datasets' && this.formGroup.get(controlName).invalid){
errmess.push(...this._buildErrorMessagesForAbstractControl(this.formGroup.get(controlName), controlName));
}
})
return errmess;
}
// takes as an input an abstract control and gets its error messages[]
private _buildErrorMessagesForAbstractControl(aControl: AbstractControl, controlName: string):string[]{
const errmess:string[] = [];
if(aControl.invalid){
if(aControl.errors){
//check if has placeholder
if( (<any>aControl).nativeElement !== undefined && (<any>aControl).nativeElement !== null){
const placeholder = this._getPlaceHolder(aControl);
if(placeholder){
controlName = placeholder;
}
}
const errorMessage = this._getErrorMessage(aControl, controlName);
errmess.push(...errorMessage);
}
/*in case the aControl is FormControl then the it should have provided its error messages above.
No need to check case of FormControl below*/
if(aControl instanceof FormGroup){
const fg = aControl as FormGroup;
//check children
Object.keys(fg.controls).forEach(controlName=>{
errmess.push(...this._buildErrorMessagesForAbstractControl(fg.get(controlName), controlName));
});
}else if(aControl instanceof FormArray){
const fa = aControl as FormArray;
fa.controls.forEach((control,index)=>{
errmess.push(... this._buildErrorMessagesForAbstractControl(control, `${controlName} --> ${index+1}`));
});
}
}
return errmess;
}
private _getErrorMessage(formControl: AbstractControl, name: string): string[] {
const errors: string[] = [];
Object.keys(formControl.errors).forEach(key => {
if (key === 'required') { errors.push(this.language.instant(name + ": " + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.REQUIRED'))); }
// if (key === 'required') { errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + this.getPlaceHolder(formControl) + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.REQUIRED')); }
else if (key === 'email') { errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.EMAIL')); }
else if (key === 'min') { errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.MIN-VALUE', { 'min': formControl.getError('min').min })); }
else if (key === 'max') { errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.MAX-VALUE', { 'max': formControl.getError('max').max })); }
else { errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + formControl.errors[key].message); }
});
return errors;
}
private _getPlaceHolder(formControl: any): string {
if (formControl.nativeElement.localName === 'input' || formControl.nativeElement.localName === 'textarea'
|| formControl.nativeElement.localName === 'richTextarea') {
return formControl.nativeElement.getAttribute('placeholder');
} else if (formControl.nativeElement.localName === 'mat-select') {
return formControl.nativeElement.getAttribute('placeholder');
} else if (formControl.nativeElement.localName === 'app-single-auto-complete') {
return (Array.from(formControl.nativeElement.firstChild.children).filter((x: any) => x.localName === 'input')[0] as any).getAttribute('placeholder');
} else if (formControl.nativeElement.localName === 'app-multiple-auto-complete') {
return (Array.from(formControl.nativeElement.firstChild.firstChild.firstChild.children).filter((x: any) => x.localName === 'input')[0] as any).getAttribute('placeholder');
}
}
filterProfiles(value: string): Observable<DatasetProfileModel[]> {
const request = new DataTableRequest<DatasetProfileCriteria>(null, null, { fields: ['+label'] });
const criteria = new DatasetProfileCriteria();
criteria.like = value;
request.criteria = criteria;
return this.dmpService.searchDMPProfiles(request);
}
registerFormEventsForDmpBlueprint(): void {
this.formGroup.get('profile').valueChanges
.pipe(
takeUntil(this._destroyed))
.subscribe(Option => {
if (Option instanceof Object) {
this.selectedDmpBlueprintDefinition = Option.definition;
}
else {
this.selectedDmpBlueprintDefinition = null;
}
})
}
dmpBlueprintAutoCompleteConfiguration: SingleAutoCompleteConfiguration = {
filterFn: this.dmpBlueprintSearch.bind(this),
initialItems: (extraData) => this.dmpBlueprintSearch(''),
displayFn: (item) => item['label'],
titleFn: (item) => item['label']
};
dmpBlueprintSearch(query: string) {
let fields: Array<string> = new Array();
var request = new DataTableRequest<DmpBlueprintCriteria>(0, 10, { fields: fields });
request.criteria = new DmpBlueprintCriteria();
return this.dmpProfileService.getPagedBlueprint(request).pipe(map(x => x.data));
}
getLanguageInfos(): LanguageInfo[] {
return this.languageInfoService.getLanguageInfoValues();
}
getAssociates(): UserModel[] {
let associates: UserModel[];
if (this.formGroup.get('associatedUsers').value && this.formGroup.get('associatedUsers').value.length > 0) {
associates = [];
} else {
associates = this.associates;
}
//associates = (this.formGroup.get('researchers').value as any[]);
associates = associates.concat(this.formGroup.get('associatedUsers').value);
return associates;
}
organisationsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterOrganisations.bind(this),
initialItems: (excludedItems: any[]) => this.filterOrganisations('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['name'],
titleFn: (item) => item['name'],
subtitleFn: (item) => item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'))
};
researchersAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterResearchers.bind(this),
initialItems: (excludedItems: any[]) => this.filterResearchers('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['name'],
titleFn: (item) => item['name'],
subtitleFn: (item) => item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'))
};
// Researchers
filterResearchers(value: string): Observable<ExternalSourceItemModel[]> {
return this.externalSourcesService.searchDMPResearchers({ criteria: { name: value, like: null } });
}
addResearcher(event: MouseEvent) {
event.stopPropagation();
const dialogRef = this.dialog.open(AddResearcherComponent, {
data: this.formGroup.get('researchers')
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
const fullName = result.firstName + " " + result.lastName;
const newItem = {
label: null,
name: fullName,
id: null,
status: 0,
key: "Internal",
reference: result.reference
};
const researchersArray = this.formGroup.get('researchers').value || [];
researchersArray.push(newItem);
this.formGroup.get('researchers').setValue(researchersArray);
}
});
}
// Organizations
showOrganizationCreator(): boolean {
return this.configurationService.allowOrganizationCreator;
}
filterOrganisations(value: string): Observable<ExternalSourceItemModel[]> {
return this.organizationService.searchGeneralOrganisations({ criteria: { labelLike: value } });
}
cantAddOrganizations(): boolean {
if (!isNullOrUndefined(this.formGroup.get('organizations'))) {
return this.formGroup.get('organiztions').disabled;
} else {
return false;
}
}
addOrganization(event: MouseEvent) {
event.stopPropagation();
const dialogRef = this.dialog.open(AddOrganizationComponent, {
data: this.formGroup.get('organisations')
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
const fullName = result.name;
const newItem = {
label: null,
name: fullName,
id: null,
status: 0,
key: "Internal",
reference: result.reference
};
const organizationsArray = this.formGroup.get('organisations').value || [];
organizationsArray.push(newItem);
this.formGroup.get('organisations').setValue(organizationsArray);
}
});
}
showToggleButton() {
return (!this.isFinalized && this.isUserOwner) || this.isClone;
}
licenseSearch(query: string): Observable<ExternalSourceItemModel[]> {
const request = new RequestItem<LicenseCriteria>();
request.criteria = new LicenseCriteria();
request.criteria.like = query;
request.criteria.type = '';
return this.externalSourcesService.searchLicense(request);
}
allAvailableProfiles(event: MouseEvent) {
event.stopPropagation();
const dialogRef = this.dialog.open(AvailableProfilesComponent, {
data: {
profiles: this.formGroup.get('profiles')
}
});
return false;
}
onRemoveTemplate(event) {
let found = false;
const profiles = this.formGroup.get('profiles').value;
this.formGroup.get('datasets')['controls'].forEach(element => {
if (element.get('profile').value.id === event.id) {
found = true;
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-REMOVE-TEMPLATE'), SnackBarNotificationLevel.Success);
}
});
if (found) {
this.formGroup.get('profiles').setValue(profiles);
this.profilesAutoCompleteConfiguration = {
filterFn: this.filterProfiles.bind(this),
initialItems: (excludedItems: any[]) => this.filterProfiles('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
subtitleFn: (item) => item['description'],
popupItemActionIcon: 'visibility'
};
}
}
onPreviewTemplate(event) {
const dialogRef = this.dialog.open(DatasetPreviewDialogComponent, {
width: '590px',
minHeight: '200px',
restoreFocus: false,
data: {
template: event
},
panelClass: 'custom-modalbox'
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
let profiles = this.formGroup.get('profiles').value;
profiles.push(event);
this.formGroup.get('profiles').setValue(profiles);
this.profilesAutoCompleteConfiguration = {
filterFn: this.filterProfiles.bind(this),
initialItems: (excludedItems: any[]) => this.filterProfiles('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
subtitleFn: (item) => item['description'],
popupItemActionIcon: 'visibility'
};
}
});
}
onOptionSelected(){
try{
const profiles = this.formGroup.get('profiles').value as {id:string, label:string}[];
const profileCounts: Map<String, number> = new Map<String, number>();
profiles.forEach((value) => profileCounts.set(value.id, (profileCounts.get(value.id) !== undefined ? profileCounts.get(value.id): 0 ) + 1));
const duplicateProfiles = profiles.filter((value) => {
let isOk = profileCounts.get(value.id) > 1;
if (isOk) {
profileCounts.set(value.id, 0);
}
return isOk;
});
duplicateProfiles.forEach((value) => profiles.splice(profiles.lastIndexOf(value), 1));
profiles.sort((a,b)=> a.label.localeCompare(b.label));
}catch{
console.info('Could not sort Dataset Templates')
}
}
}

View File

@ -57,6 +57,7 @@ import {
} from '../misc/dataset-description-form/components/form-progress-indication/form-progress-indication.module';
import {DatasetPreviewDialogComponent} from './dataset-preview/dataset-preview-dialog.component';
import {RichTextEditorModule} from "@app/library/rich-text-editor/rich-text-editor.module";
import { DmpEditorBlueprintComponent } from './dmp-editor-blueprint/dmp-editor-blueprint.component';
@NgModule({
imports: [
@ -110,7 +111,8 @@ import {RichTextEditorModule} from "@app/library/rich-text-editor/rich-text-edit
FundingInfoComponent,
DatasetInfoComponent,
LicenseInfoComponent,
DatasetPreviewDialogComponent
DatasetPreviewDialogComponent,
DmpEditorBlueprintComponent
],
entryComponents: [
DmpInvitationDialogComponent,

View File

@ -8,6 +8,7 @@ import { DmpOverviewComponent } from './overview/dmp-overview.component';
import { DmpCloneComponent } from './clone/dmp-clone.component';
import { AuthGuard } from '@app/core/auth-guard.service';
import { CanDeactivateGuard } from '@app/library/deactivate/can-deactivate.guard';
import { DmpEditorBlueprintComponent } from './dmp-editor-blueprint/dmp-editor-blueprint.component';
const routes: Routes = [
{
@ -74,9 +75,19 @@ const routes: Routes = [
// breadcrumbs: 'new'
// }
// },
// {
// path: 'new',
// component: DmpEditorComponent,
// canActivate: [AuthGuard],
// data: {
// breadcrumbs: 'new',
// title: 'GENERAL.TITLES.DMP-NEW'
// },
// canDeactivate:[CanDeactivateGuard]
// },
{
path: 'new',
component: DmpEditorComponent,
component: DmpEditorBlueprintComponent,
canActivate: [AuthGuard],
data: {
breadcrumbs: 'new',

View File

@ -1,19 +1,19 @@
<div class="funding-info">
<form *ngIf="grantformGroup" [formGroup]="grantformGroup">
<div class="col-12 intro">
<!-- <div class="col-12 intro">
{{'DMP-EDITOR.FUNDING-INFO.INTRO' | translate}}
</div>
<div class="col-12 card">
<div class="col-12 card"> -->
<!-- Funder Field -->
<div class="row">
<!-- <div class="row">
<div class="col-12">
<div class="heading">2.1 {{'DMP-EDITOR.FIELDS.FUNDING-ORGANIZATIONS' | translate}}*</div>
<div class="hint">
<!-- <div class="pb-1">{{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}}</div> -->
<div class="pb-1">{{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}}</div>
<div class="pb-1">{{'DMP-EDITOR.FIELDS.FUNDER-HINT' | translate}}</div>
<div><span class="material-icons-outlined align-bottom">info</span> {{'DMP-EDITOR.MAIN-INFO.TYPING' | translate}}</div>
</div>
<div class="funder-form">
</div> -->
<div class="funder-form" *ngIf="type == 1">
<div *ngIf="!isCreateNewFunder">
<mat-form-field appearance="outline">
<app-single-auto-complete required='true' [formControl]="funderFormGroup.get('existFunder')" placeholder="{{'DMP-EDITOR.FIELDS.FUNDER' | translate}}" [configuration]="funderAutoCompleteConfiguration">
@ -38,31 +38,32 @@
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
<!-- Toggle Between Add Funder or Use Existing -->
<div class="col d-flex">
<div class="row" *ngIf="showToggleButton()">
<div *ngIf="isCreateNewFunder" (click)="createFunder()">
<span class="insert">{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.EXIST-FUNDER' | translate}}</span>
</div>
<div *ngIf="!isCreateNewFunder">
<span [ngClass]="isNewVersion?'disabled-toggle':'not-found'">{{'DMP-EDITOR.FUNDING-INFO.FIND' | translate}}</span>
<span [ngClass]="isNewVersion?'disabled-toggle':'insert'" (click)="createFunder()">{{'DMP-EDITOR.ACTIONS.INSERT-MANUALLY' | translate}}</span>
<!-- Toggle Between Add Funder or Use Existing -->
<div class="col d-flex">
<div class="row" *ngIf="showToggleButton()">
<div *ngIf="isCreateNewFunder" (click)="createFunder()">
<span class="insert">{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.EXIST-FUNDER' | translate}}</span>
</div>
<div *ngIf="!isCreateNewFunder">
<span [ngClass]="isNewVersion?'disabled-toggle':'not-found'">{{'DMP-EDITOR.FUNDING-INFO.FIND' | translate}}</span>
<span [ngClass]="isNewVersion?'disabled-toggle':'insert'" (click)="createFunder()">{{'DMP-EDITOR.ACTIONS.INSERT-MANUALLY' | translate}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- </div>
</div> -->
<!-- Grant field -->
<div class="row">
<!-- <div class="row">
<div class="col-12">
<div class="heading">2.2 {{'DMP-EDITOR.FIELDS.GRANTS' | translate}}*</div>
<div class="hint">
<!-- <div class="pb-1">{{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}}</div> -->
<div class="pb-1">{{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}}</div>
<div class="pb-1">{{'DMP-EDITOR.FIELDS.GRANTS-HINT' | translate}}</div>
<div><span class="material-icons-outlined align-bottom">info</span> {{'DMP-EDITOR.MAIN-INFO.TYPING' | translate}}</div>
</div>
<div class="grant-form">
</div> -->
<div class="grant-form" *ngIf="type == 2">
<div *ngIf="!isCreateNew">
<mat-form-field appearance="outline">
<app-single-auto-complete required='true' [formControl]="grantformGroup.get('existGrant')" placeholder="{{'DMP-EDITOR.FIELDS.GRANT' | translate}}" [configuration]="grantAutoCompleteConfiguration">
@ -107,18 +108,18 @@
</div>
</div>
</div>
</div>
</div>
<!-- </div>
</div> -->
<!-- Project field-->
<div class="row">
<!-- <div class="row">
<div class="col-12">
<div class="heading">2.3 {{'DMP-EDITOR.FIELDS.PROJECT' | translate}}</div>
<div class="hint">
<!-- <div class="pb-1">{{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}}</div> -->
<div class="pb-1">{{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}}</div>
<div class="pb-1">{{'DMP-EDITOR.FIELDS.PROJECT-HINT' | translate}}</div>
<div><span class="material-icons-outlined align-bottom">info</span> {{'DMP-EDITOR.MAIN-INFO.TYPING' | translate}}</div>
</div>
<div class="project-form">
</div> -->
<div class="project-form" *ngIf="type == 3">
<div *ngIf="!isCreateNewProject">
<mat-form-field appearance="outline">
<app-single-auto-complete [formControl]="projectFormGroup.get('existProject')" placeholder="{{'DMP-EDITOR.FIELDS.PROJECT' | translate}}" [configuration]="projectAutoCompleteConfiguration">
@ -162,9 +163,9 @@
</div>
</div>
</div>
</div>
</div>
</div>
<!-- </div>
</div> -->
<!-- </div> -->
</form>
<!-- <button (click)="consoleForm()" type="button">consoleForm</button> -->
</div>

View File

@ -28,6 +28,8 @@ export class FundingInfoComponent extends BaseComponent implements OnInit {
@Input() isClone: boolean = false;
@Input() isNewVersion: boolean;
@Input() type: number;
@Input() formGroup: FormGroup;
@Input() grantformGroup: FormGroup;
@Input() projectFormGroup: FormGroup;
@ -71,7 +73,7 @@ export class FundingInfoComponent extends BaseComponent implements OnInit {
return '';
}
ngOnInit() {
ngOnInit() {
const grantRequestItem: RequestItem<GrantCriteria> = new RequestItem();
grantRequestItem.criteria = new GrantCriteria();

View File

@ -11,7 +11,7 @@
<a mat-button class="buttonNav navbar-button" routerLink="/plans">{{'NAV-BAR.DMPS' | translate}}</a>
<a mat-button class="buttonNav navbar-button" routerLink="/datasets">{{'NAV-BAR.DATASETS' | translate}}</a>
<a *ngIf="isAdmin()" mat-button class="buttonNav navbar-button" routerLink="/users">{{'NAV-BAR.USERS' | translate}}</a>
<a *ngIf="isAdmin()" mat-button class="buttonNav navbar-button" routerLink="/dmp-profiles">{{'NAV-BAR.DMP-PROFILES' |
<a *ngIf="isAdmin()" mat-button class="buttonNav navbar-button" routerLink="/dmp-profiles">{{'NAV-BAR.DMP-BLUEPRINTS' |
translate}}</a>
<a *ngIf="isAdmin()" mat-button class="buttonNav navbar-button" routerLink="/dataset-profiles">{{'NAV-BAR.DATASETS-ADMIN'
| translate}}</a>

View File

@ -101,7 +101,7 @@
<!-- Admin -->
<!-- <a *ngIf="isAdmin()" mat-button class="buttonNav navbar-button"
routerLink="/users">{{'NAV-BAR.USERS' | translate}}</a>
<a *ngIf="isAdmin()" mat-button class="buttonNav navbar-button" routerLink="/dmp-profiles">{{'NAV-BAR.DMP-PROFILES' |
<a *ngIf="isAdmin()" mat-button class="buttonNav navbar-button" routerLink="/dmp-profiles">{{'NAV-BAR.DMP-BLUEPRINTS' |
translate}}</a>
<a *ngIf="isAdmin()" mat-button class="buttonNav navbar-button" routerLink="/dataset-profiles">{{'NAV-BAR.DATASETS-ADMIN'
| translate}}</a> -->