From 3dd520fea3ee6805e8d897f8872f21b5412db162 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 28 Nov 2019 13:13:33 +0200 Subject: [PATCH 001/106] Refactors RDA export model. --- .../data/rda/ContactIdRDAExportModel.java | 25 -- .../data/rda/ContactRDAExportModel.java | 28 +- .../DatasetDistributionRDAExportModel.java | 121 ++++++++ .../data/rda/DatasetIdRDAExportModel.java | 25 -- .../rda/DatasetMetadataRDAExportModel.java | 14 +- .../data/rda/DatasetRDAExportModel.java | 263 +++++++++++++----- ...tasetSecurityAndPrivacyRDAExportModel.java | 29 ++ ...atasetTechnicalResourceRDAExportModel.java | 29 ++ .../rda/DmpContributorRDAExportModel.java | 52 ++++ .../data/rda/DmpCostRDAExportModel.java | 36 +++ .../models/data/rda/DmpIdRDAExportModel.java | 25 -- .../models/data/rda/DmpRDAExportModel.java | 168 +++++++---- .../data/rda/FunderIdRDAExportModel.java | 25 -- .../data/rda/FundingRDAExportModel.java | 21 +- .../data/rda/GrantIdRDAExportModel.java | 25 -- .../models/data/rda/HostRDAExportModel.java | 86 ++++++ .../models/data/rda/IdRDAExportModel.java | 25 ++ .../data/rda/LicenseRDAExportModel.java | 20 ++ .../eudat/models/data/rda/RDAExportModel.java | 13 - .../src/main/resources/RDACommonStandards.txt | 72 ++--- 20 files changed, 778 insertions(+), 324 deletions(-) delete mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/ContactIdRDAExportModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetDistributionRDAExportModel.java delete mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetIdRDAExportModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetSecurityAndPrivacyRDAExportModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetTechnicalResourceRDAExportModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpContributorRDAExportModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpCostRDAExportModel.java delete mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpIdRDAExportModel.java delete mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/FunderIdRDAExportModel.java delete mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/GrantIdRDAExportModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/HostRDAExportModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/IdRDAExportModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/LicenseRDAExportModel.java diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/ContactIdRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/ContactIdRDAExportModel.java deleted file mode 100644 index 7a6afae46..000000000 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/ContactIdRDAExportModel.java +++ /dev/null @@ -1,25 +0,0 @@ -package eu.eudat.models.data.rda; - -public class ContactIdRDAExportModel { - private String contact_id; - private String contact_id_type; - - public String getContact_id() { - return contact_id; - } - public void setContact_id(String contact_id) { - this.contact_id = contact_id; - } - - public String getContact_id_type() { - return contact_id_type; - } - public void setContact_id_type(String contact_id_type) { - this.contact_id_type = contact_id_type; - } - - ContactIdRDAExportModel(String contact_id, String contact_id_type) { - this.contact_id = contact_id; - this.contact_id_type = contact_id_type; - } -} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/ContactRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/ContactRDAExportModel.java index 2742f5443..6f03ac9f7 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/ContactRDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/ContactRDAExportModel.java @@ -3,15 +3,15 @@ package eu.eudat.models.data.rda; import eu.eudat.data.entities.UserInfo; public class ContactRDAExportModel { - private String mail; + private String mbox; private String name; - private ContactIdRDAExportModel contact_id; + private IdRDAExportModel contact_id; - public String getMail() { - return mail; + public String getMbox() { + return mbox; } - public void setMail(String mail) { - this.mail = mail; + public void setMbox(String mbox) { + this.mbox = mbox; } public String getName() { @@ -21,24 +21,24 @@ public class ContactRDAExportModel { this.name = name; } - public ContactIdRDAExportModel getContact_id() { + public IdRDAExportModel getContact_id() { return contact_id; } - public void setContact_id(ContactIdRDAExportModel contact_id) { + public void setContact_id(IdRDAExportModel contact_id) { this.contact_id = contact_id; } - public ContactRDAExportModel fromDataModel(UserInfo entity) { - this.mail = entity.getEmail(); - this.name = entity.getName(); + ContactRDAExportModel contact = new ContactRDAExportModel(); + contact.mbox = entity.getEmail(); + contact.name = entity.getName(); // TODO: we should use a contact_id and not our UUID. if (!entity.getId().toString().isEmpty()) { - this.contact_id = new ContactIdRDAExportModel(entity.getId().toString(), "argos_internal"); + contact.contact_id = new IdRDAExportModel(entity.getId().toString(), "other"); } else { - this.contact_id = null; + contact.contact_id = null; } - return this; + return contact; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetDistributionRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetDistributionRDAExportModel.java new file mode 100644 index 000000000..067b1aa0f --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetDistributionRDAExportModel.java @@ -0,0 +1,121 @@ +package eu.eudat.models.data.rda; + +import java.util.List; + +public class DatasetDistributionRDAExportModel { + private String access_url; + private String available_till; + private int byte_size; + private String data_access; // Allowed values: open / shared / closed + private String description; + private String download_url; + private List format; // Format according to: https://www.iana.org/assignments/media-types/media-types.xhtml if appropriate, otherwise use the common name for this format + private HostRDAExportModel host; + private List license; + private String title; + + public String getAccess_url() { + return access_url; + } + public void setAccess_url(String access_url) { + this.access_url = access_url; + } + + public String getAvailable_till() { + return available_till; + } + public void setAvailable_till(String available_till) { + this.available_till = available_till; + } + + public int getByte_size() { + return byte_size; + } + public void setByte_size(int byte_size) { + this.byte_size = byte_size; + } + + public String getData_access() { + return data_access; + } + public void setData_access(String data_access) { + this.data_access = data_access; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public String getDownload_url() { + return download_url; + } + public void setDownload_url(String download_url) { + this.download_url = download_url; + } + + public List getFormat() { + return format; + } + public void setFormat(List format) { + this.format = format; + } + + public HostRDAExportModel getHost() { + return host; + } + public void setHost(HostRDAExportModel host) { + this.host = host; + } + + public List getLicense() { + return license; + } + public void setLicense(List license) { + this.license = license; + } + + public String getTitle() { + return title; + } + public void setTitle(String title) { + this.title = title; + } + + public DatasetDistributionRDAExportModel fromDataModel(String key, Object value) { + DatasetDistributionRDAExportModel distributionModel = new DatasetDistributionRDAExportModel(); + switch (key) { + case "access_url": + distributionModel.setAccess_url(value.toString()); + break; + case "available_till": + distributionModel.setAvailable_till(value.toString()); + break; + case "byte_size": + try { distributionModel.setByte_size(Integer.parseInt(value.toString())); } + catch (NumberFormatException e) { e.printStackTrace(); } + break; + case "data_access": + distributionModel.setData_access(value.toString()); + break; + case "description": + distributionModel.setDescription(value.toString()); + break; + case "download_url": + distributionModel.setDownload_url(value.toString()); + break; + case "format": + break; + case "host": + break; + case "license": + break; + case "title": + distributionModel.setTitle(value.toString()); + break; + } + return distributionModel; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetIdRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetIdRDAExportModel.java deleted file mode 100644 index 0267514c5..000000000 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetIdRDAExportModel.java +++ /dev/null @@ -1,25 +0,0 @@ -package eu.eudat.models.data.rda; - -public class DatasetIdRDAExportModel { - private String dataset_id; - private String dataset_id_type; - - public String getDataset_id() { - return dataset_id; - } - public void setDataset_id(String dataset_id) { - this.dataset_id = dataset_id; - } - - public String getDataset_id_type() { - return dataset_id_type; - } - public void setDataset_id_type(String dataset_id_type) { - this.dataset_id_type = dataset_id_type; - } - - DatasetIdRDAExportModel(String dataset_id, String dataset_id_type) { - this.dataset_id = dataset_id; - this.dataset_id_type = dataset_id_type; - } -} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetMetadataRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetMetadataRDAExportModel.java index 9a70ed7d2..dc5814375 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetMetadataRDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetMetadataRDAExportModel.java @@ -3,7 +3,7 @@ package eu.eudat.models.data.rda; public class DatasetMetadataRDAExportModel { private String description; // Not mandatory. private String language; - private DatasetMetadataIdRDAExportModel metadata_id; + private IdRDAExportModel metadata_standard_id; public String getDescription() { return description; @@ -19,17 +19,17 @@ public class DatasetMetadataRDAExportModel { this.language = language; } - public DatasetMetadataIdRDAExportModel getMetadata_id() { - return metadata_id; + public IdRDAExportModel getMetadata_standard_id() { + return metadata_standard_id; } - public void setMetadata_id(DatasetMetadataIdRDAExportModel metadata_id) { - this.metadata_id = metadata_id; + public void setMetadata_standard_id(IdRDAExportModel metadata_standard_id) { + this.metadata_standard_id = metadata_standard_id; } public DatasetMetadataRDAExportModel fromDataModel(String key, Object value) { DatasetMetadataRDAExportModel metadataRDAExportModel = new DatasetMetadataRDAExportModel(); - if (key.contains("metadata_id")) - metadataRDAExportModel.setMetadata_id(new DatasetMetadataIdRDAExportModel().fromDataModel(key, value)); + if (key.contains("metadata_standard_id")) + metadataRDAExportModel.setMetadata_standard_id(new IdRDAExportModel(value.toString(), value.toString())); else if (key.contains("language")) metadataRDAExportModel.setLanguage(value.toString()); else if (key.contains("description")) diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetRDAExportModel.java index 94931b782..0c94ad88a 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetRDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetRDAExportModel.java @@ -6,31 +6,48 @@ import eu.eudat.data.entities.Dataset; import eu.eudat.logic.utilities.builders.XmlBuilder; import org.apache.commons.collections4.MultiValuedMap; import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; +import org.apache.poi.ss.formula.functions.T; import org.json.JSONObject; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.xml.xpath.*; +import java.text.DateFormat; import java.util.*; public class DatasetRDAExportModel { private static final ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private MultiValuedMap rdaToValueMap; - private DatasetIdRDAExportModel dataset_id; - private String description; - private Date issued; // Created Date, could also use finalized one. - private String language; - private String title; - private String sensitive_data; private String data_quality_assurance; + private IdRDAExportModel dataset_id; + private String description; + private List distribution; + private String issued; // Created Date, could also use finalized one. + private List keyword; + private String language; private List metadata; + private String personal_data; // Allowed Values: yes no unknown. + private String preservation_statement; + private List security_and_privacy; + private String sensitive_data; // Allowed Values: yes no unknown. + private List technical_resource; + private String title; + private String type; // Type according to: http://vocabularies.coar-repositories.org/pubby/resource_type.html - public DatasetIdRDAExportModel getDataset_id() { + public String getData_quality_assurance() { + return data_quality_assurance; + } + public void setData_quality_assurance(String data_quality_assurance) { + this.data_quality_assurance = data_quality_assurance; + } + + public IdRDAExportModel getDataset_id() { return dataset_id; } - public void setDataset_id(DatasetIdRDAExportModel dataset_id) { + public void setDataset_id(IdRDAExportModel dataset_id) { this.dataset_id = dataset_id; } @@ -41,13 +58,27 @@ public class DatasetRDAExportModel { this.description = description; } - public Date getIssued() { + public List getDistribution() { + return distribution; + } + public void setDistribution(List distribution) { + this.distribution = distribution; + } + + public String getIssued() { return issued; } - public void setIssued(Date issued) { + public void setIssued(String issued) { this.issued = issued; } + public List getKeyword() { + return keyword; + } + public void setKeyword(List keyword) { + this.keyword = keyword; + } + public String getLanguage() { return language; } @@ -55,11 +86,32 @@ public class DatasetRDAExportModel { this.language = language; } - public String getTitle() { - return title; + public List getMetadata() { + return metadata; } - public void setTitle(String title) { - this.title = title; + public void setMetadata(List metadata) { + this.metadata = metadata; + } + + public String getPersonal_data() { + return personal_data; + } + public void setPersonal_data(String personal_data) { + this.personal_data = personal_data; + } + + public String getPreservation_statement() { + return preservation_statement; + } + public void setPreservation_statement(String preservation_statement) { + this.preservation_statement = preservation_statement; + } + + public List getSecurity_and_privacy() { + return security_and_privacy; + } + public void setSecurity_and_privacy(List security_and_privacy) { + this.security_and_privacy = security_and_privacy; } public String getSensitive_data() { @@ -69,67 +121,45 @@ public class DatasetRDAExportModel { this.sensitive_data = sensitive_data; } - public String getData_quality_assurance() { - return data_quality_assurance; + public List getTechnical_resource() { + return technical_resource; } - public void setData_quality_assurance(String data_quality_assurance) { - this.data_quality_assurance = data_quality_assurance; + public void setTechnical_resource(List technical_resource) { + this.technical_resource = technical_resource; } - public List getMetadata() { - return metadata; + public String getTitle() { + return title; } - public void setMetadata(List metadata) { - this.metadata = metadata; + public void setTitle(String title) { + this.title = title; + } + + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; } public DatasetRDAExportModel fromDataModel(Dataset dataset) { - // Parsing dataset template definition to create a map of which question of the template corresponds to the RDA common standard. Map: TemplateId -> rdaProperty - List rdaPropertiesThatExistOnDatasetTemplate = xmlNodeListFromExpression(dataset.getProfile().getDefinition(), "//rdaCommonStandard/text()"); - List rdaProperties = new LinkedList<>(); - for (String item : rdaPropertiesThatExistOnDatasetTemplate) { - item = item.replace("dataset.", ""); - rdaProperties.add(item); - } - List datasetTemplateIdsWithRdaProperties = xmlNodeListFromExpression(dataset.getProfile().getDefinition(), "//rdaCommonStandard/text()/ancestor::field/@id"); - Map templateIdsToRDAProperties = combineListsIntoOrderedMap(datasetTemplateIdsWithRdaProperties, rdaProperties); + this.rdaToValueMap = getRdaValueMap(dataset); + List distributions = getDatasetDistribution(); + List datasetMetadata = getDatasetMetadata(); + List securityAndPrivacy = getSecurityAndPrivacy(); + List technicalResources = getTechnicalResource(); - // Parsing dataset answers from json to map. Map: TemplateId -> datasetValue - JSONObject jObject = new JSONObject(dataset.getProperties()); - Map templateIdsToValues = jObject.toMap(); - - // Map: rdaProperty -> datasetValue - MultiValuedMap rdaToValueMap = new ArrayListValuedHashMap<>(); - for (String templateId : templateIdsToRDAProperties.keySet()) { - if (templateIdsToValues.containsKey(templateId)) { - rdaToValueMap.put(templateIdsToRDAProperties.get(templateId), templateIdsToValues.get(templateId).toString()); - } - } - - // Creates and fills a map to include metadata keys and values. - MultiValuedMap metadataJsonMap = new ArrayListValuedHashMap<>(); - for (String key : rdaToValueMap.keySet()) { - if (key.startsWith("metadata.")) { - metadataJsonMap.putAll(key.replace("metadata.", ""), rdaToValueMap.get(key)); - } - } - // Removes metadata keys from rdaToValueMap. - for (String metadataKey : metadataJsonMap.keySet()) rdaToValueMap.remove(metadataKey); - - DatasetRDAExportModel datasetRDAExportModel = mapper.convertValue(rdaToValueMap, DatasetRDAExportModel.class); - datasetRDAExportModel.setTitle(dataset.getLabel()); - datasetRDAExportModel.setIssued(dataset.getCreated()); + DatasetRDAExportModel datasetRDAExportModel = mapper.convertValue(this.rdaToValueMap, DatasetRDAExportModel.class); + datasetRDAExportModel.setDataset_id(new IdRDAExportModel(dataset.getId().toString(), "other")); + datasetRDAExportModel.setDescription(dataset.getDescription()); + datasetRDAExportModel.setIssued(DateFormat.getDateInstance(DateFormat.SHORT).format(dataset.getCreated())); datasetRDAExportModel.setLanguage("en"); // mock data; - datasetRDAExportModel.setDataset_id(new DatasetIdRDAExportModel(dataset.getId().toString(), "argos_internal")); - - List datasetMetadataRDAExportModels = new LinkedList<>(); - for (String key : metadataJsonMap.keySet()) { - for (String value : metadataJsonMap.get(key)) { - datasetMetadataRDAExportModels.add(new DatasetMetadataRDAExportModel().fromDataModel(key,value)); - } - } - datasetRDAExportModel.setMetadata(datasetMetadataRDAExportModels); + datasetRDAExportModel.setTitle(dataset.getLabel()); + datasetRDAExportModel.setDistribution(distributions); + datasetRDAExportModel.setMetadata(datasetMetadata); + datasetRDAExportModel.setSecurity_and_privacy(securityAndPrivacy); + datasetRDAExportModel.setTechnical_resource(technicalResources); return datasetRDAExportModel; } @@ -162,4 +192,107 @@ public class DatasetRDAExportModel { } return map; } + + private MultiValuedMap getRdaValueMap(Dataset dataset) { + // Parsing dataset template definition to create a map of which question of the template corresponds to the RDA common standard. Map: TemplateId -> rdaProperty + List rdaPropertiesThatExistOnDatasetTemplate = xmlNodeListFromExpression(dataset.getProfile().getDefinition(), "//rdaCommonStandard/text()"); + List rdaProperties = new LinkedList<>(); + for (String item : rdaPropertiesThatExistOnDatasetTemplate) { + item = item.replace("dataset.", ""); + rdaProperties.add(item); + } + List datasetTemplateIdsWithRdaProperties = xmlNodeListFromExpression(dataset.getProfile().getDefinition(), "//rdaCommonStandard/text()/ancestor::field/@id"); + Map templateIdsToRDAProperties = combineListsIntoOrderedMap(datasetTemplateIdsWithRdaProperties, rdaProperties); + + // Parsing dataset answers from json to map. Map: TemplateId -> datasetValue + JSONObject jObject = new JSONObject(dataset.getProperties()); + Map templateIdsToValues = jObject.toMap(); + + // Map: rdaProperty -> datasetValue + MultiValuedMap rdaToValueMap = new ArrayListValuedHashMap<>(); + for (String templateId : templateIdsToRDAProperties.keySet()) { + if (templateIdsToValues.containsKey(templateId)) { + rdaToValueMap.put(templateIdsToRDAProperties.get(templateId), templateIdsToValues.get(templateId).toString()); + } + } + return rdaToValueMap; + } + + private List getDatasetDistribution() { + // Creates and fills a map to include distribution keys and values. + MultiValuedMap distributionJsonMap = new ArrayListValuedHashMap<>(); + for (String key : this.rdaToValueMap.keySet()) { + if (key.startsWith("distribution.")) { + distributionJsonMap.putAll(key.replace("distribution.", ""), this.rdaToValueMap.get(key)); + } + } + // Removes distribution keys from rdaToValueMap. + for (String distributionKey : distributionJsonMap.keySet()) this.rdaToValueMap.remove(distributionKey); + List distributionModels = new LinkedList<>(); + for (String key : distributionJsonMap.keySet()) { + for (String value : distributionJsonMap.get(key)) { + distributionModels.add(new DatasetDistributionRDAExportModel().fromDataModel(key, value)); + } + } + return distributionModels; + } + + private List getDatasetMetadata() { + // Creates and fills a map to include metadata keys and values. + MultiValuedMap metadataJsonMap = new ArrayListValuedHashMap<>(); + for (String key : this.rdaToValueMap.keySet()) { + if (key.startsWith("metadata.")) { + metadataJsonMap.putAll(key.replace("metadata.", ""), this.rdaToValueMap.get(key)); + } + } + // Removes metadata keys from rdaToValueMap. + for (String metadataKey : metadataJsonMap.keySet()) this.rdaToValueMap.remove(metadataKey); + List datasetMetadataRDAExportModels = new LinkedList<>(); + for (String key : metadataJsonMap.keySet()) { + for (String value : metadataJsonMap.get(key)) { + datasetMetadataRDAExportModels.add(new DatasetMetadataRDAExportModel().fromDataModel(key, value)); + } + } + return datasetMetadataRDAExportModels; + } + + private List getSecurityAndPrivacy() { + // Creates and fills a map to include SecurityAndPrivacy keys and values. + MultiValuedMap securityAndPrivacyJsonMap = new ArrayListValuedHashMap<>(); + for (String key : this.rdaToValueMap.keySet()) { + if (key.startsWith("security_and_privacy.")) { + securityAndPrivacyJsonMap.putAll(key.replace("security_and_privacy.", ""), this.rdaToValueMap.get(key)); + } + } + // Removes SecurityAndPrivacy keys from rdaToValueMap. + for (String securityAndPrivacy : securityAndPrivacyJsonMap.keySet()) this.rdaToValueMap.remove(securityAndPrivacy); + List securityAndPrivacyList= new LinkedList<>(); + for (String key : securityAndPrivacyJsonMap.keySet()) { + for (String value : securityAndPrivacyJsonMap.get(key)) { + securityAndPrivacyList.add(new DatasetSecurityAndPrivacyRDAExportModel().fromDataModel(key, value)); + } + } + return securityAndPrivacyList; + } + + private List getTechnicalResource() { + // Creates and fills a map to include Technical_Resource keys and values. + MultiValuedMap technicalResourceJsonMap = new ArrayListValuedHashMap<>(); + for (String key : this.rdaToValueMap.keySet()) { + if (key.startsWith("technical_resource.")) { + technicalResourceJsonMap.putAll(key.replace("technical_resource.", ""), this.rdaToValueMap.get(key)); + } + } + // Removes Technical_Resource keys from rdaToValueMap. + for (String techResource : technicalResourceJsonMap.keySet()) this.rdaToValueMap.remove(techResource); + List datasetTechnicalResourceRDAExportModel= new LinkedList<>(); + for (String key : technicalResourceJsonMap.keySet()) { + for (String value : technicalResourceJsonMap.get(key)) { + datasetTechnicalResourceRDAExportModel.add(new DatasetTechnicalResourceRDAExportModel().fromDataModel(key, value)); + } + } + return datasetTechnicalResourceRDAExportModel; + } + + } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetSecurityAndPrivacyRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetSecurityAndPrivacyRDAExportModel.java new file mode 100644 index 000000000..77115e086 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetSecurityAndPrivacyRDAExportModel.java @@ -0,0 +1,29 @@ +package eu.eudat.models.data.rda; + +public class DatasetSecurityAndPrivacyRDAExportModel { + private String description; + private String title; + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public String getTitle() { + return title; + } + public void setTitle(String title) { + this.title = title; + } + + public DatasetSecurityAndPrivacyRDAExportModel fromDataModel(String key, Object value) { + DatasetSecurityAndPrivacyRDAExportModel securityAndPrivacy = new DatasetSecurityAndPrivacyRDAExportModel(); + if (key.contains("description")) + securityAndPrivacy.setDescription(value.toString()); + else if (key.contains("title")) + securityAndPrivacy.setTitle(value.toString()); + return securityAndPrivacy; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetTechnicalResourceRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetTechnicalResourceRDAExportModel.java new file mode 100644 index 000000000..96ad0c3fb --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetTechnicalResourceRDAExportModel.java @@ -0,0 +1,29 @@ +package eu.eudat.models.data.rda; + +public class DatasetTechnicalResourceRDAExportModel { + private String description; + private String name; + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public DatasetTechnicalResourceRDAExportModel fromDataModel(String key, Object value) { + DatasetTechnicalResourceRDAExportModel technicalResource = new DatasetTechnicalResourceRDAExportModel(); + if (key.contains("description")) + technicalResource.setDescription(value.toString()); + else if (key.contains("name")) + technicalResource.setName(value.toString()); + return technicalResource; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpContributorRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpContributorRDAExportModel.java new file mode 100644 index 000000000..47079023f --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpContributorRDAExportModel.java @@ -0,0 +1,52 @@ +package eu.eudat.models.data.rda; + +import eu.eudat.data.entities.UserInfo; + +import java.util.LinkedList; +import java.util.List; + +public class DmpContributorRDAExportModel { + private IdRDAExportModel contributor_id; + private String mbox; + private String name; + private List role; + + public IdRDAExportModel getContributor_id() { + return contributor_id; + } + public void setContributor_id(IdRDAExportModel contributor_id) { + this.contributor_id = contributor_id; + } + + public String getMbox() { + return mbox; + } + public void setMbox(String mbox) { + this.mbox = mbox; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public List getRole() { + return role; + } + public void setRole(List role) { + this.role = role; + } + + public DmpContributorRDAExportModel fromDataModel(UserInfo user, String role) { + DmpContributorRDAExportModel contributor = new DmpContributorRDAExportModel(); + contributor.contributor_id = new IdRDAExportModel(user.getId().toString(), "other"); + contributor.mbox = user.getEmail(); + contributor.name = user.getName(); + contributor.role = new LinkedList<>(); + contributor.role.add(role); + + return contributor; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpCostRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpCostRDAExportModel.java new file mode 100644 index 000000000..98abbadd8 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpCostRDAExportModel.java @@ -0,0 +1,36 @@ +package eu.eudat.models.data.rda; + +public class DmpCostRDAExportModel { + private String currency_code; //Allowed values defined by ISO 4217. + private String description; + private String title; + private String value; + + public String getCurrency_code() { + return currency_code; + } + public void setCurrency_code(String currency_code) { + this.currency_code = currency_code; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public String getTitle() { + return title; + } + public void setTitle(String title) { + this.title = title; + } + + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpIdRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpIdRDAExportModel.java deleted file mode 100644 index 1c7e09793..000000000 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpIdRDAExportModel.java +++ /dev/null @@ -1,25 +0,0 @@ -package eu.eudat.models.data.rda; - -public class DmpIdRDAExportModel { - private String dmp_id; - private String dmp_id_type; - - public String getDmp_id() { - return dmp_id; - } - public void setDmp_id(String dmp_id) { - this.dmp_id = dmp_id; - } - - public String getDmp_id_type() { - return dmp_id_type; - } - public void setDmp_id_type(String dmp_id_type) { - this.dmp_id_type = dmp_id_type; - } - - DmpIdRDAExportModel(String dmp_id, String dmp_id_type) { - this.dmp_id = dmp_id; - this.dmp_id_type = dmp_id_type; - } -} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpRDAExportModel.java index a4fab5c74..7c2b02eaf 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpRDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpRDAExportModel.java @@ -1,34 +1,66 @@ package eu.eudat.models.data.rda; import eu.eudat.data.entities.DMP; +import eu.eudat.data.entities.Dataset; import eu.eudat.data.entities.UserDMP; +import eu.eudat.data.entities.UserInfo; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Date; -import java.util.UUID; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; public class DmpRDAExportModel { - private DmpIdRDAExportModel dmp_id; - private String title; - private String description; - private Date created; - private Date modified; private ContactRDAExportModel contact; + private List contributor; + private List cost; + private String created; + private List dataset; + private String description; + private IdRDAExportModel dmp_id; + private String ethical_issues_description; + private String ethical_issues_exist; // Allowed Values: yes no unknown. + private String ethical_issues_report; private String language; - private String ethical_issues_exist; + private String modified; private ProjectRDAExportModel project; + private String title; - public DmpIdRDAExportModel getDmp_id() { - return dmp_id; + public ContactRDAExportModel getContact() { + return contact; } - public void setDmp_id(DmpIdRDAExportModel dmp_id) { - this.dmp_id = dmp_id; + public void setContact(ContactRDAExportModel contact) { + this.contact = contact; } - public String getTitle() { - return title; + public List getContributor() { + return contributor; } - public void setTitle(String title) { - this.title = title; + public void setContributor(List contributor) { + this.contributor = contributor; + } + + public List getCost() { + return cost; + } + public void setCost(List cost) { + this.cost = cost; + } + + public String getCreated() { + return created; + } + public void setCreated(String created) { + this.created = created; + } + + public List getDataset() { + return dataset; + } + public void setDataset(List dataset) { + this.dataset = dataset; } public String getDescription() { @@ -38,32 +70,18 @@ public class DmpRDAExportModel { this.description = description; } - public Date getCreated() { - return created; + public IdRDAExportModel getDmp_id() { + return dmp_id; } - public void setCreated(Date created) { - this.created = created; + public void setDmp_id(IdRDAExportModel dmp_id) { + this.dmp_id = dmp_id; } - public Date getModified() { - return modified; + public String getEthical_issues_description() { + return ethical_issues_description; } - public void setModified(Date modified) { - this.modified = modified; - } - - public ContactRDAExportModel getContact() { - return contact; - } - public void setContact(ContactRDAExportModel contact) { - this.contact = contact; - } - - public String getLanguage() { - return language; - } - public void setLanguage(String language) { - this.language = language; + public void setEthical_issues_description(String ethical_issues_description) { + this.ethical_issues_description = ethical_issues_description; } public String getEthical_issues_exist() { @@ -73,6 +91,27 @@ public class DmpRDAExportModel { this.ethical_issues_exist = ethical_issues_exist; } + public String getEthical_issues_report() { + return ethical_issues_report; + } + public void setEthical_issues_report(String ethical_issues_report) { + this.ethical_issues_report = ethical_issues_report; + } + + public String getLanguage() { + return language; + } + public void setLanguage(String language) { + this.language = language; + } + + public String getModified() { + return modified; + } + public void setModified(String modified) { + this.modified = modified; + } + public ProjectRDAExportModel getProject() { return project; } @@ -80,25 +119,46 @@ public class DmpRDAExportModel { this.project = project; } + public String getTitle() { + return title; + } + public void setTitle(String title) { + this.title = title; + } public DmpRDAExportModel fromDataModel(DMP entity) { - if (entity.getDoi() != null) - this.dmp_id = new DmpIdRDAExportModel(entity.getDoi(), "zenodo"); - else - this.dmp_id = new DmpIdRDAExportModel(entity.getId().toString(), "argos_internal"); + DmpRDAExportModel dmpRda = new DmpRDAExportModel(); + dmpRda.contact = new ContactRDAExportModel().fromDataModel(entity.getUsers().stream().filter(x -> x.getRole().equals(UserDMP.UserDMPRoles.OWNER.getValue())).findFirst().get().getUser()); + if (entity.getUsers().stream().anyMatch(x -> x.getRole().equals(UserDMP.UserDMPRoles.USER.getValue()))) { + dmpRda.contributor = new LinkedList<>(); + for (UserDMP userdmp : entity.getUsers().stream().filter(x -> x.getRole().equals(UserDMP.UserDMPRoles.USER.getValue())).collect(Collectors.toList())) { + dmpRda.contributor.add(new DmpContributorRDAExportModel().fromDataModel(userdmp.getUser(), UserDMP.UserDMPRoles.fromInteger(userdmp.getRole()).toString())); + } + } + dmpRda.cost = null; + SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); + dmpRda.created = formatter.format(entity.getCreated()); + dmpRda.dataset = new LinkedList<>(); + for (Dataset dataset : entity.getDataset()) { + if (dataset.getStatus() != Dataset.Status.DELETED.getValue() && dataset.getStatus() != Dataset.Status.CANCELED.getValue()) + dmpRda.dataset.add(new DatasetRDAExportModel().fromDataModel(dataset)); + } + dmpRda.description = entity.getDescription(); + if (entity.getDoi() != null) { + dmpRda.dmp_id = new IdRDAExportModel(entity.getDoi(), "zenodo"); + } + else { + dmpRda.dmp_id = new IdRDAExportModel(entity.getId().toString(), "other"); + } + // Mock up data on "language" and "ethical_issues_*" for now. + // dmpRda.ethical_issues_description = null; + dmpRda.ethical_issues_exist = "unknown"; + // dmpRda.ethical_issues_report = null; + dmpRda.language = "en"; + dmpRda.modified = formatter.format(new Date()); + dmpRda.project = new ProjectRDAExportModel().fromDataModel(entity.getGrant()); + dmpRda.title = entity.getLabel(); - this.title = entity.getLabel(); - this.description = entity.getDescription(); - this.created = entity.getCreated(); - this.modified = entity.getModified(); - this.contact = new ContactRDAExportModel().fromDataModel(entity.getUsers().stream().filter(x -> x.getRole().equals(UserDMP.UserDMPRoles.OWNER.getValue())).findFirst().get().getUser()); - - // Mock up data on "language" and "ethical_issues" for now. - this.language = "en"; - this.ethical_issues_exist = "unknown"; - - this.project = new ProjectRDAExportModel().fromDataModel(entity.getGrant()); - - return this; + return dmpRda; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/FunderIdRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/FunderIdRDAExportModel.java deleted file mode 100644 index d58abeb5f..000000000 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/FunderIdRDAExportModel.java +++ /dev/null @@ -1,25 +0,0 @@ -package eu.eudat.models.data.rda; - -public class FunderIdRDAExportModel { - private String funder_id; - private String funder_id_type; - - public String getFunder_id() { - return funder_id; - } - public void setFunder_id(String funder_id) { - this.funder_id = funder_id; - } - - public String getFunder_id_type() { - return funder_id_type; - } - public void setFunder_id_type(String funder_id_type) { - this.funder_id_type = funder_id_type; - } - - FunderIdRDAExportModel(String funder_id, String funder_id_type) { - this.funder_id = funder_id; - this.funder_id_type = funder_id_type; - } -} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/FundingRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/FundingRDAExportModel.java index 0739b7766..5691cae2c 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/FundingRDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/FundingRDAExportModel.java @@ -4,21 +4,21 @@ import eu.eudat.data.entities.Funder; import eu.eudat.data.entities.Grant; public class FundingRDAExportModel { - private FunderIdRDAExportModel funder_id; - private GrantIdRDAExportModel grant_id; + private IdRDAExportModel funder_id; + private IdRDAExportModel grant_id; private String funding_status; - public FunderIdRDAExportModel getFunder_id() { + public IdRDAExportModel getFunder_id() { return funder_id; } - public void setFunder_id(FunderIdRDAExportModel funder_id) { + public void setFunder_id(IdRDAExportModel funder_id) { this.funder_id = funder_id; } - public GrantIdRDAExportModel getGrant_id() { + public IdRDAExportModel getGrant_id() { return grant_id; } - public void setGrant_id(GrantIdRDAExportModel grant_id) { + public void setGrant_id(IdRDAExportModel grant_id) { this.grant_id = grant_id; } @@ -30,13 +30,14 @@ public class FundingRDAExportModel { } public FundingRDAExportModel fromDataModel(Funder funder, Grant grant) { - this.funding_status = "planned"; // mock data + FundingRDAExportModel funding = new FundingRDAExportModel(); + funding.funding_status = "planned"; // mock data if (funder != null) { - this.funder_id = new FunderIdRDAExportModel(funder.getReference(), "argos_internal"); + funding.funder_id = new IdRDAExportModel(funder.getReference(), "other"); } if (grant != null) { - this.grant_id = new GrantIdRDAExportModel(grant.getReference(), "argos_internal"); + funding.grant_id = new IdRDAExportModel(grant.getReference(), "other"); } - return this; + return funding; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/GrantIdRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/GrantIdRDAExportModel.java deleted file mode 100644 index 8bcac2735..000000000 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/GrantIdRDAExportModel.java +++ /dev/null @@ -1,25 +0,0 @@ -package eu.eudat.models.data.rda; - -public class GrantIdRDAExportModel { - private String grant_id; - private String grant_id_type; - - public String getGrant_id() { - return grant_id; - } - public void setGrant_id(String grant_id) { - this.grant_id = grant_id; - } - - public String getGrant_id_type() { - return grant_id_type; - } - public void setGrant_id_type(String grant_id_type) { - this.grant_id_type = grant_id_type; - } - - GrantIdRDAExportModel(String grant_id, String grant_id_type) { - this.grant_id = grant_id; - this.grant_id_type = grant_id_type; - } -} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/HostRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/HostRDAExportModel.java new file mode 100644 index 000000000..bac169259 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/HostRDAExportModel.java @@ -0,0 +1,86 @@ +package eu.eudat.models.data.rda; + +import java.util.List; + +public class HostRDAExportModel { + private String availability; + private String backup__frequency; + private String backup_type; + private String certified_with; // Repository certified with one the following standards: DIN31644 / DINI-Zertifikat / DSA / ISO16363 / ISO16919 /TRAC / WDS / CoreTrustSeal + private String description; + private String geo_location; // Physical location of the data expressed using ISO 3166-1 country code. + private List pid_system; // PID System: ark arxiv bibcode doi ean13 eissn handle igsn isbn issn istc lissn lsid pmid purl upc url urn other + private String storage_type; + private String support_versioning; // Allowed values: yes / no / unknown + private String title; + + public String getAvailability() { + return availability; + } + public void setAvailability(String availability) { + this.availability = availability; + } + + public String getBackup__frequency() { + return backup__frequency; + } + public void setBackup__frequency(String backup__frequency) { + this.backup__frequency = backup__frequency; + } + + public String getBackup_type() { + return backup_type; + } + public void setBackup_type(String backup_type) { + this.backup_type = backup_type; + } + + public String getCertified_with() { + return certified_with; + } + public void setCertified_with(String certified_with) { + this.certified_with = certified_with; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public String getGeo_location() { + return geo_location; + } + public void setGeo_location(String geo_location) { + this.geo_location = geo_location; + } + + public List getPid_system() { + return pid_system; + } + public void setPid_system(List pid_system) { + this.pid_system = pid_system; + } + + public String getStorage_type() { + return storage_type; + } + public void setStorage_type(String storage_type) { + this.storage_type = storage_type; + } + + public String getSupport_versioning() { + return support_versioning; + } + public void setSupport_versioning(String support_versioning) { + this.support_versioning = support_versioning; + } + + public String getTitle() { + return title; + } + public void setTitle(String title) { + this.title = title; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/IdRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/IdRDAExportModel.java new file mode 100644 index 000000000..2aef46e5b --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/IdRDAExportModel.java @@ -0,0 +1,25 @@ +package eu.eudat.models.data.rda; + +public class IdRDAExportModel { + private String identifier; + private String type; + + public String getIdentifier() { + return identifier; + } + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + + IdRDAExportModel(String identifier, String type) { + this.identifier = identifier; + this.type = type; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/LicenseRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/LicenseRDAExportModel.java new file mode 100644 index 000000000..dec57a467 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/LicenseRDAExportModel.java @@ -0,0 +1,20 @@ +package eu.eudat.models.data.rda; + +public class LicenseRDAExportModel { + private String license_ref; + private String start_date; // If date is set in the future, it indicates embargo period. + + public String getLicense_ref() { + return license_ref; + } + public void setLicense_ref(String license_ref) { + this.license_ref = license_ref; + } + + public String getStart_date() { + return start_date; + } + public void setStart_date(String start_date) { + this.start_date = start_date; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RDAExportModel.java index b4720d350..eae34fa60 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RDAExportModel.java @@ -8,7 +8,6 @@ import java.util.List; public class RDAExportModel { private DmpRDAExportModel dmp; - private List datasets; public DmpRDAExportModel getDmp() { return dmp; @@ -17,20 +16,8 @@ public class RDAExportModel { this.dmp = dmp; } - public List getDatasets() { - return datasets; - } - public void setDatasets(List datasets) { - this.datasets = datasets; - } - public RDAExportModel fromDataModel(DMP dmp) { this.dmp = new DmpRDAExportModel().fromDataModel(dmp); - this.datasets = new LinkedList<>(); - for (Dataset dataset : dmp.getDataset()) { - if (dataset.getStatus() != Dataset.Status.DELETED.getValue() && dataset.getStatus() != Dataset.Status.CANCELED.getValue()) - this.datasets.add(new DatasetRDAExportModel().fromDataModel(dataset)); - } return this; } } diff --git a/dmp-backend/web/src/main/resources/RDACommonStandards.txt b/dmp-backend/web/src/main/resources/RDACommonStandards.txt index 134b84e73..8c543d6aa 100644 --- a/dmp-backend/web/src/main/resources/RDACommonStandards.txt +++ b/dmp-backend/web/src/main/resources/RDACommonStandards.txt @@ -1,39 +1,39 @@ -ethical_issues_exist -cost -cost.title -cost.description -cost.value -cost.currency_code -contact -contact.mail -contact.name -contact.contact_id -contact.contact_id.contact_id -contact.contact_id.contact_id_type -project -project.title -project.project_start -project.project_end -project.funding -project.funding.funder_id -project.funding.funder_id.funder_id -project.funding.funder_id.funder_id_type -project.funding.grant_id -project.funding.grant_id.grant_id -project.funding.grant_id.grant_id_type -dataset -dataset.title -dataset.type -dataset.personal_data -dataset.sensitive_data -dataset.dataset_id -dataset.dataset_id.dataset_id -dataset.dataset_id.dataset_id_type -dataset.metadata +dataset.data_quality_assurance +dataset.distribution.access_url +dataset.distribution.available_till +dataset.distribution.byte_size +dataset.distribution.data_access +dataset.distribution.description +dataset.distribution.download_url +dataset.distribution.format +dataset.distribution.host.availability +dataset.distribution.host.backup_frequency +dataset.distribution.host.backup_type +dataset.distribution.host.certified_with +dataset.distribution.host.description +dataset.distribution.host.geo_location +dataset.distribution.host.pid_system +dataset.distribution.host.storage_type +dataset.distribution.host.supports_versioning +dataset.distribution.host.title +dataset.distribution.host.url +dataset.distribution.license.license_ref +dataset.distribution.license.start_date +dataset.distribution.title +dataset.keyword +dataset.language dataset.metadata.language -dataset.metadata.metadata_id -dataset.metadata.metadata_id.metadata_id -dataset.metadata.metadata_id.metadata_id_type +dataset.metadata.metadata_standard_id +dataset.metadata.metadata_standard_id.identifier +dataset.metadata.metadata_standard_id.type +dataset.personal_data +dataset.preservation_statement dataset.security_and_privacy +dataset.security_and_privacy.description dataset.security_and_privacy.title -dataset.security_and_privacy.description \ No newline at end of file +dataset.sensitive_data +dataset.technical_resource.description +dataset.technical_resource.technical_resource +dataset.technical_resource.technical_resource.description +dataset.technical_resource.technical_resource.name +dataset.type \ No newline at end of file From 7e8a70e2d4e0d61c366d38ab69e722b0e1f85df0 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Mon, 2 Dec 2019 10:29:41 +0200 Subject: [PATCH 002/106] Fixes bug on cookies consent "Learn more" link. --- dmp-frontend/src/app/app.module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmp-frontend/src/app/app.module.ts b/dmp-frontend/src/app/app.module.ts index b82670f0c..d40363ad6 100644 --- a/dmp-frontend/src/app/app.module.ts +++ b/dmp-frontend/src/app/app.module.ts @@ -54,7 +54,7 @@ const cookieConfig: NgcCookieConsentConfig = { dismiss: "Got it!", deny: "Refuse cookies", link: "Learn more", - href: "http://localhost:4200/terms-of-service", + href: environment.App + "terms-of-service", policy: "Cookie Policy" }, position: "bottom-right", From bccb4460a72b65c0aca943a679cb3acb55a76d2a Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Mon, 9 Dec 2019 18:23:21 +0200 Subject: [PATCH 003/106] Fixes bug not having validators on adding new Researcher on a DMP. (Issue #207) --- .../eu/eudat/models/data/dmp/Researcher.java | 4 ++-- .../add-researcher.component.html | 2 +- .../add-researcher/add-researcher.component.ts | 4 ++++ .../add-researcher/add-researcher.model.ts | 17 ++++++++++++++--- .../editor/general-tab/general-tab.component.ts | 2 +- 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Researcher.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Researcher.java index 9cf079480..c610c92e6 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Researcher.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Researcher.java @@ -74,10 +74,10 @@ public class Researcher implements DataModel
-
+
diff --git a/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.component.ts b/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.component.ts index 08d3940aa..7d677020e 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.component.ts @@ -37,4 +37,8 @@ export class AddResearcherComponent extends BaseComponent implements OnInit { addResearcher() { this.dialogRef.close(this.formGroup.value); } + + isFormValid() { + return this.formGroup.valid; + } } diff --git a/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.model.ts b/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.model.ts index 529a0bb3d..a5fa6df33 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.model.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.model.ts @@ -1,5 +1,8 @@ import { FormBuilder, FormGroup } from '@angular/forms'; import { ResearcherModel } from '../../../../core/model/researcher/researcher'; +import { ValidationContext } from "../../../../common/forms/validation/validation-context"; +import { BackendErrorValidator } from "../../../../common/forms/validation/custom-validator"; +import { ValidationErrorModel } from "../../../../common/forms/validation/error-model/validation-error-model"; export class ResearcherEditorModel { public id: String; @@ -7,6 +10,7 @@ export class ResearcherEditorModel { public lastName: String; public uri: String; public email: String; + public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); fromModel(item: ResearcherModel): ResearcherEditorModel { this.id = item.id; @@ -17,13 +21,20 @@ export class ResearcherEditorModel { return this; } - buildForm(): FormGroup { + buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { + if (context == null) { context = this.createValidationContext(); } const formGroup = new FormBuilder().group({ - firstName: [this.name], - lastName: [this.lastName] + firstName: [{ value: this.name, disabled: disabled }, context.getValidation('firstName').validators], + lastName: [{ value: this.lastName, disabled: disabled }, context.getValidation('lastName').validators] }); return formGroup; } + createValidationContext(): ValidationContext { + const baseContext: ValidationContext = new ValidationContext(); + baseContext.validation.push({ key: 'firstName', validators: [BackendErrorValidator(this.validationErrorModel, 'firstName')] }); + baseContext.validation.push({ key: 'lastName', validators: [BackendErrorValidator(this.validationErrorModel, 'lastName')] }); + return baseContext; + } } diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts index dff382cfd..28621b809 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts @@ -179,7 +179,7 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { name: fullName, id: "dmp:" + fullName, status: 0, - tag: null, + tag: "Internal", }); } }); From 5585baa951154e463e0598bd4bab79b3433c5374 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Tue, 10 Dec 2019 11:58:15 +0200 Subject: [PATCH 004/106] Fixes bug replacing "funder url" when fetching from remote APIs. --- .../main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java index efc0b1db4..f3a416982 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java @@ -138,7 +138,7 @@ public class RemoteFetcher { private void ifFunderQueryExist(UrlConfiguration urlConfiguration, ExternalUrlCriteria externalUrlCriteria) { if (urlConfiguration.getFunderQuery() != null) { - if (externalUrlCriteria.getFunderId() != null && urlConfiguration.getFunderQuery().startsWith("dmp:")) { + if (externalUrlCriteria.getFunderId() != null && !urlConfiguration.getFunderQuery().startsWith("dmp:")) { urlConfiguration.setUrl(urlConfiguration.getUrl().replace("{funderQuery}", urlConfiguration.getFunderQuery())); } else { From 77638fbf9d7afe49e081585165a836e2b6059845 Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Wed, 11 Dec 2019 11:15:30 +0200 Subject: [PATCH 005/106] dmp general tab changes --- .../general-tab/general-tab.component.ts | 85 +++++++------------ 1 file changed, 30 insertions(+), 55 deletions(-) diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts index dff382cfd..817786f8b 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts @@ -1,9 +1,10 @@ -import {map, takeUntil } from 'rxjs/operators'; import { Component, Input, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; +import { TranslateService } from '@ngx-translate/core'; import { Observable } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; import { BaseComponent } from '../../../../core/common/base/base.component'; import { DataTableRequest } from '../../../../core/model/data-table/data-table-request'; import { DatasetProfileModel } from '../../../../core/model/dataset/dataset-profile'; @@ -19,7 +20,6 @@ import { MultipleAutoCompleteConfiguration } from '../../../../library/auto-comp import { SingleAutoCompleteConfiguration } from '../../../../library/auto-complete/single/single-auto-complete-configuration'; import { AddResearcherComponent } from '../add-researcher/add-researcher.component'; import { AvailableProfilesComponent } from '../available-profiles/available-profiles.component'; -import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-general-tab', @@ -31,17 +31,34 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { @Input() formGroup: FormGroup = null; @Input() isNewVersion: boolean; - filteringOrganisationsAsync = false; - filteringResearchersAsync = false; - filteredProfilesAsync = false; - filteredOrganisations: ExternalSourceItemModel[]; - filteredResearchers: ExternalSourceItemModel[]; - filteredProfiles: DatasetProfileModel[]; + profilesAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { + 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'] + }; - profilesAutoCompleteConfiguration: MultipleAutoCompleteConfiguration; - organisationsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration; - researchersAutoCompleteConfiguration: MultipleAutoCompleteConfiguration; - dmpProfileAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + 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 ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : 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 ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') + }; + dmpProfileAutoCompleteConfiguration: SingleAutoCompleteConfiguration = { + filterFn: this.dmpProfileSearch.bind(this), + initialItems: (extraData) => this.dmpProfileSearch(''), + displayFn: (item) => item['label'], + titleFn: (item) => item['label'] + }; selectedDmpProfileDefinition: DmpProfileDefinition; @@ -63,43 +80,12 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { if (this.isNewVersion) { this.formGroup.get('label').disable(); } - - this.dmpProfileAutoCompleteConfiguration = { - filterFn: this.dmpProfileSearch.bind(this), - initialItems: (extraData) => this.dmpProfileSearch(''), - displayFn: (item) => item['label'], - titleFn: (item) => item['label'] - }; - - 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'] - }; - - this.organisationsAutoCompleteConfiguration = { - 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 ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') - }; - - this.researchersAutoCompleteConfiguration = { - 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 ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') - }; } registerFormEventsForDmpProfile(definitionProperties?: DmpProfileDefinition): void { this.formGroup.get('profile').valueChanges .pipe( - takeUntil(this._destroyed)) + takeUntil(this._destroyed)) .subscribe(Option => { if (Option instanceof Object) { this.selectedDmpProfileDefinition = null; @@ -140,26 +126,15 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { // } filterOrganisations(value: string): Observable { - - this.filteredOrganisations = undefined; - this.filteringOrganisationsAsync = true; - return this.externalSourcesService.searchDMPOrganizations(value); } filterResearchers(value: string): Observable { - - this.filteredResearchers = undefined; - this.filteringResearchersAsync = true; - return this.externalSourcesService.searchDMPResearchers({ criteria: { name: value, like: null } }); } filterProfiles(value: string): Observable { - this.filteredProfiles = undefined; - this.filteredProfilesAsync = true; - const request = new RequestItem(); const criteria = new DatasetProfileCriteria(); criteria.like = value; From 3765d7cc9f4980debbbce32a21d39c2de61c14a9 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Wed, 11 Dec 2019 12:48:13 +0200 Subject: [PATCH 006/106] Refactors RDA export for DMP. --- .../main/java/eu/eudat/controllers/DMPs.java | 2 +- .../eudat/logic/managers/DatasetManager.java | 2 +- .../rda/DatasetMetadataIdRDAExportModel.java | 31 -- .../rda/DatasetMetadataRDAExportModel.java | 9 +- .../data/rda/DatasetRDAExportModel.java | 410 ++++++++++++------ ...tasetSecurityAndPrivacyRDAExportModel.java | 18 +- ...atasetTechnicalResourceRDAExportModel.java | 15 +- .../models/data/rda/DmpRDAExportModel.java | 9 +- .../eudat/models/data/rda/RDAExportModel.java | 5 +- .../eu/eudat/models/data/rda/RdaField.java | 36 ++ .../user/components/datasetprofile/Field.java | 12 + .../src/main/resources/RDACommonStandards.txt | 1 + 12 files changed, 358 insertions(+), 192 deletions(-) delete mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetMetadataIdRDAExportModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RdaField.java diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java index 5208e5d43..beca226a5 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java @@ -110,7 +110,7 @@ public class DMPs extends BaseController { @RequestMapping(method = RequestMethod.GET, value = {"rda/{id}"}) public @ResponseBody ResponseEntity getRDAJsonDocument(@PathVariable String id, @ClaimedAuthorities(claims = {Authorities.ADMIN, Authorities.MANAGER, Authorities.USER, Authorities.ANONYMOUS}) Principal principal) throws IOException { - return this.dataManagementPlanManager.getRDAJsonDocument(id, principal); + return this.dataManagementPlanManager.getRDAJsonDocument(id, datasetManager, principal); } @RequestMapping(method = RequestMethod.GET, value = {"/overview/{id}"}) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java index 5b04ef777..3a1d2e8f8 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java @@ -172,7 +172,7 @@ public class DatasetManager { return dataTable; } - public DatasetWizardModel getSingle(String id) throws InstantiationException, IllegalAccessException, IOException { + public DatasetWizardModel getSingle(String id) { DatasetWizardModel dataset = new DatasetWizardModel(); eu.eudat.data.entities.Dataset datasetEntity = databaseRepository.getDatasetDao().find(UUID.fromString(id), HintedModelFactory.getHint(DatasetWizardModel.class)); eu.eudat.elastic.entities.Dataset datasetElastic; diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetMetadataIdRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetMetadataIdRDAExportModel.java deleted file mode 100644 index f6b3130ba..000000000 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetMetadataIdRDAExportModel.java +++ /dev/null @@ -1,31 +0,0 @@ -package eu.eudat.models.data.rda; - -public class DatasetMetadataIdRDAExportModel { - private String metadata_id; - private String metadata_id_type; - - public String getMetadata_id() { - return metadata_id; - } - public void setMetadata_id(String metadata_id) { - this.metadata_id = metadata_id; - } - - public String getMetadata_id_type() { - return metadata_id_type; - } - public void setMetadata_id_type(String metadata_id_type) { - this.metadata_id_type = metadata_id_type; - } - - - public DatasetMetadataIdRDAExportModel fromDataModel(String key, Object value) { - DatasetMetadataIdRDAExportModel metadataIdRDAExportModel = new DatasetMetadataIdRDAExportModel(); - if (key.contains(".metadata_id")) - metadataIdRDAExportModel.setMetadata_id(value.toString()); - else if (key.contains(".metadata_id_type")) - metadataIdRDAExportModel.setMetadata_id_type(value.toString()); - - return metadataIdRDAExportModel; - } -} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetMetadataRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetMetadataRDAExportModel.java index dc5814375..2b5da6abd 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetMetadataRDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetMetadataRDAExportModel.java @@ -1,5 +1,7 @@ package eu.eudat.models.data.rda; +import com.fasterxml.jackson.annotation.JsonIgnore; + public class DatasetMetadataRDAExportModel { private String description; // Not mandatory. private String language; @@ -29,7 +31,7 @@ public class DatasetMetadataRDAExportModel { public DatasetMetadataRDAExportModel fromDataModel(String key, Object value) { DatasetMetadataRDAExportModel metadataRDAExportModel = new DatasetMetadataRDAExportModel(); if (key.contains("metadata_standard_id")) - metadataRDAExportModel.setMetadata_standard_id(new IdRDAExportModel(value.toString(), value.toString())); + metadataRDAExportModel.setMetadata_standard_id(new IdRDAExportModel(value.toString(), "other")); else if (key.contains("language")) metadataRDAExportModel.setLanguage(value.toString()); else if (key.contains("description")) @@ -37,4 +39,9 @@ public class DatasetMetadataRDAExportModel { return metadataRDAExportModel; } + + @JsonIgnore + public boolean isValid() { + return description != null || language != null || metadata_standard_id != null; + } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetRDAExportModel.java index 0c94ad88a..71705b859 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetRDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetRDAExportModel.java @@ -1,12 +1,13 @@ package eu.eudat.models.data.rda; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.JsonPath; import eu.eudat.data.entities.Dataset; +import eu.eudat.logic.managers.DatasetManager; import eu.eudat.logic.utilities.builders.XmlBuilder; -import org.apache.commons.collections4.MultiValuedMap; -import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; -import org.apache.poi.ss.formula.functions.T; +import org.json.JSONArray; import org.json.JSONObject; import org.w3c.dom.Document; import org.w3c.dom.Node; @@ -16,12 +17,14 @@ import javax.xml.xpath.*; import java.text.DateFormat; import java.util.*; +import static java.util.stream.Collectors.groupingBy; + public class DatasetRDAExportModel { private static final ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - private MultiValuedMap rdaToValueMap; + private Map multiplicityIdToFieldSetId = new HashMap<>(); - private String data_quality_assurance; + private List data_quality_assurance; private IdRDAExportModel dataset_id; private String description; private List distribution; @@ -37,10 +40,10 @@ public class DatasetRDAExportModel { private String title; private String type; // Type according to: http://vocabularies.coar-repositories.org/pubby/resource_type.html - public String getData_quality_assurance() { + public List getData_quality_assurance() { return data_quality_assurance; } - public void setData_quality_assurance(String data_quality_assurance) { + public void setData_quality_assurance(List data_quality_assurance) { this.data_quality_assurance = data_quality_assurance; } @@ -143,28 +146,280 @@ public class DatasetRDAExportModel { } - public DatasetRDAExportModel fromDataModel(Dataset dataset) { - this.rdaToValueMap = getRdaValueMap(dataset); - List distributions = getDatasetDistribution(); - List datasetMetadata = getDatasetMetadata(); - List securityAndPrivacy = getSecurityAndPrivacy(); - List technicalResources = getTechnicalResource(); + public DatasetRDAExportModel fromDataModel(Dataset dataset, DatasetManager datasetManager) { + // Map of template Ids to rda values. + JSONObject jObject = new JSONObject(dataset.getProperties()); + Map templateIdsToValues = jObject.toMap(); - DatasetRDAExportModel datasetRDAExportModel = mapper.convertValue(this.rdaToValueMap, DatasetRDAExportModel.class); + /*--------- Building dataset rda export model ---------*/ + DatasetRDAExportModel datasetRDAExportModel = new DatasetRDAExportModel(); datasetRDAExportModel.setDataset_id(new IdRDAExportModel(dataset.getId().toString(), "other")); - datasetRDAExportModel.setDescription(dataset.getDescription()); + if (dataset.getDescription() != null) datasetRDAExportModel.setDescription(dataset.getDescription().replace("\n", " ")); datasetRDAExportModel.setIssued(DateFormat.getDateInstance(DateFormat.SHORT).format(dataset.getCreated())); - datasetRDAExportModel.setLanguage("en"); // mock data; + datasetRDAExportModel.setLanguage("en"); // mock data datasetRDAExportModel.setTitle(dataset.getLabel()); - datasetRDAExportModel.setDistribution(distributions); - datasetRDAExportModel.setMetadata(datasetMetadata); - datasetRDAExportModel.setSecurity_and_privacy(securityAndPrivacy); - datasetRDAExportModel.setTechnical_resource(technicalResources); + + // Transform the answered dataset description to json so we can parse it and fill the rda model. + JSONObject datasetDescriptionJson = null; + try { + String jsonResult = mapper.writeValueAsString(datasetManager.getSingle(dataset.getId().toString()).getDatasetProfileDefinition()); + datasetDescriptionJson = new JSONObject(jsonResult); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + setMultiplicityIdToFieldSetId(datasetDescriptionJson); + + /*--------- Building personal data. ---------*/ + String personalData = buildSingleProperties("dataset.personal_data", datasetDescriptionJson, templateIdsToValues); + if (personalData != null) { + datasetRDAExportModel.setPersonal_data(personalData); + } else { + datasetRDAExportModel.setPersonal_data("unknown"); + } + + /*--------- Building preservation statement. ---------*/ + datasetRDAExportModel.setPreservation_statement(buildSingleProperties("dataset.preservation_statement", datasetDescriptionJson, templateIdsToValues)); + + /*--------- Building sensitive data. ---------*/ + String sensitiveData = buildSingleProperties("dataset.sensitive_data", datasetDescriptionJson, templateIdsToValues); + if (personalData != null) { + datasetRDAExportModel.setSensitive_data(sensitiveData); + } else { + datasetRDAExportModel.setSensitive_data("unknown"); + } + + /*--------- Building type. ---------*/ + datasetRDAExportModel.setType(buildSingleProperties("dataset.type", datasetDescriptionJson, templateIdsToValues)); + + /*--------- Building data_quality_assurance. ---------*/ + datasetRDAExportModel.setData_quality_assurance(buildDataQualityAssurance(datasetDescriptionJson, templateIdsToValues, dataset.getProfile().getDefinition())); + + /*--------- Building keywords. ---------*/ + datasetRDAExportModel.setKeyword(buildKeywords(datasetDescriptionJson, templateIdsToValues, dataset.getProfile().getDefinition())); + + /*--------- Building metadata items. ---------*/ + datasetRDAExportModel.setMetadata(buildMetadata(datasetDescriptionJson, templateIdsToValues, dataset.getProfile().getDefinition())); + + /*--------- Building security and privacy items. ---------*/ + datasetRDAExportModel.setSecurity_and_privacy(buildSecurityAndPrivacy(datasetDescriptionJson, templateIdsToValues, dataset.getProfile().getDefinition())); + + /*--------- Building technical_resource. ---------*/ + datasetRDAExportModel.setTechnical_resource(buildTechnicalResource(datasetDescriptionJson, templateIdsToValues, dataset.getProfile().getDefinition())); return datasetRDAExportModel; } - private List xmlNodeListFromExpression(String xml, String expression) { + private String buildSingleProperties(String rdaKey, JSONObject datasetDescriptionJson, Map templateIdsToValues) { + String expression = "$..fields[*][?(@.rdaProperty == \"" + rdaKey + "\" )].id"; + List list = jsonValueListFromExpression(datasetDescriptionJson, expression); + if (!list.isEmpty()) { + return templateIdsToValues.get(list.get(0)).toString(); + } else { + return null; + } + } + + private List buildDataQualityAssurance(JSONObject datasetDescriptionJson, Map templateIdsToValues, String datasetProfileDefinition) { + List dataQualityFields = getRDAFieldsFromJson(datasetDescriptionJson, new String[]{"dataset.data_quality_assurance"}, datasetProfileDefinition); + for (RdaField rdaField : dataQualityFields) { + rdaField.setRdaValue(templateIdsToValues.get(rdaField.getFieldId()).toString()); + } + List dataQualityAssuranceList = new LinkedList<>(); + for (RdaField rdaField : dataQualityFields) { + dataQualityAssuranceList.add(rdaField.getRdaValue()); + } + + return dataQualityAssuranceList; + } + + private List buildKeywords(JSONObject datasetDescriptionJson, Map templateIdsToValues, String datasetProfileDefinition) { + List keywordFields = getRDAFieldsFromJson(datasetDescriptionJson, new String[]{"dataset.keyword"}, datasetProfileDefinition); + for (RdaField rdaField : keywordFields) { + rdaField.setRdaValue(templateIdsToValues.get(rdaField.getFieldId()).toString()); + } + List keywordsList = new LinkedList<>(); + for (RdaField rdaField : keywordFields) { + keywordsList.add(rdaField.getRdaValue()); + } + + return keywordsList; + } + + private List buildMetadata(JSONObject datasetDescriptionJson, Map templateIdsToValues, String datasetProfileDefinition) { + List metadataFields = getRDAFieldsFromJson(datasetDescriptionJson, + new String[]{"dataset.metadata.metadata_standard_id.type", "dataset.metadata.metadata_standard_id.identifier", "dataset.metadata.description", "dataset.metadata.language", "dataset.metadata.metadata_standard_id"}, + datasetProfileDefinition); + + // Adding rdaValue and FieldSetIds on metadataFields. + for (RdaField rdaField : metadataFields) { + rdaField.setRdaValue(templateIdsToValues.get(rdaField.getFieldId()).toString()); + } + // Group metadataFields based on their field set id. + Map> groupedMetadataFields = metadataFields.stream().collect(groupingBy(RdaField::getFieldSetId)); + + // Creating the metadata. + List metadataRDAExportModelList = new LinkedList<>(); + for (String fieldSetId : groupedMetadataFields.keySet()) { + DatasetMetadataRDAExportModel metadataRda = new DatasetMetadataRDAExportModel(); + for (RdaField rdaField : groupedMetadataFields.get(fieldSetId)) { + if (rdaField.getRdaProperty().equals("dataset.metadata.metadata_standard_id.identifier")) { + if (metadataRda.getMetadata_standard_id() != null) { + metadataRda.getMetadata_standard_id().setIdentifier(rdaField.getRdaValue()); + } else { + metadataRda.setMetadata_standard_id(new IdRDAExportModel(rdaField.getRdaValue(), "other")); + } + } + if (rdaField.getRdaProperty().equals("dataset.metadata.metadata_standard_id.type")) { + if (metadataRda.getMetadata_standard_id() != null) { + metadataRda.getMetadata_standard_id().setType(rdaField.getRdaValue()); + } else { + metadataRda.setMetadata_standard_id(new IdRDAExportModel("", rdaField.getRdaValue())); + } + } + if (rdaField.getRdaProperty().equals("dataset.metadata.description")) { + metadataRda.setDescription(rdaField.getRdaValue()); + } + if (rdaField.getRdaProperty().equals("dataset.metadata.language")) { + metadataRda.setLanguage(rdaField.getRdaValue()); + } + if (rdaField.getRdaProperty().equals("dataset.metadata.metadata_standard_id")) { + JSONArray jsonArray = new JSONArray(rdaField.getRdaValue()); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + Map jsonObjectMap = jsonObject.toMap(); + DatasetMetadataRDAExportModel metadataRda1 = new DatasetMetadataRDAExportModel(); + metadataRda1.setMetadata_standard_id(new IdRDAExportModel(jsonObjectMap.get("label").toString(), jsonObjectMap.get("source").toString())); + metadataRDAExportModelList.add(metadataRda1); + } + } + } + if (metadataRda.isValid()) { + metadataRDAExportModelList.add(metadataRda); + } + } + + return new LinkedList<>(metadataRDAExportModelList); + } + + private List buildSecurityAndPrivacy(JSONObject datasetDescriptionJson, Map templateIdsToValues, String datasetProfileDefinition) { + List secAndPrFields = getRDAFieldsFromJson( + datasetDescriptionJson, + new String[]{"dataset.security_and_privacy.description", "dataset.security_and_privacy.title", "dataset.security_and_privacy"}, + datasetProfileDefinition); + for (RdaField rdaField : secAndPrFields) { + rdaField.setRdaValue(templateIdsToValues.get(rdaField.getFieldId()).toString()); + } + Map> groupedSecurityAndPrivacyFields = secAndPrFields.stream().collect(groupingBy(RdaField::getFieldSetId)); + + List securityAndPrivacyRDAExportModelList = new LinkedList<>(); + for (String fieldSetId : groupedSecurityAndPrivacyFields.keySet()) { + DatasetSecurityAndPrivacyRDAExportModel securityAndPrivacyModel = new DatasetSecurityAndPrivacyRDAExportModel(); + for (RdaField rdaField : groupedSecurityAndPrivacyFields.get(fieldSetId)) { + if (rdaField.getRdaProperty().equals("dataset.security_and_privacy.description")) { + securityAndPrivacyModel.setDescription(rdaField.getRdaValue()); + } + if (rdaField.getRdaProperty().equals("dataset.security_and_privacy.title")) { + securityAndPrivacyModel.setTitle(rdaField.getRdaValue()); + } + if (rdaField.getRdaProperty().equals("dataset.security_and_privacy")) { + JSONArray jsonArray = new JSONArray(rdaField.getRdaValue()); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + Map jsonObjectMap = jsonObject.toMap(); + DatasetSecurityAndPrivacyRDAExportModel secAndPrivacy = new DatasetSecurityAndPrivacyRDAExportModel(jsonObjectMap.get("label").toString(), jsonObjectMap.get("source").toString()); + securityAndPrivacyRDAExportModelList.add(secAndPrivacy); + } + } + } + securityAndPrivacyRDAExportModelList.add(securityAndPrivacyModel); + } + + return securityAndPrivacyRDAExportModelList; + } + + private List buildTechnicalResource(JSONObject datasetDescriptionJson, Map templateIdsToValues, String datasetProfileDefinition) { + List dataQualityFields = getRDAFieldsFromJson(datasetDescriptionJson, + new String[]{"dataset.technical_resource.technical_resource", "dataset.technical_resource.technical_resource.description", "dataset.technical_resource.technical_resource.name"}, + datasetProfileDefinition); + for (RdaField rdaField : dataQualityFields) { + rdaField.setRdaValue(templateIdsToValues.get(rdaField.getFieldId()).toString()); + } + List technicalResourceList = new LinkedList<>(); + Map> groupedDataQualityFields = dataQualityFields.stream().collect(groupingBy(RdaField::getFieldSetId)); + for (String fieldSetId : groupedDataQualityFields.keySet()) { + DatasetTechnicalResourceRDAExportModel technicalResourceModel = new DatasetTechnicalResourceRDAExportModel(); + for (RdaField rdaField : groupedDataQualityFields.get(fieldSetId)) { + if (rdaField.getRdaProperty().equals("dataset.technical_resource.technical_resource.description")) { + technicalResourceModel.setDescription(rdaField.getRdaValue()); + } + if (rdaField.getRdaProperty().equals("dataset.technical_resource.technical_resource.name")) { + technicalResourceModel.setName(rdaField.getRdaValue()); + } + if (rdaField.getRdaProperty().equals("dataset.security_and_privacy")) { + JSONArray jsonArray = new JSONArray(rdaField.getRdaValue()); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + Map jsonObjectMap = jsonObject.toMap(); + DatasetTechnicalResourceRDAExportModel technicalResource = new DatasetTechnicalResourceRDAExportModel(jsonObjectMap.get("label").toString(), jsonObjectMap.get("label").toString()); + technicalResourceList.add(technicalResource); + } + } + } + technicalResourceList.add(technicalResourceModel); + } + + return technicalResourceList; + } + + private void setMultiplicityIdToFieldSetId(JSONObject json) { + String multiplicityItemsFieldSetIdExp = "$..multiplicityItems[*].id"; + List multiplicityItemsFieldSetIdList = jsonValueListFromExpression(json, multiplicityItemsFieldSetIdExp); + for (String fieldSetId : multiplicityItemsFieldSetIdList) { + String fieldsFromFieldSetIdExp = "$..multiplicityItems[*][?(@.id == \""+ fieldSetId +"\")].fields[*].id"; + List fieldsIdList = jsonValueListFromExpression(json, fieldsFromFieldSetIdExp); + for (String fieldId : fieldsIdList) { + this.multiplicityIdToFieldSetId.put(fieldId, fieldSetId); + } + } + } + + private List getRDAFieldsFromJson(JSONObject json, String[] rdaKey, String datasetProfileDefinition) { + List rdaFields = new LinkedList<>(); + for (String key : rdaKey) { + String fieldIdExpression = "$..fields[*][?(@.rdaProperty == \"" + key + "\" )].id"; + List listFromExpression = jsonValueListFromExpression(json, fieldIdExpression); + for (String fieldId : listFromExpression) { + RdaField rdaField = new RdaField(); + rdaField.setRdaProperty(key); + rdaField.setFieldId(fieldId); + if (fieldId.startsWith("multiple_")) { + rdaField.setFieldSetId(this.multiplicityIdToFieldSetId.get(fieldId)); + } else { + rdaField.setFieldSetId(getFieldSetIdForFieldFromXML(datasetProfileDefinition, fieldId)); + } + rdaFields.add(rdaField); + } + } + return rdaFields; + } + + private List jsonValueListFromExpression(JSONObject json, String expression) { + net.minidev.json.JSONArray jsonArray = JsonPath.parse(json.toString()).read(expression); + List valueList = new LinkedList<>(); + for (Object o : jsonArray) { + valueList.add(o.toString()); + } + return valueList; + } + + private String getFieldSetIdForFieldFromXML(String datasetProfileDefinition, String fieldId) { + String fieldSetIdExpression = "//field[@id ='" + fieldId + "']/ancestor::fieldSet/@id"; + List listFromExpression = xmlValueListFromExpression(datasetProfileDefinition, fieldSetIdExpression); + if (listFromExpression.size() == 1) return listFromExpression.get(0); + return null; + } + + private List xmlValueListFromExpression(String xml, String expression) { List valuesList = new LinkedList<>(); Document document = XmlBuilder.fromXml(xml); XPathFactory xpathFactory = XPathFactory.newInstance(); @@ -182,117 +437,4 @@ public class DatasetRDAExportModel { return valuesList; } - - private Map combineListsIntoOrderedMap (List keys, List values) { - if (keys.size() != values.size()) - throw new IllegalArgumentException ("Cannot combine lists with dissimilar sizes"); - Map map = new LinkedHashMap<>(); - for (int i=0; i getRdaValueMap(Dataset dataset) { - // Parsing dataset template definition to create a map of which question of the template corresponds to the RDA common standard. Map: TemplateId -> rdaProperty - List rdaPropertiesThatExistOnDatasetTemplate = xmlNodeListFromExpression(dataset.getProfile().getDefinition(), "//rdaCommonStandard/text()"); - List rdaProperties = new LinkedList<>(); - for (String item : rdaPropertiesThatExistOnDatasetTemplate) { - item = item.replace("dataset.", ""); - rdaProperties.add(item); - } - List datasetTemplateIdsWithRdaProperties = xmlNodeListFromExpression(dataset.getProfile().getDefinition(), "//rdaCommonStandard/text()/ancestor::field/@id"); - Map templateIdsToRDAProperties = combineListsIntoOrderedMap(datasetTemplateIdsWithRdaProperties, rdaProperties); - - // Parsing dataset answers from json to map. Map: TemplateId -> datasetValue - JSONObject jObject = new JSONObject(dataset.getProperties()); - Map templateIdsToValues = jObject.toMap(); - - // Map: rdaProperty -> datasetValue - MultiValuedMap rdaToValueMap = new ArrayListValuedHashMap<>(); - for (String templateId : templateIdsToRDAProperties.keySet()) { - if (templateIdsToValues.containsKey(templateId)) { - rdaToValueMap.put(templateIdsToRDAProperties.get(templateId), templateIdsToValues.get(templateId).toString()); - } - } - return rdaToValueMap; - } - - private List getDatasetDistribution() { - // Creates and fills a map to include distribution keys and values. - MultiValuedMap distributionJsonMap = new ArrayListValuedHashMap<>(); - for (String key : this.rdaToValueMap.keySet()) { - if (key.startsWith("distribution.")) { - distributionJsonMap.putAll(key.replace("distribution.", ""), this.rdaToValueMap.get(key)); - } - } - // Removes distribution keys from rdaToValueMap. - for (String distributionKey : distributionJsonMap.keySet()) this.rdaToValueMap.remove(distributionKey); - List distributionModels = new LinkedList<>(); - for (String key : distributionJsonMap.keySet()) { - for (String value : distributionJsonMap.get(key)) { - distributionModels.add(new DatasetDistributionRDAExportModel().fromDataModel(key, value)); - } - } - return distributionModels; - } - - private List getDatasetMetadata() { - // Creates and fills a map to include metadata keys and values. - MultiValuedMap metadataJsonMap = new ArrayListValuedHashMap<>(); - for (String key : this.rdaToValueMap.keySet()) { - if (key.startsWith("metadata.")) { - metadataJsonMap.putAll(key.replace("metadata.", ""), this.rdaToValueMap.get(key)); - } - } - // Removes metadata keys from rdaToValueMap. - for (String metadataKey : metadataJsonMap.keySet()) this.rdaToValueMap.remove(metadataKey); - List datasetMetadataRDAExportModels = new LinkedList<>(); - for (String key : metadataJsonMap.keySet()) { - for (String value : metadataJsonMap.get(key)) { - datasetMetadataRDAExportModels.add(new DatasetMetadataRDAExportModel().fromDataModel(key, value)); - } - } - return datasetMetadataRDAExportModels; - } - - private List getSecurityAndPrivacy() { - // Creates and fills a map to include SecurityAndPrivacy keys and values. - MultiValuedMap securityAndPrivacyJsonMap = new ArrayListValuedHashMap<>(); - for (String key : this.rdaToValueMap.keySet()) { - if (key.startsWith("security_and_privacy.")) { - securityAndPrivacyJsonMap.putAll(key.replace("security_and_privacy.", ""), this.rdaToValueMap.get(key)); - } - } - // Removes SecurityAndPrivacy keys from rdaToValueMap. - for (String securityAndPrivacy : securityAndPrivacyJsonMap.keySet()) this.rdaToValueMap.remove(securityAndPrivacy); - List securityAndPrivacyList= new LinkedList<>(); - for (String key : securityAndPrivacyJsonMap.keySet()) { - for (String value : securityAndPrivacyJsonMap.get(key)) { - securityAndPrivacyList.add(new DatasetSecurityAndPrivacyRDAExportModel().fromDataModel(key, value)); - } - } - return securityAndPrivacyList; - } - - private List getTechnicalResource() { - // Creates and fills a map to include Technical_Resource keys and values. - MultiValuedMap technicalResourceJsonMap = new ArrayListValuedHashMap<>(); - for (String key : this.rdaToValueMap.keySet()) { - if (key.startsWith("technical_resource.")) { - technicalResourceJsonMap.putAll(key.replace("technical_resource.", ""), this.rdaToValueMap.get(key)); - } - } - // Removes Technical_Resource keys from rdaToValueMap. - for (String techResource : technicalResourceJsonMap.keySet()) this.rdaToValueMap.remove(techResource); - List datasetTechnicalResourceRDAExportModel= new LinkedList<>(); - for (String key : technicalResourceJsonMap.keySet()) { - for (String value : technicalResourceJsonMap.get(key)) { - datasetTechnicalResourceRDAExportModel.add(new DatasetTechnicalResourceRDAExportModel().fromDataModel(key, value)); - } - } - return datasetTechnicalResourceRDAExportModel; - } - - } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetSecurityAndPrivacyRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetSecurityAndPrivacyRDAExportModel.java index 77115e086..a2d2a5581 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetSecurityAndPrivacyRDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetSecurityAndPrivacyRDAExportModel.java @@ -4,6 +4,15 @@ public class DatasetSecurityAndPrivacyRDAExportModel { private String description; private String title; + public DatasetSecurityAndPrivacyRDAExportModel() { + + } + + public DatasetSecurityAndPrivacyRDAExportModel(String description, String title) { + this.description = description; + this.title = title; + } + public String getDescription() { return description; } @@ -17,13 +26,4 @@ public class DatasetSecurityAndPrivacyRDAExportModel { public void setTitle(String title) { this.title = title; } - - public DatasetSecurityAndPrivacyRDAExportModel fromDataModel(String key, Object value) { - DatasetSecurityAndPrivacyRDAExportModel securityAndPrivacy = new DatasetSecurityAndPrivacyRDAExportModel(); - if (key.contains("description")) - securityAndPrivacy.setDescription(value.toString()); - else if (key.contains("title")) - securityAndPrivacy.setTitle(value.toString()); - return securityAndPrivacy; - } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetTechnicalResourceRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetTechnicalResourceRDAExportModel.java index 96ad0c3fb..6c47ea98e 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetTechnicalResourceRDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DatasetTechnicalResourceRDAExportModel.java @@ -18,12 +18,11 @@ public class DatasetTechnicalResourceRDAExportModel { this.name = name; } - public DatasetTechnicalResourceRDAExportModel fromDataModel(String key, Object value) { - DatasetTechnicalResourceRDAExportModel technicalResource = new DatasetTechnicalResourceRDAExportModel(); - if (key.contains("description")) - technicalResource.setDescription(value.toString()); - else if (key.contains("name")) - technicalResource.setName(value.toString()); - return technicalResource; + public DatasetTechnicalResourceRDAExportModel(String description, String name) { + this.description = description; + this.name = name; } -} + + public DatasetTechnicalResourceRDAExportModel() { + } +} \ No newline at end of file diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpRDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpRDAExportModel.java index 7c2b02eaf..53fda76d0 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpRDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/DmpRDAExportModel.java @@ -4,6 +4,7 @@ import eu.eudat.data.entities.DMP; import eu.eudat.data.entities.Dataset; import eu.eudat.data.entities.UserDMP; import eu.eudat.data.entities.UserInfo; +import eu.eudat.logic.managers.DatasetManager; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -126,7 +127,7 @@ public class DmpRDAExportModel { this.title = title; } - public DmpRDAExportModel fromDataModel(DMP entity) { + public DmpRDAExportModel fromDataModel(DMP entity, DatasetManager datasetManager) { DmpRDAExportModel dmpRda = new DmpRDAExportModel(); dmpRda.contact = new ContactRDAExportModel().fromDataModel(entity.getUsers().stream().filter(x -> x.getRole().equals(UserDMP.UserDMPRoles.OWNER.getValue())).findFirst().get().getUser()); if (entity.getUsers().stream().anyMatch(x -> x.getRole().equals(UserDMP.UserDMPRoles.USER.getValue()))) { @@ -141,9 +142,9 @@ public class DmpRDAExportModel { dmpRda.dataset = new LinkedList<>(); for (Dataset dataset : entity.getDataset()) { if (dataset.getStatus() != Dataset.Status.DELETED.getValue() && dataset.getStatus() != Dataset.Status.CANCELED.getValue()) - dmpRda.dataset.add(new DatasetRDAExportModel().fromDataModel(dataset)); + dmpRda.dataset.add(new DatasetRDAExportModel().fromDataModel(dataset, datasetManager)); } - dmpRda.description = entity.getDescription(); + dmpRda.description = entity.getDescription().replace("\n", " "); if (entity.getDoi() != null) { dmpRda.dmp_id = new IdRDAExportModel(entity.getDoi(), "zenodo"); } @@ -151,9 +152,7 @@ public class DmpRDAExportModel { dmpRda.dmp_id = new IdRDAExportModel(entity.getId().toString(), "other"); } // Mock up data on "language" and "ethical_issues_*" for now. - // dmpRda.ethical_issues_description = null; dmpRda.ethical_issues_exist = "unknown"; - // dmpRda.ethical_issues_report = null; dmpRda.language = "en"; dmpRda.modified = formatter.format(new Date()); dmpRda.project = new ProjectRDAExportModel().fromDataModel(entity.getGrant()); diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RDAExportModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RDAExportModel.java index eae34fa60..ad3d3c16b 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RDAExportModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RDAExportModel.java @@ -2,6 +2,7 @@ package eu.eudat.models.data.rda; import eu.eudat.data.entities.DMP; import eu.eudat.data.entities.Dataset; +import eu.eudat.logic.managers.DatasetManager; import java.util.LinkedList; import java.util.List; @@ -16,8 +17,8 @@ public class RDAExportModel { this.dmp = dmp; } - public RDAExportModel fromDataModel(DMP dmp) { - this.dmp = new DmpRDAExportModel().fromDataModel(dmp); + public RDAExportModel fromDataModel(DMP dmp, DatasetManager datasetManager) { + this.dmp = new DmpRDAExportModel().fromDataModel(dmp, datasetManager); return this; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RdaField.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RdaField.java new file mode 100644 index 000000000..31acd5c51 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/rda/RdaField.java @@ -0,0 +1,36 @@ +package eu.eudat.models.data.rda; + +public class RdaField { + private String rdaProperty; + private String rdaValue; + private String fieldId; + private String fieldSetId; + + public String getRdaProperty() { + return rdaProperty; + } + public void setRdaProperty(String rdaProperty) { + this.rdaProperty = rdaProperty; + } + + public String getRdaValue() { + return rdaValue; + } + public void setRdaValue(String rdaValue) { + this.rdaValue = rdaValue; + } + + public String getFieldId() { + return fieldId; + } + public void setFieldId(String fieldId) { + this.fieldId = fieldId; + } + + public String getFieldSetId() { + return fieldSetId; + } + public void setFieldSetId(String fieldSetId) { + this.fieldSetId = fieldSetId; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/user/components/datasetprofile/Field.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/user/components/datasetprofile/Field.java index f01ecf678..ea4301ef6 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/user/components/datasetprofile/Field.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/user/components/datasetprofile/Field.java @@ -28,6 +28,7 @@ public class Field implements Comparable, PropertiesModelBuilder, ViewStyleDefin private List multiplicityItems; private List validations; private Visibility visible; + private String rdaProperty; public List getMultiplicityItems() { return multiplicityItems; @@ -137,6 +138,14 @@ public class Field implements Comparable, PropertiesModelBuilder, ViewStyleDefin this.numbering = numbering; } + public String getRdaProperty() { + return rdaProperty; + } + + public void setRdaProperty(String rdaProperty) { + this.rdaProperty = rdaProperty; + } + public Field cloneForMultiplicity(String key, Map properties) { Field newField = new Field(); newField.id = key; @@ -148,6 +157,7 @@ public class Field implements Comparable, PropertiesModelBuilder, ViewStyleDefin newField.defaultValue = this.defaultValue; newField.data = this.data; newField.validations = this.validations; + newField.rdaProperty = this.rdaProperty; return newField; } @@ -160,6 +170,7 @@ public class Field implements Comparable, PropertiesModelBuilder, ViewStyleDefin field.setDefaultValue(this.defaultValue); field.setVisible(this.visible); field.setValidations(this.validations); + field.setRdaCommonStandard(this.rdaProperty); return field; } @@ -173,6 +184,7 @@ public class Field implements Comparable, PropertiesModelBuilder, ViewStyleDefin this.defaultValue = item.getDefaultValue(); this.visible = item.getVisible(); this.validations = item.getValidations(); + this.rdaProperty = item.getRdaCommonStandard(); } @Override diff --git a/dmp-backend/web/src/main/resources/RDACommonStandards.txt b/dmp-backend/web/src/main/resources/RDACommonStandards.txt index 8c543d6aa..697e195b2 100644 --- a/dmp-backend/web/src/main/resources/RDACommonStandards.txt +++ b/dmp-backend/web/src/main/resources/RDACommonStandards.txt @@ -22,6 +22,7 @@ dataset.distribution.license.start_date dataset.distribution.title dataset.keyword dataset.language +dataset.metadata.description dataset.metadata.language dataset.metadata.metadata_standard_id dataset.metadata.metadata_standard_id.identifier From b3422f83ef6dd3fb6068c4cafc1d544e9301b8b3 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Wed, 11 Dec 2019 12:55:40 +0200 Subject: [PATCH 007/106] Adds missing changes for RDA refactor. --- .../eudat/logic/managers/DataManagementPlanManager.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index 8dde96a2d..49d0816f2 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -1,5 +1,6 @@ package eu.eudat.logic.managers; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import eu.eudat.configurations.dynamicgrant.DynamicGrantConfiguration; import eu.eudat.configurations.dynamicgrant.entities.Property; @@ -944,13 +945,14 @@ public class DataManagementPlanManager { return fileEnvelope; } - public ResponseEntity getRDAJsonDocument(String id, Principal principal) throws IOException { + public ResponseEntity getRDAJsonDocument(String id, DatasetManager datasetManager, Principal principal) throws IOException { eu.eudat.data.entities.DMP dmp = databaseRepository.getDmpDao().find(UUID.fromString(id)); - if (!dmp.isPublic() && dmp.getUsers().stream().filter(userInfo -> userInfo.getUser().getId() == principal.getId()).collect(Collectors.toList()).size() == 0) + if (!dmp.isPublic() && dmp.getUsers().stream().noneMatch(userInfo -> userInfo.getUser().getId() == principal.getId())) throw new UnauthorisedException(); - RDAExportModel rdaExportModel = new RDAExportModel().fromDataModel(dmp); + RDAExportModel rdaExportModel = new RDAExportModel().fromDataModel(dmp, datasetManager); ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); String fileName = dmp.getLabel(); fileName = fileName.replaceAll("[^a-zA-Z0-9+ ]", ""); File file = new File(fileName); From 16d57bd0ad9f8604f87d0a55d3b066258b906fcc Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Wed, 11 Dec 2019 16:51:03 +0200 Subject: [PATCH 008/106] dmp advanced editor changed to remain at the same page when saving --- dmp-frontend/src/app/app.module.ts | 40 +- .../forms/validation/custom-validator.ts | 32 -- .../model/contact/contact-email-form-model.ts | 8 +- .../dashboard/dashboard-statistics-model.ts | 2 - .../dmp-create-wizard-form.model.ts | 10 +- .../dmp/invitation/dmp-invitation-user.ts | 2 +- .../app/core/services/auth/auth.service.ts | 21 +- .../dataset-profile.service.ts | 24 +- .../dataset-wizard/dataset-wizard.service.ts | 4 +- .../core/services/dmp/dmp-profile.service.ts | 4 +- .../src/app/core/services/dmp/dmp.service.ts | 4 +- .../grant/grant-file-upload.service.ts | 4 +- .../auto-complete/auto-complete.module.ts | 10 +- .../multiple-auto-complete-configuration.ts | 16 +- .../multiple-auto-complete.component.html | 67 +++- .../multiple-auto-complete.component.scss | 37 +- .../multiple-auto-complete.component.ts | 352 ++++++++++-------- .../single-auto-complete-configuration.ts | 24 +- .../single-auto-complete.component.html | 54 +-- .../single-auto-complete.component.scss | 69 ++-- .../single/single-auto-complete.component.ts | 309 ++++++++------- .../confirmation-dialog.component.scss | 44 --- .../confirmation-dialog.module.ts | 13 - .../deactivate/can-deactivate.guard.ts | 28 +- .../deactivate/deactivate.component.ts | 2 +- .../export-method-dialog.module.ts | 4 +- .../notification/notification.component.ts | 8 +- .../notification/notification.module.ts | 8 +- .../library/url-listing/url-listing.module.ts | 6 +- dmp-frontend/src/app/ui/about/about.module.ts | 6 +- .../admin/page-editor-model.ts | 6 +- .../dataset-profile/dataset-profile.module.ts | 56 +-- ...rofile-editor-composite-field.component.ts | 2 +- ...rofile-editor-combo-box-field.component.ts | 10 +- ...r-internal-dmp-entities-field.component.ts | 19 +- .../dataset-profile-editor-field.component.ts | 29 +- ...ataset-profile-editor-section.component.ts | 16 +- .../dataset-profile-editor.component.ts | 27 +- .../criteria/dataset-profile.component.ts | 10 +- .../dataset-profile-listing.component.ts | 20 +- .../dataset-profile-preview.component.ts | 8 +- .../admin/dmp-profile/dmp-profile.module.ts | 20 +- .../editor/dmp-profile-editor.component.ts | 42 +-- .../editor/dmp-profile-editor.model.ts | 12 +- .../dmp-profile-criteria.component.ts | 16 +- .../listing/dmp-profile-listing.component.ts | 22 +- .../criteria/user-criteria.component.ts | 10 +- .../role-editor/user-role-editor.component.ts | 20 +- .../src/app/ui/admin/user/user.module.ts | 6 +- .../auth/admin-login/admin-login.component.ts | 11 +- .../ui/auth/admin-login/admin-login.module.ts | 8 +- .../b2access/b2access-login.component.ts | 18 +- .../configurable-login.component.ts | 22 +- .../email-confirmation.component.ts | 20 +- .../linkedin-login.component.ts | 12 +- .../src/app/ui/auth/login/login.component.ts | 15 +- .../src/app/ui/auth/login/login.module.ts | 26 +- .../openaire-login.component.ts | 16 +- .../orcid-login/orcid-login.component.ts | 26 +- .../twitter-login/twitter-login.component.ts | 12 +- .../configurableProviders.service.ts | 4 +- .../ui/auth/login/utilities/login.service.ts | 8 +- .../contact-content.component.ts | 16 +- .../src/app/ui/contact/contact.module.ts | 8 +- .../app/ui/dashboard/dashboard.component.ts | 47 ++- .../src/app/ui/dashboard/dashboard.module.ts | 33 +- .../quick-wizard-create-add.component.ts | 16 +- .../recent-activity.component.ts | 6 +- .../recent-edited-activity.component.ts | 29 +- .../recent-visited-activity.component.ts | 20 +- .../dataset-create-wizard.component.ts | 25 +- .../dataset-create-wizard.model.ts | 12 +- .../dataset-create-wizard.module.ts | 27 +- .../dataset-dmp-selector.component.ts | 26 +- .../dataset-copy-dialogue.component.ts | 10 +- .../dataset-editor.component.ts | 2 +- .../dataset-wizard-editor.model.ts | 26 +- .../dataset-wizard.component.ts | 53 ++- ...et-external-references-editor.component.ts | 125 +++---- ...data-repository-dialog-editor.component.ts | 6 +- ...xternal-dataset-dialog-editor.component.ts | 6 +- ...ternal-registry-dialog-editor.component.ts | 6 +- ...xternal-service-dialog-editor.component.ts | 6 +- .../src/app/ui/dataset/dataset.module.ts | 44 +-- .../criteria/dataset-criteria.component.ts | 62 +-- .../dataset-upload-dialogue.component.ts | 29 +- .../listing/dataset-listing.component.ts | 26 +- .../app/ui/dmp/clone/dmp-clone.component.ts | 34 +- dmp-frontend/src/app/ui/dmp/dmp.module.ts | 64 ++-- .../add-researcher.component.ts | 9 +- .../add-researcher/add-researcher.model.ts | 8 +- .../available-profiles.component.ts | 10 +- .../ui/dmp/editor/dmp-editor.component.html | 6 +- .../app/ui/dmp/editor/dmp-editor.component.ts | 93 +++-- .../src/app/ui/dmp/editor/dmp-editor.model.ts | 42 +-- .../dmp-finalize-dialog.component.ts | 6 +- .../general-tab/general-tab.component.ts | 30 +- .../dmp/editor/grant-tab/funder-form-model.ts | 13 +- .../dmp/editor/grant-tab/grant-tab-model.ts | 15 +- .../editor/grant-tab/grant-tab.component.ts | 24 +- .../editor/grant-tab/project-form-model.ts | 14 +- .../editor/people-tab/people-tab.component.ts | 2 +- .../dmp-invitation-accepted.component.ts | 4 +- .../invitation/dmp-invitation.component.ts | 21 +- .../criteria/dmp-criteria.component.ts | 42 +-- .../ui/dmp/listing/dmp-listing.component.ts | 26 +- .../ui/dmp/overview/dmp-overview.component.ts | 30 +- .../ui/dmp/overview/dmp-overview.module.ts | 16 +- .../ui/dmp/wizard/dmp-wizard-editor.model.ts | 31 +- .../app/ui/dmp/wizard/dmp-wizard.component.ts | 29 +- .../editor/dmp-wizard-editor.component.ts | 40 +- .../dmp-wizard-dataset-listing.component.ts | 14 +- .../explore-dataset-listing.component.ts | 24 +- .../explore-dataset/explore-dataset.module.ts | 16 +- .../explore-dataset-filter-item.component.ts | 10 +- .../explore-dataset-filters.component.ts | 60 +-- .../explore-dmp-filter-item.component.ts | 10 +- .../explore-dmp-filters.component.ts | 48 +-- .../explore-dmp-listing.component.ts | 22 +- .../app/ui/explore-dmp/explore-dmp.module.ts | 18 +- dmp-frontend/src/app/ui/faq/faq.module.ts | 4 +- .../src/app/ui/glossary/glossary.module.ts | 6 +- .../ui/grant/editor/grant-editor.component.ts | 30 +- .../app/ui/grant/editor/grant-editor.model.ts | 17 +- dmp-frontend/src/app/ui/grant/grant.module.ts | 18 +- .../criteria/grant-criteria.component.ts | 12 +- .../grant/listing/grant-listing.component.ts | 22 +- .../ui/misc/breadcrumb/breadcrumb.module.ts | 6 +- .../breadcrumb/service/breadcrumb.service.ts | 8 +- .../misc/criteria/base-criteria.component.ts | 4 +- .../form-field/form-field.component.ts | 36 +- .../form-progress-indication.component.ts | 4 +- .../dataset-description-form.component.ts | 8 +- .../dataset-description-form.model.ts | 10 +- .../dataset-description-form.module.ts | 26 +- .../form-focus/form-focus.service.ts | 2 +- .../table-of-contents.ts | 7 +- .../external-sources.module.ts | 8 +- .../external-item-listing.component.ts | 11 +- .../help-content/help-content.component.ts | 6 +- .../misc/help-content/help-content.module.ts | 4 +- .../misc/navigation/navigation.component.ts | 28 +- .../ui/misc/navigation/navigation.module.ts | 9 +- .../unauthorized/unauthorized.component.ts | 4 +- .../misc/unauthorized/unauthorized.module.ts | 6 +- .../src/app/ui/navbar/navbar.component.ts | 19 +- .../src/app/ui/navbar/navbar.module.ts | 10 +- .../dataset-editor-wizard-model.ts | 23 +- .../dataset-editor-wizard.component.ts | 12 +- .../dmp-editor/dmp-editor-wizard-model.ts | 18 +- .../dmp-editor/dmp-editor-wizard.component.ts | 22 +- .../grant-editor/grant-editor-wizard-model.ts | 14 +- .../grant-editor-wizard.component.ts | 24 +- .../quick-wizard-editor.component.ts | 38 +- .../quick-wizard-editor.model.ts | 61 ++- .../ui/quick-wizard/quick-wizard.module.ts | 30 +- .../sidebar-footer/privacy/privacy.module.ts | 12 +- .../sidebar-footer.component.ts | 18 +- .../sidebar-footer/terms/terms.module.ts | 6 +- .../src/app/ui/sidebar/sidebar.module.ts | 10 +- .../ui/user-profile/user-profile.component.ts | 14 +- .../ui/user-profile/user-profile.module.ts | 6 +- dmp-frontend/src/assets/i18n/en.json | 22 +- .../common/base/base-enum-utils.service.ts | 17 + .../src/common/base/base-form-editor-model.ts | 8 + .../src/common/base/base-form-editor.ts | 111 ++++++ .../src/common/base/base-http.service.ts | 39 ++ .../base/base-pending-changes.component.ts | 17 + .../core => }/common/base/base.component.ts | 0 dmp-frontend/src/common/base/base.guard.ts | 14 + dmp-frontend/src/common/base/base.pipe.ts | 14 + .../core => }/common/base/base.service.ts | 0 .../tenant-configuration-editor.component.ts | 20 + .../common/date/moment-utc-date-adapter.ts | 3 +- .../common/forms/common-forms.module.ts | 6 + dmp-frontend/src/common/forms/form-service.ts | 81 ++++ ...rm-validation-errors-dialog.component.html | 11 + ...rm-validation-errors-dialog.component.scss | 5 + ...form-validation-errors-dialog.component.ts | 78 ++++ .../form-validation-errors-dialog.module.ts | 25 ++ .../form-validation-errors-directive.ts | 20 + .../pending-form-changes-guard.service.ts | 34 ++ .../forms/validation/custom-validator.ts | 100 +++++ .../error-model/validation-error-model.ts | 2 +- .../forms/validation/validation-context.ts | 0 .../{app => }/common/http/base-http-params.ts | 0 .../common/http/common-http.module.ts | 0 .../common/http/image/secure-image.pipe.ts | 16 + .../common/http/interceptor-context.ts | 0 .../interceptors/auth-token.interceptor.ts | 2 +- .../http/interceptors/base.interceptor.ts | 2 +- .../http/interceptors/interceptor-type.ts | 0 .../http/interceptors/json.interceptor.ts | 0 .../http/interceptors/locale.interceptor.ts | 0 .../progress-indication.interceptor.ts | 2 +- .../request-timing.interceptor.ts | 2 +- .../response-payload.interceptor.ts | 0 .../interceptors/status-code.interceptor.ts | 0 .../unauthorized-response.interceptor.ts | 2 +- .../common/material/material.module.ts | 0 .../confirmation-dialog.component.html | 0 .../confirmation-dialog.component.scss | 45 +++ .../confirmation-dialog.component.ts | 0 .../confirmation-dialog.module.ts | 14 + .../http-error-handling.service.ts | 67 ++++ .../errors-component/errors.component.html | 34 ++ .../errors-component/errors.component.scss | 14 + .../errors-component/errors.component.ts | 21 ++ .../errors/errors-handler/errors-handler.ts | 51 +++ .../errors-routing/errors-routing.module.ts | 14 + .../common/modules/errors/errors.module.ts | 34 ++ .../external-tracing/external-trace-entry.ts | 20 + .../server-errors.interceptor.ts | 13 + .../popup/popup-notification.component.html | 5 + .../popup/popup-notification.component.ts | 16 + .../snack-bar-notification.component.html | 1 + .../snack-bar-notification.component.ts | 15 + .../notification/ui-notification-service.ts | 60 +++ .../ui-notification.component.html | 1 + .../ui-notification.component.scss | 15 + .../notification/ui-notification.component.ts | 55 +++ .../notification/ui-notification.module.ts | 26 ++ .../page-not-found.component.html | 1 + .../page-not-found.component.ts | 13 + .../page-not-found/page-not-found.module.ts | 12 + .../src/{app => }/common/types/guid.ts | 0 .../common/types/json/json-serializer.ts | 2 +- .../common/types/json/serializable.ts | 0 .../src/{app => }/common/types/pair.ts | 0 .../{app => }/common/ui/common-ui.module.ts | 10 +- dmp-frontend/tsconfig.json | 31 +- 231 files changed, 3192 insertions(+), 1942 deletions(-) delete mode 100644 dmp-frontend/src/app/common/forms/validation/custom-validator.ts delete mode 100644 dmp-frontend/src/app/library/confirmation-dialog/confirmation-dialog.component.scss delete mode 100644 dmp-frontend/src/app/library/confirmation-dialog/confirmation-dialog.module.ts create mode 100644 dmp-frontend/src/common/base/base-enum-utils.service.ts create mode 100644 dmp-frontend/src/common/base/base-form-editor-model.ts create mode 100644 dmp-frontend/src/common/base/base-form-editor.ts create mode 100644 dmp-frontend/src/common/base/base-http.service.ts create mode 100644 dmp-frontend/src/common/base/base-pending-changes.component.ts rename dmp-frontend/src/{app/core => }/common/base/base.component.ts (100%) create mode 100644 dmp-frontend/src/common/base/base.guard.ts create mode 100644 dmp-frontend/src/common/base/base.pipe.ts rename dmp-frontend/src/{app/core => }/common/base/base.service.ts (100%) create mode 100644 dmp-frontend/src/common/base/tenant-configuration-editor.component.ts rename dmp-frontend/src/{app => }/common/date/moment-utc-date-adapter.ts (93%) rename dmp-frontend/src/{app => }/common/forms/common-forms.module.ts (55%) create mode 100644 dmp-frontend/src/common/forms/form-service.ts create mode 100644 dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.html create mode 100644 dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.scss create mode 100644 dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.ts create mode 100644 dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.module.ts create mode 100644 dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-directive.ts create mode 100644 dmp-frontend/src/common/forms/pending-form-changes/pending-form-changes-guard.service.ts create mode 100644 dmp-frontend/src/common/forms/validation/custom-validator.ts rename dmp-frontend/src/{app => }/common/forms/validation/error-model/validation-error-model.ts (97%) rename dmp-frontend/src/{app => }/common/forms/validation/validation-context.ts (100%) rename dmp-frontend/src/{app => }/common/http/base-http-params.ts (100%) rename dmp-frontend/src/{app => }/common/http/common-http.module.ts (100%) create mode 100644 dmp-frontend/src/common/http/image/secure-image.pipe.ts rename dmp-frontend/src/{app => }/common/http/interceptor-context.ts (100%) rename dmp-frontend/src/{app => }/common/http/interceptors/auth-token.interceptor.ts (91%) rename dmp-frontend/src/{app => }/common/http/interceptors/base.interceptor.ts (94%) rename dmp-frontend/src/{app => }/common/http/interceptors/interceptor-type.ts (100%) rename dmp-frontend/src/{app => }/common/http/interceptors/json.interceptor.ts (100%) rename dmp-frontend/src/{app => }/common/http/interceptors/locale.interceptor.ts (100%) rename dmp-frontend/src/{app => }/common/http/interceptors/progress-indication.interceptor.ts (87%) rename dmp-frontend/src/{app => }/common/http/interceptors/request-timing.interceptor.ts (92%) rename dmp-frontend/src/{app => }/common/http/interceptors/response-payload.interceptor.ts (100%) rename dmp-frontend/src/{app => }/common/http/interceptors/status-code.interceptor.ts (100%) rename dmp-frontend/src/{app => }/common/http/interceptors/unauthorized-response.interceptor.ts (97%) rename dmp-frontend/src/{app => }/common/material/material.module.ts (100%) rename dmp-frontend/src/{app/library => common/modules}/confirmation-dialog/confirmation-dialog.component.html (100%) create mode 100644 dmp-frontend/src/common/modules/confirmation-dialog/confirmation-dialog.component.scss rename dmp-frontend/src/{app/library => common/modules}/confirmation-dialog/confirmation-dialog.component.ts (100%) create mode 100644 dmp-frontend/src/common/modules/confirmation-dialog/confirmation-dialog.module.ts create mode 100644 dmp-frontend/src/common/modules/errors/error-handling/http-error-handling.service.ts create mode 100644 dmp-frontend/src/common/modules/errors/errors-component/errors.component.html create mode 100644 dmp-frontend/src/common/modules/errors/errors-component/errors.component.scss create mode 100644 dmp-frontend/src/common/modules/errors/errors-component/errors.component.ts create mode 100644 dmp-frontend/src/common/modules/errors/errors-handler/errors-handler.ts create mode 100644 dmp-frontend/src/common/modules/errors/errors-routing/errors-routing.module.ts create mode 100644 dmp-frontend/src/common/modules/errors/errors.module.ts create mode 100644 dmp-frontend/src/common/modules/errors/external-tracing/external-trace-entry.ts create mode 100644 dmp-frontend/src/common/modules/errors/server-errors-interceptor/server-errors.interceptor.ts create mode 100644 dmp-frontend/src/common/modules/notification/popup/popup-notification.component.html create mode 100644 dmp-frontend/src/common/modules/notification/popup/popup-notification.component.ts create mode 100644 dmp-frontend/src/common/modules/notification/snack-bar/snack-bar-notification.component.html create mode 100644 dmp-frontend/src/common/modules/notification/snack-bar/snack-bar-notification.component.ts create mode 100644 dmp-frontend/src/common/modules/notification/ui-notification-service.ts create mode 100644 dmp-frontend/src/common/modules/notification/ui-notification.component.html create mode 100644 dmp-frontend/src/common/modules/notification/ui-notification.component.scss create mode 100644 dmp-frontend/src/common/modules/notification/ui-notification.component.ts create mode 100644 dmp-frontend/src/common/modules/notification/ui-notification.module.ts create mode 100644 dmp-frontend/src/common/modules/page-not-found/page-not-found.component.html create mode 100644 dmp-frontend/src/common/modules/page-not-found/page-not-found.component.ts create mode 100644 dmp-frontend/src/common/modules/page-not-found/page-not-found.module.ts rename dmp-frontend/src/{app => }/common/types/guid.ts (100%) rename dmp-frontend/src/{app => }/common/types/json/json-serializer.ts (82%) rename dmp-frontend/src/{app => }/common/types/json/serializable.ts (100%) rename dmp-frontend/src/{app => }/common/types/pair.ts (100%) rename dmp-frontend/src/{app => }/common/ui/common-ui.module.ts (62%) diff --git a/dmp-frontend/src/app/app.module.ts b/dmp-frontend/src/app/app.module.ts index d40363ad6..47ea72a8b 100644 --- a/dmp-frontend/src/app/app.module.ts +++ b/dmp-frontend/src/app/app.module.ts @@ -1,31 +1,31 @@ import { OverlayModule } from '@angular/cdk/overlay'; import { HttpClient, HttpClientModule } from '@angular/common/http'; import { LOCALE_ID, NgModule } from '@angular/core'; -import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatMomentDateModule, MAT_MOMENT_DATE_FORMATS } from '@angular/material-moment-adapter'; +import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core'; import { BrowserModule, Title } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { AppRoutingModule } from '@app/app-routing.module'; +import { AppComponent } from '@app/app.component'; +import { CoreServiceModule } from '@app/core/core-service.module'; +import { CultureService } from '@app/core/services/culture/culture-service'; +import { NotificationModule } from '@app/library/notification/notification.module'; +import { LoginModule } from '@app/ui/auth/login/login.module'; +import { DatasetCreateWizardModule } from '@app/ui/dataset-create-wizard/dataset-create-wizard.module'; +import { BreadcrumbModule } from '@app/ui/misc/breadcrumb/breadcrumb.module'; +import { HelpContentModule } from '@app/ui/misc/help-content/help-content.module'; +import { NavigationModule } from '@app/ui/misc/navigation/navigation.module'; +import { NavbarModule } from '@app/ui/navbar/navbar.module'; +import { SidebarModule } from '@app/ui/sidebar/sidebar.module'; +import { MomentUtcDateAdapter } from '@common/date/moment-utc-date-adapter'; +import { CommonHttpModule } from '@common/http/common-http.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateHttpLoader } from '@ngx-translate/http-loader'; -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; -import { MomentUtcDateAdapter } from './common/date/moment-utc-date-adapter'; -import { CommonHttpModule } from './common/http/common-http.module'; -import { CommonUiModule } from './common/ui/common-ui.module'; -import { CoreServiceModule } from './core/core-service.module'; -import { CultureService } from './core/services/culture/culture-service'; -import { NotificationModule } from './library/notification/notification.module'; -import { BreadcrumbModule } from './ui/misc/breadcrumb/breadcrumb.module'; -import { HelpContentModule } from './ui/misc/help-content/help-content.module'; -import { NavigationModule } from './ui/misc/navigation/navigation.module'; -import { LoginModule } from './ui/auth/login/login.module'; -import { ReactiveFormsModule, FormsModule } from '@angular/forms'; -import { DatasetCreateWizardModule } from './ui/dataset-create-wizard/dataset-create-wizard.module'; -import { NavbarModule } from './ui/navbar/navbar.module'; -import { SidebarModule } from './ui/sidebar/sidebar.module'; -import { NgcCookieConsentModule, NgcCookieConsentConfig } from 'ngx-cookieconsent'; -import { CookieService } from "ngx-cookie-service"; -import { environment } from '../environments/environment'; +import { environment } from 'environments/environment'; +import { CookieService } from 'ngx-cookie-service'; +import { NgcCookieConsentConfig, NgcCookieConsentModule } from 'ngx-cookieconsent'; // AoT requires an exported function for factories export function HttpLoaderFactory(http: HttpClient) { diff --git a/dmp-frontend/src/app/common/forms/validation/custom-validator.ts b/dmp-frontend/src/app/common/forms/validation/custom-validator.ts deleted file mode 100644 index ee70c8eaf..000000000 --- a/dmp-frontend/src/app/common/forms/validation/custom-validator.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { AbstractControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'; -import { ValidationErrorModel } from './error-model/validation-error-model'; - -export function BackendErrorValidator(errorModel: ValidationErrorModel, propertyName: string): ValidatorFn { - return (control: AbstractControl): { [key: string]: any } => { - const error: String = errorModel.getError(propertyName); - return error ? { 'backendError': { message: error } } : null; - }; -} - -export function E164PhoneValidator(): ValidatorFn { - return Validators.pattern('^\\+?[1-9]\\d{1,14}$'); -} - -// Getter is required because the index of each element is not fixed (array does not always follow LIFO) -export function BackendArrayErrorValidator(errorModel: ValidationErrorModel, propertyNameGetter: () => string): ValidatorFn { - return (control: AbstractControl): { [key: string]: any } => { - const error: String = errorModel.getError(propertyNameGetter()); - return error ? { 'backendError': { message: error } } : null; - }; -} - -export function CustomErrorValidator(errorModel: ValidationErrorModel, propertyNames: string[]): ValidatorFn { - return (control: AbstractControl): { [key: string]: any } => { - const error: String = errorModel.getErrors(propertyNames); - return error ? { 'customError': { message: error } } : null; - }; -} - -export function PasswordMatchValidator(formGroup: FormGroup) { - return formGroup.get('password').value === formGroup.get('passwordConfirm').value ? null : { 'passwordMismatch': true }; -} diff --git a/dmp-frontend/src/app/core/model/contact/contact-email-form-model.ts b/dmp-frontend/src/app/core/model/contact/contact-email-form-model.ts index 51cd07722..9a2df910e 100644 --- a/dmp-frontend/src/app/core/model/contact/contact-email-form-model.ts +++ b/dmp-frontend/src/app/core/model/contact/contact-email-form-model.ts @@ -1,5 +1,5 @@ -import { ValidationErrorModel } from "../../../common/forms/validation/error-model/validation-error-model"; -import { FormGroup, FormBuilder, Validators } from "@angular/forms"; +import { FormBuilder, FormGroup, Validators } from "@angular/forms"; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; export interface ContactEmail { subject: string; @@ -19,8 +19,8 @@ export class ContactEmailFormModel { buildForm(): FormGroup { const formGroup = new FormBuilder().group({ - subject: [ this.subject, [Validators.required] ], - description: [ this.description, [Validators.required] ] + subject: [this.subject, [Validators.required]], + description: [this.description, [Validators.required]] }); return formGroup; } diff --git a/dmp-frontend/src/app/core/model/dashboard/dashboard-statistics-model.ts b/dmp-frontend/src/app/core/model/dashboard/dashboard-statistics-model.ts index 4a83f56cc..1b11ace71 100644 --- a/dmp-frontend/src/app/core/model/dashboard/dashboard-statistics-model.ts +++ b/dmp-frontend/src/app/core/model/dashboard/dashboard-statistics-model.ts @@ -1,5 +1,3 @@ -import { Serializable } from "../../../common/types/json/serializable"; - export interface DashboardStatisticsModel { totalDataManagementPlanCount: number; totalGrantCount: number; diff --git a/dmp-frontend/src/app/core/model/dmp/dmp-create-wizard/dmp-create-wizard-form.model.ts b/dmp-frontend/src/app/core/model/dmp/dmp-create-wizard/dmp-create-wizard-form.model.ts index a3303ccac..f12e350cb 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp-create-wizard/dmp-create-wizard-form.model.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp-create-wizard/dmp-create-wizard-form.model.ts @@ -1,9 +1,9 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms"; -import { BackendErrorValidator } from "../../../../common/forms/validation/custom-validator"; -import { ValidationErrorModel } from "../../../../common/forms/validation/error-model/validation-error-model"; -import { ValidationContext } from "../../../../common/forms/validation/validation-context"; -import { DatasetProfileModel } from "../../dataset/dataset-profile"; -import { DmpModel } from "../dmp"; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; export class DmpCreateWizardFormModel { dmp: DmpModel; diff --git a/dmp-frontend/src/app/core/model/dmp/invitation/dmp-invitation-user.ts b/dmp-frontend/src/app/core/model/dmp/invitation/dmp-invitation-user.ts index 7634679cb..7c1163475 100644 --- a/dmp-frontend/src/app/core/model/dmp/invitation/dmp-invitation-user.ts +++ b/dmp-frontend/src/app/core/model/dmp/invitation/dmp-invitation-user.ts @@ -1,5 +1,5 @@ import { FormBuilder, FormGroup } from '@angular/forms'; -import { Serializable } from '../../../../common/types/json/serializable'; +import { Serializable } from '@common/types/json/serializable'; export class DmpInvitationUser implements Serializable { diff --git a/dmp-frontend/src/app/core/services/auth/auth.service.ts b/dmp-frontend/src/app/core/services/auth/auth.service.ts index 7eea789d2..bcb59345a 100644 --- a/dmp-frontend/src/app/core/services/auth/auth.service.ts +++ b/dmp-frontend/src/app/core/services/auth/auth.service.ts @@ -1,21 +1,18 @@ -import { of as observableOf, throwError as observableThrowError, Observable } from 'rxjs'; - -import { map, catchError, takeUntil } from 'rxjs/operators'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { MatSnackBar } from '@angular/material/snack-bar'; import { Router } from '@angular/router'; +import { Credential } from '@app/core/model/auth/credential'; +import { LoginInfo } from '@app/core/model/auth/login-info'; +import { Principal } from '@app/core/model/auth/Principal'; +import { ConfigurableProvider } from '@app/core/model/configurable-provider/configurableProvider'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { BaseService } from '@common/base/base.service'; import { TranslateService } from '@ngx-translate/core'; -import { environment } from '../../../../environments/environment'; -import { SnackBarNotificationComponent } from '../../../library/notification/snack-bar/snack-bar-notification.component'; -import { BaseService } from '../../common/base/base.service'; -import { Credential } from '../../model/auth/credential'; -import { LoginInfo } from '../../model/auth/login-info'; -import { Principal } from '../../model/auth/Principal'; -import { UiNotificationService, SnackBarNotificationLevel } from '../notification/ui-notification-service'; -import { ConfigurableProvider } from "../../model/configurable-provider/configurableProvider"; - +import { environment } from 'environments/environment'; +import { Observable, of as observableOf, throwError as observableThrowError } from 'rxjs'; +import { catchError, map, takeUntil } from 'rxjs/operators'; @Injectable() export class AuthService extends BaseService { diff --git a/dmp-frontend/src/app/core/services/dataset-profile/dataset-profile.service.ts b/dmp-frontend/src/app/core/services/dataset-profile/dataset-profile.service.ts index 56d259e2e..2d19bdea8 100644 --- a/dmp-frontend/src/app/core/services/dataset-profile/dataset-profile.service.ts +++ b/dmp-frontend/src/app/core/services/dataset-profile/dataset-profile.service.ts @@ -1,19 +1,19 @@ import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; +import { DatasetProfile } from '@app/core/model/admin/dataset-profile/dataset-profile'; +import { DataTableData } from '@app/core/model/data-table/data-table-data'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetProfileDefinitionModel } from '@app/core/model/dataset-profile-definition/dataset-profile-definition'; +import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { BaseHttpService } from '@app/core/services/http/base-http.service'; +import { DatasetProfileEditorModel } from '@app/ui/admin/dataset-profile/editor/dataset-profile-editor-model'; +import { BaseService } from '@common/base/base.service'; +import { BaseHttpParams } from '@common/http/base-http-params'; +import { InterceptorType } from '@common/http/interceptors/interceptor-type'; +import { environment } from 'environments/environment'; import { Observable } from 'rxjs'; import { takeUntil } from "rxjs/operators"; -import { environment } from '../../../../environments/environment'; -import { BaseHttpParams } from '../../../common/http/base-http-params'; -import { InterceptorType } from '../../../common/http/interceptors/interceptor-type'; -import { DatasetProfileEditorModel } from '../../../ui/admin/dataset-profile/editor/dataset-profile-editor-model'; -import { BaseService } from "../../common/base/base.service"; -import { DatasetProfile } from '../../model/admin/dataset-profile/dataset-profile'; -import { DataTableData } from '../../model/data-table/data-table-data'; -import { DataTableRequest } from '../../model/data-table/data-table-request'; -import { DatasetProfileDefinitionModel } from '../../model/dataset-profile-definition/dataset-profile-definition'; -import { DatasetListingModel } from '../../model/dataset/dataset-listing'; -import { DatasetProfileCriteria } from '../../query/dataset-profile/dataset-profile-criteria'; -import { BaseHttpService } from '../http/base-http.service'; @Injectable() export class DatasetProfileService extends BaseService { diff --git a/dmp-frontend/src/app/core/services/dataset-wizard/dataset-wizard.service.ts b/dmp-frontend/src/app/core/services/dataset-wizard/dataset-wizard.service.ts index e11802ccd..ef43731f6 100644 --- a/dmp-frontend/src/app/core/services/dataset-wizard/dataset-wizard.service.ts +++ b/dmp-frontend/src/app/core/services/dataset-wizard/dataset-wizard.service.ts @@ -2,8 +2,8 @@ import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { environment } from '../../../../environments/environment'; -import { BaseHttpParams } from '../../../common/http/base-http-params'; -import { InterceptorType } from '../../../common/http/interceptors/interceptor-type'; +import { BaseHttpParams } from '../../../../common/http/base-http-params'; +import { InterceptorType } from '../../../../common/http/interceptors/interceptor-type'; import { DatasetProfileDefinitionModel } from '../../model/dataset-profile-definition/dataset-profile-definition'; import { DatasetProfileModel } from '../../model/dataset/dataset-profile'; import { DatasetWizardModel } from '../../model/dataset/dataset-wizard'; diff --git a/dmp-frontend/src/app/core/services/dmp/dmp-profile.service.ts b/dmp-frontend/src/app/core/services/dmp/dmp-profile.service.ts index cbb28a893..a6679c832 100644 --- a/dmp-frontend/src/app/core/services/dmp/dmp-profile.service.ts +++ b/dmp-frontend/src/app/core/services/dmp/dmp-profile.service.ts @@ -10,8 +10,8 @@ import { RequestItem } from '../../query/request-item'; import { DataTableData } from '../../model/data-table/data-table-data'; import { DmpProfileCriteria } from '../../query/dmp/dmp-profile-criteria'; import { DatasetListingModel } from '../../model/dataset/dataset-listing'; -import { BaseHttpParams } from '../../../common/http/base-http-params'; -import { InterceptorType } from '../../../common/http/interceptors/interceptor-type'; +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'; @Injectable() diff --git a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts index 2df142252..0edd621a9 100644 --- a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts +++ b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts @@ -2,8 +2,8 @@ import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { environment } from '../../../../environments/environment'; -import { BaseHttpParams } from '../../../common/http/base-http-params'; -import { InterceptorType } from '../../../common/http/interceptors/interceptor-type'; +import { BaseHttpParams } from '../../../../common/http/base-http-params'; +import { InterceptorType } from '../../../../common/http/interceptors/interceptor-type'; import { DynamicFieldGrantCriteria } from '../../../models/dynamic-field-grant/DynamicFieldGrantCriteria'; import { DataTableData } from '../../model/data-table/data-table-data'; import { DataTableRequest } from '../../model/data-table/data-table-request'; diff --git a/dmp-frontend/src/app/core/services/grant/grant-file-upload.service.ts b/dmp-frontend/src/app/core/services/grant/grant-file-upload.service.ts index 094f4bdef..a4cd0a646 100644 --- a/dmp-frontend/src/app/core/services/grant/grant-file-upload.service.ts +++ b/dmp-frontend/src/app/core/services/grant/grant-file-upload.service.ts @@ -4,8 +4,8 @@ import { Observable } from 'rxjs'; import { environment } from '../../../../environments/environment'; import { ContentFile } from '../../model/grant/grant-listing'; import { BaseHttpService } from '../http/base-http.service'; -import { BaseHttpParams } from '../../../common/http/base-http-params'; -import { InterceptorType } from '../../../common/http/interceptors/interceptor-type'; +import { BaseHttpParams } from '../../../../common/http/base-http-params'; +import { InterceptorType } from '../../../../common/http/interceptors/interceptor-type'; @Injectable() export class GrantFileUploadService { diff --git a/dmp-frontend/src/app/library/auto-complete/auto-complete.module.ts b/dmp-frontend/src/app/library/auto-complete/auto-complete.module.ts index b7cf221e6..cbb060569 100644 --- a/dmp-frontend/src/app/library/auto-complete/auto-complete.module.ts +++ b/dmp-frontend/src/app/library/auto-complete/auto-complete.module.ts @@ -1,9 +1,9 @@ import { NgModule } from '@angular/core'; -import { CommonFormsModule } from '../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { MultipleAutoCompleteComponent } from './multiple/multiple-auto-complete.component'; -import { SingleAutoCompleteComponent } from './single/single-auto-complete.component'; -import { FormattingModule } from '../../core/formatting.module'; +import { FormattingModule } from '@app/core/formatting.module'; +import { MultipleAutoCompleteComponent } from '@app/library/auto-complete/multiple/multiple-auto-complete.component'; +import { SingleAutoCompleteComponent } from '@app/library/auto-complete/single/single-auto-complete.component'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete-configuration.ts b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete-configuration.ts index 98c86ee8d..ebb0be39f 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete-configuration.ts +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete-configuration.ts @@ -1,17 +1,20 @@ +import { TemplateRef } from '@angular/core'; import { Observable } from 'rxjs'; import { AutoCompleteGroup } from '../auto-complete-group'; export interface MultipleAutoCompleteConfiguration { // Delay for performing the request. Default: 200ms. requestDelay?: number; - // Min characters for the filtering to be applied. Default: 1. + // Min characters for the filtering to be applied. Default: 3. minFilteringChars?: number; // Load and present items from start, without user query. Default: true. loadDataOnStart?: boolean; // Static or initial items. - initialItems?: (excludedItems: any[]) => Observable; + initialItems?: (excludedItems: any[], data?: any) => Observable; // Data retrieval function filterFn?: (searchQuery: string, excludedItems: any[]) => Observable; + // Get selected items. Used when valueAssign is used so the full object can be retrieved for presentation. + getSelectedItems?: (selectedItems: any[]) => Observable; // Property formating for input displayFn?: (item: any) => string; // Function to group results in the drop down @@ -20,6 +23,15 @@ export interface MultipleAutoCompleteConfiguration { titleFn?: (item: any) => string; // Display function for the drop down subtitle subtitleFn?: (item: any) => string; + //Extra data passed to query function + extraData?: any; // Callback to intercept value assignment based on item selection valueAssign?: (selectedItem: any) => any; + // Property formating template + optionTemplate?: TemplateRef; + // Selected value formating template + selectedValueTemplate?: TemplateRef; + + + autoSelectFirstOptionOnBlur?: boolean; } diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html index adc236268..add09a812 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html @@ -1,28 +1,57 @@ -
- - - {{this._displayFn(selectedItem)}} - cancel - - +
+ + + + + +
{{_displayFn(selectedItem)}}
+ cancel +
+
+
- - + + keyboard_arrow_down + - - {{_titleFn(item)}} -
- {{_subtitleFn(item)}} + + + +
+ {{_titleFn(item)}} +
+ {{_subtitleFn(item)}} +
- - {{_titleFn(item)}} -
- {{_subtitleFn(item)}} -
+
+ + + + +
+ {{_titleFn(item)}} +
+ {{_subtitleFn(item)}} +
+
+
+ + No results found! + +
+ + loading... +
-
+
\ No newline at end of file diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss index 07c37ced4..cdaa669c8 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss @@ -1,32 +1,21 @@ .multiple-auto-complete { - margin-left: inherit; - margin-right: inherit; + margin-left: inherit; + margin-right: inherit; - .multi-chip-list { - padding-left: 0; + .not-loading { + display: none; + } - .chip { - border-radius: 2em !important; - height: auto !important; - min-width: fit-content !important; - } - } + + .align-arrow-right { + position: absolute; + right: 0; + vertical-align: middle; + } - .multi-loading-bar { - padding-right: 0; - padding-left: 0; - } - - .not-loading { - display: none; - } } .two-line-mat-option { - // height: 3.5em; - line-height: 1.2em; -} - -::ng-deep .mat-autocomplete-panel.panel-width { - max-width: 78vw !important; + height: 3.5em; + line-height: 1.2em; } diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts index a19d1c55d..a81bf3b2f 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts @@ -1,15 +1,25 @@ import { FocusMonitor } from '@angular/cdk/a11y'; import { COMMA, ENTER } from '@angular/cdk/keycodes'; -import { Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Optional, Output, Self, ViewChild } from '@angular/core'; -import { ControlValueAccessor, NgControl } from '@angular/forms'; -import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete'; -import { MatChipInputEvent } from '@angular/material/chips'; +import { Component, DoCheck, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Optional, Output, Self, SimpleChanges, TemplateRef, ViewChild } from '@angular/core'; +import { ControlValueAccessor, FormGroupDirective, NgControl, NgForm } from '@angular/forms'; +import { ErrorStateMatcher, MatChipInputEvent, mixinErrorState } from '@angular/material'; +import { MatAutocomplete, MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete'; import { MatFormFieldControl } from '@angular/material/form-field'; +import { AutoCompleteGroup } from '@app/library/auto-complete/auto-complete-group'; +import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; +import { BaseComponent } from '@common/base/base.component'; import { Observable, of as observableOf, Subject } from 'rxjs'; -import { debounceTime, distinctUntilChanged, map, mergeMap, startWith, tap } from 'rxjs/operators'; -import { AutoCompleteGroup } from '../auto-complete-group'; -import { MultipleAutoCompleteConfiguration } from './multiple-auto-complete-configuration'; -import { switchMap } from 'rxjs/internal/operators/switchMap'; +import { debounceTime, distinctUntilChanged, map, mergeMap, startWith, takeUntil } from 'rxjs/operators'; + +export class CustomComponentBase extends BaseComponent { + constructor( + public _defaultErrorStateMatcher: ErrorStateMatcher, + public _parentForm: NgForm, + public _parentFormGroup: FormGroupDirective, + public ngControl: NgControl + ) { super(); } +} +export const _CustomComponentMixinBase = mixinErrorState(CustomComponentBase); @Component({ selector: 'app-multiple-auto-complete', @@ -17,40 +27,39 @@ import { switchMap } from 'rxjs/internal/operators/switchMap'; styleUrls: ['./multiple-auto-complete.component.scss'], providers: [{ provide: MatFormFieldControl, useExisting: MultipleAutoCompleteComponent }] }) -export class MultipleAutoCompleteComponent implements OnInit, MatFormFieldControl, ControlValueAccessor, OnDestroy { +export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase implements OnInit, MatFormFieldControl, ControlValueAccessor, OnDestroy, DoCheck, OnChanges { static nextId = 0; + @ViewChild('autocomplete', { static: true }) autocomplete: MatAutocomplete; + @ViewChild('autocompleteTrigger', { static: true }) autocompleteTrigger: MatAutocompleteTrigger; + @ViewChild('autocompleteInput', { static: true }) autocompleteInput: ElementRef; - separatorKeysCodes = [ENTER, COMMA]; + @Input() + get configuration(): MultipleAutoCompleteConfiguration { return this._configuration; } + set configuration(configuration: MultipleAutoCompleteConfiguration) { + this._configuration = configuration; + } + private _configuration: MultipleAutoCompleteConfiguration; - @Input() configuration: MultipleAutoCompleteConfiguration; // Selected Option Event @Output() optionSelected: EventEmitter = new EventEmitter(); - // Removed Option Event @Output() optionRemoved: EventEmitter = new EventEmitter(); id = `multiple-autocomplete-${MultipleAutoCompleteComponent.nextId++}`; stateChanges = new Subject(); focused = false; - errorState = false; controlType = 'multiple-autocomplete'; describedBy = ''; - _inputValue: string; + inputValue = ''; _inputSubject = new Subject(); - loading = false; _items: Observable; + _selectedItems: Map = new Map(); _groupedItems: Observable; - private requestDelay = 200; //ms - private minFilteringChars = 1; - private loadDataOnStart = true; - visible = true; - selectable = true; + selectable = false; removable = true; - addOnBlur = false; + separatorKeysCodes = [ENTER, COMMA]; - get empty() { - return !this._inputValue || this._inputValue.length === 0; - } + get empty() { return (!this.value || this.value.length === 0) && (!this.inputValue || this.inputValue.length === 0); } get shouldLabelFloat() { return this.focused || !this.empty; } @@ -83,21 +92,22 @@ export class MultipleAutoCompleteComponent implements OnInit, MatFormFieldContro return this._selectedValue; } set value(value: any | null) { - this._selectedValue = value; - this._inputValue = value; + this._selectedValue = (value != null && value.length === 0) ? null : value; this.stateChanges.next(); } private _selectedValue; - @ViewChild('textInput', { static: true }) textInput: ElementRef; - @ViewChild(MatAutocompleteTrigger, { static: true }) autocomplete: MatAutocompleteTrigger; - constructor( private fm: FocusMonitor, private elRef: ElementRef, - @Optional() @Self() public ngControl: NgControl) { + @Optional() @Self() public ngControl: NgControl, + @Optional() _parentForm: NgForm, + @Optional() _parentFormGroup: FormGroupDirective, + _defaultErrorStateMatcher: ErrorStateMatcher + ) { + super(_defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl); - fm.monitor(elRef.nativeElement, true).subscribe((origin) => { + fm.monitor(elRef.nativeElement, true).pipe(takeUntil(this._destroyed)).subscribe((origin) => { this.focused = !!origin; this.stateChanges.next(); }); @@ -109,83 +119,84 @@ export class MultipleAutoCompleteComponent implements OnInit, MatFormFieldContro } } - ngOnInit() { + ngOnInit() { } + + ngDoCheck(): void { + if (this.ngControl) { + this.updateErrorState(); + } + } + + ngOnChanges(changes: SimpleChanges) { + if (changes['configuration'] && changes['configuration'].isFirstChange) { + this.getSelectedItems(this.value); + } + } + + getSelectedItems(value: any) { + if (value != null && Array.isArray(value) && this.configuration) { + const newSelections = value.filter(x => !this._selectedItems.has(JSON.stringify(x))); + if (newSelections.length > 0 && this.configuration.getSelectedItems != null) { + this.configuration.getSelectedItems(newSelections).pipe(takeUntil(this._destroyed)).subscribe(x => { + x.forEach(element => { + this._selectedItems.set(JSON.stringify(this.configuration.valueAssign != null ? this.configuration.valueAssign(element) : element), element); + }); + }); + } else { + newSelections.forEach(element => { + this._selectedItems.set(JSON.stringify(this.configuration.valueAssign != null ? this.configuration.valueAssign(element) : element), element); + }); + } + } } filter(query: string): Observable { // If loadDataOnStart is enabled and query is empty we return the initial items. if (this.isNullOrEmpty(query) && this.loadDataOnStart) { - return this.configuration.initialItems(this.value || []) || observableOf([]); + return this.configuration.initialItems(this.configuration.extraData) || observableOf([]); } else if (query && query.length >= this.minFilteringChars) { if (this.configuration.filterFn) { - return this.configuration.filterFn(query, this.value || []); + return this.configuration.filterFn(query, this.configuration.extraData); } else { - return this.configuration.initialItems(this.value || []) || observableOf([]); + return this.configuration.initialItems(this.configuration.extraData) || observableOf([]); } } else { return observableOf([]); } } + stringify(value: any): string { + return JSON.stringify(value); + } + isNullOrEmpty(query: string): boolean { return typeof query !== 'string' || query === null || query.length === 0; } - _displayFn(item: any): string { - if (this.configuration.displayFn && item) { return this.configuration.displayFn(item); } - return item; - } - - _titleFn(item: any): string { - if (this.configuration.titleFn && item) { return this.configuration.titleFn(item); } - return item; - } - - _subtitleFn(item: any): string { - if (this.configuration.subtitleFn && item) { return this.configuration.subtitleFn(item); } - return null; - } - - _requestDelay(): number { - return this.configuration.requestDelay || this.requestDelay; - } - - _minFilteringChars(): number { - return this.configuration.minFilteringChars || this.minFilteringChars; - } - - _loadDataOnStart(): boolean { - return this.configuration.loadDataOnStart || this.loadDataOnStart; - } - - _chipItems(): any[] { - return this.value || []; - } - - _arraysEqual(arr1, arr2) { - if (arr1.length !== arr2.length) - return false; - for (var i = arr1.length; i--;) { - if (arr1[i].id !== arr2[i].id) - return false; - } - - return true; - } - _optionSelected(event: MatAutocompleteSelectedEvent) { - if (this.configuration.valueAssign) { - const newValue = this.configuration.valueAssign(this.value) || []; - newValue.push(event.option.value); - this._setValue(this.configuration.valueAssign(newValue)); - } - else { - const newValue = this.value || []; - newValue.push(event.option.value); - this._setValue(newValue); - this.stateChanges.next(); - this.optionSelected.emit(newValue); - this.textInput.nativeElement.value = ''; + this.optionSelectedInternal(event.option.value); + this.autocompleteInput.nativeElement.value = ''; + } + + private optionSelectedInternal(item: any) { + const newValue = this._valueToAssign(item); + + //Update selected items + this._selectedItems.set(JSON.stringify(newValue), item); + + const newValueArray = (Array.isArray(this.value) ? this.value : []); + newValueArray.push(newValue); + this._setValue(newValueArray); + + this.stateChanges.next(); + this.optionSelected.emit(item); + } + + public onKeyUp(event) { + this.inputValue = event.target.value; + // prevent filtering results if arrow were pressed + if (event.keyCode !== ENTER && (event.keyCode < 37 || event.keyCode > 40)) { + this._inputSubject.next(this.inputValue); } } @@ -201,88 +212,39 @@ export class MultipleAutoCompleteComponent implements OnInit, MatFormFieldContro startWith(null), debounceTime(this.requestDelay), distinctUntilChanged(), - tap(() => { this.loading = true; }), - switchMap(query => { - // If its a valid object, a selection just made and the object is set as the value of the form control. That means we should fire an extra request to the server. - if (this._isValidObject(query)) { return observableOf([]); } - - // Since the object is changed we need to clear any existing selections, except for the first time. - // if (query !== null) { this.pushChanges(null); } - return this.filter(query); - }), - tap(() => { this.loading = false; })); + distinctUntilChanged(), + mergeMap(query => this.filter(query))); if (this.configuration.groupingFn) { this._groupedItems = this._items.pipe(map(items => this.configuration.groupingFn(items))); } } } - _inputValueChange(value: string) { - this._inputValue = value; - this._inputSubject.next(value); - this.stateChanges.next(); - } - - _isValidObject(value: any): boolean { - try { - if (!value) { return false; } - if (typeof value !== 'object') { JSON.parse(value); } - } catch (e) { - return false; - } - return true; - } - - _removeSelectedItem(item: any): void { - if (this.configuration.valueAssign) { - this.optionRemoved.emit(item); - this.textInput.nativeElement.focus(); - } - else { - const index = this.value.indexOf(item); - if (index >= 0) { - this.value.splice(index, 1); - this.optionRemoved.emit(item); - } - this.textInput.nativeElement.focus(); - this.pushChanges(this.value); + public onBlur($event: MouseEvent) { + if (this.inputValue && this.inputValue.length > 1 && this.autocomplete.options && this.autocomplete.options.length > 0 && this.autoSelectFirstOptionOnBlur) { + this.optionSelectedInternal(this.autocomplete.options.first.value); } } - _onInputClick(item: any) { - if (!this.autocomplete.panelOpen) { - this.autocomplete.openPanel(); - } - } - - _addItem(event: MatChipInputEvent): void { - // const input = event.input; - // const value = event.value; - // // Add our fruit - // if ((value || '').trim()) { - // this.selectedItems.push(value.trim()); - // } - // // Reset the input value - // if (input) { - // input.value = ''; - // } - // this.inputFormControl.setValue(null); - } onChange = (_: any) => { }; - onTouched = () => { }; - writeValue(value: any): void { this.value = value || ''; } + private _onTouched = () => { }; + writeValue(value: any): void { + this.value = Array.isArray(value) ? value : null; + // Update chips observable + this.getSelectedItems(value); + } pushChanges(value: any) { this.onChange(value); } registerOnChange(fn: (_: any) => {}): void { this.onChange = fn; } - registerOnTouched(fn: () => {}): void { this.onTouched = fn; } + registerOnTouched(fn: () => {}): void { this._onTouched = fn; } setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; } - - setDescribedByIds(ids: string[]) { - this.describedBy = ids.join(' '); - } + setDescribedByIds(ids: string[]) { this.describedBy = ids.join(' '); } onContainerClick(event: MouseEvent) { - if ((event.target as Element).tagName.toLowerCase() !== 'input') { - this.elRef.nativeElement.querySelector('input').focus(); + event.stopPropagation(); + this._onInputFocus(); + if (this.disabled) { return; } + if (!this.autocomplete.isOpen) { + this.autocompleteTrigger.openPanel(); } } @@ -290,4 +252,80 @@ export class MultipleAutoCompleteComponent implements OnInit, MatFormFieldContro this.stateChanges.complete(); this.fm.stopMonitoring(this.elRef.nativeElement); } -} + + //Configuration getters + _displayFn(item: any): string { + // console.log('_displayFn' + item); + if (this.configuration.displayFn && item) { return this.configuration.displayFn(item); } + return item; + } + + _titleFn(item: any): string { + if (this.configuration.titleFn && item) { return this.configuration.titleFn(item); } + return item; + } + + _optionTemplate(item: any): TemplateRef { + if (this.configuration.optionTemplate && item) { return this.configuration.optionTemplate; } + return null; + } + + _selectedValueTemplate(item: any): TemplateRef { + if (this.configuration.selectedValueTemplate && item) { return this.configuration.selectedValueTemplate; } + return null; + } + + _subtitleFn(item: any): string { + if (this.configuration.subtitleFn && item) { return this.configuration.subtitleFn(item); } + return null; + } + + _valueToAssign(item: any): any { + if (this.configuration.valueAssign && item) { return this.configuration.valueAssign(item); } + return item; + } + + get requestDelay(): number { + return this.configuration.requestDelay != null ? this.configuration.requestDelay : 200; + } + + get minFilteringChars(): number { + return this.configuration.minFilteringChars != null ? this.configuration.minFilteringChars : 1; + } + + get loadDataOnStart(): boolean { + return this.configuration.loadDataOnStart != null ? this.configuration.loadDataOnStart : true; + } + + get autoSelectFirstOptionOnBlur(): boolean { + return this.configuration.autoSelectFirstOptionOnBlur != null ? this.configuration.autoSelectFirstOptionOnBlur : false; + } + + //Chip Functions + _addItem(event: MatChipInputEvent): void { + const input = event.input; + const value = event.value; + // Add our fruit + // if ((value || '').trim()) { + // this.selectedItems.push(value.trim()); + // } + // Reset the input value + if (input) { + this.inputValue = ''; + } + //this.inputFormControl.setValue(null); + } + + _removeSelectedItem(item: any, event: MouseEvent): void { + if (event != null) { event.stopPropagation(); } + const valueToDelete = this._valueToAssign(item); + this.value = this.value.filter(x => JSON.stringify(x) !== JSON.stringify(valueToDelete)); //TODO, maybe we need to implement equality here differently. + this.optionRemoved.emit(item); + + //Update chips + this._selectedItems.delete(JSON.stringify(valueToDelete)); + + this.autocompleteInput.nativeElement.focus(); + this.pushChanges(this.value); + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete-configuration.ts b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete-configuration.ts index 97aedab67..dad7fcf59 100644 --- a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete-configuration.ts +++ b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete-configuration.ts @@ -1,3 +1,4 @@ +import { TemplateRef } from '@angular/core'; import { Observable } from 'rxjs'; import { AutoCompleteGroup } from '../auto-complete-group'; @@ -8,28 +9,29 @@ export interface SingleAutoCompleteConfiguration { minFilteringChars?: number; // Load and present items from start, without user query. Default: true. loadDataOnStart?: boolean; - // Remove item after selection. - removeAfterSelection?: boolean; // Static or initial items. initialItems?: (data?: any) => Observable; // Data retrieval function filterFn?: (searchQuery: string, data?: any) => Observable; + // Get selected items. Used when valueAssign is used so the full object can be retrieved for presentation. + getSelectedItem?: (selectedItem: any) => Observable; // Property formating for input displayFn?: (item: any) => string; - // Property formating for dropdown + // Function to group results in the drop down groupingFn?: (items: any[]) => AutoCompleteGroup[]; - // Property formating for dropdown + // Display function for the drop down title titleFn?: (item: any) => string; - // Property formating for dropdown + // Display function for the drop down subtitle subtitleFn?: (item: any) => string; - // Property formating for icon on chip - iconFn?: (item: any) => string; - // Property for link on chip - linkFn?: (item: any) => string; - // Disable option. - disableOption?: (item: any) => boolean; //Extra data passed to query function extraData?: any; // Callback to intercept value assignment based on item selection valueAssign?: (selectedItem: any) => any; + // Property formating template + optionTemplate?: TemplateRef; + // Selected value formating template + selectedValueTemplate?: TemplateRef; + + + autoSelectFirstOptionOnBlur?: boolean; } diff --git a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.html b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.html index abe733c08..2fd06b044 100644 --- a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.html +++ b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.html @@ -1,32 +1,44 @@
- - - {{_iconFn(value)}} - {{_displayFn(value)}} - cancel - - - - - - + + keyboard_arrow_down + - + - {{_titleFn(item)}} -
- {{_subtitleFn(item)}} + +
+ {{_titleFn(item)}} +
+ {{_subtitleFn(item)}} +
- - - {{_titleFn(item)}} -
- {{_subtitleFn(item)}} -
+
+ + + + +
+ {{_titleFn(item)}} +
+ {{_subtitleFn(item)}} +
+
+
+ + No results found! + +
+ + loading... +
diff --git a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss index 4a8d65c72..401a5e99e 100644 --- a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss +++ b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss @@ -1,35 +1,60 @@ .auto-complete { - margin-left: inherit; - margin-right: inherit; + margin-left: inherit; + margin-right: inherit; - .not-loading { - display: none; - } + .not-loading { + display: none; + } - .chip-list { - width: 100%; - } + .chip-item { + transition: none; + background-color: transparent; + padding: 0; + box-shadow: none !important; + border-radius: unset; + min-height: auto; + height: auto; + } - .progress-loader { - position: absolute; - right: 0; - } + .chip-list { + width: 100%; + } + + .progress-loader { + position: absolute; + right: 0; + } + + .align-arrow-right { + position: absolute; + right: 0; + vertical-align: middle; + } +} + +.chip-list { + width: auto; } .two-line-mat-option { - // height: 3.5em; - line-height: 1.2em; + height: 3.5em; + line-height: 1.2em; } -.chip { - cursor: pointer; - opacity: 1 !important; +// .two-line-mat-option { +// height: 3.5em; +// line-height: 1.2em; +// } + +.mat-standard-chip:hover::after { + opacity: 0; } -.chip:hover { - background-color: #c5c5c5; +.mat-standard-chip:focus::after { + opacity: 0; } -::ng-deep .mat-autocomplete-panel.panel-width { - max-width: 78vw !important; -} + +// .mat-form-field-type-single-autocomplete:not(.mat-form-field-disabled) .mat-form-field-flex { +// cursor: pointer; +// } diff --git a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.ts b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.ts index 2079b101a..3d0f8788d 100644 --- a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.ts +++ b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.ts @@ -1,52 +1,69 @@ import { FocusMonitor } from '@angular/cdk/a11y'; -import { COMMA, ENTER } from '@angular/cdk/keycodes'; -import { Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Optional, Output, Self } from '@angular/core'; -import { ControlValueAccessor, NgControl } from '@angular/forms'; -import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; +import { ENTER } from '@angular/cdk/keycodes'; +import { Component, DoCheck, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Optional, Output, Self, SimpleChanges, TemplateRef, ViewChild } from '@angular/core'; +import { ControlValueAccessor, FormGroupDirective, NgControl, NgForm } from '@angular/forms'; +import { MatAutocomplete, MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete'; +import { ErrorStateMatcher, mixinErrorState } from '@angular/material/core'; import { MatFormFieldControl } from '@angular/material/form-field'; +import { AutoCompleteGroup } from '@app/library/auto-complete/auto-complete-group'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { BaseComponent } from '@common/base/base.component'; import { Observable, of as observableOf, Subject } from 'rxjs'; -import { debounceTime, distinctUntilChanged, map, mergeMap, startWith, tap } from 'rxjs/operators'; -import { AutoCompleteGroup } from '../auto-complete-group'; -import { SingleAutoCompleteConfiguration } from './single-auto-complete-configuration'; -import { switchMap } from 'rxjs/internal/operators/switchMap'; -import { Router } from '@angular/router'; +import { debounceTime, distinctUntilChanged, map, mergeMap, startWith, takeUntil } from 'rxjs/operators'; +export class CustomComponentBase extends BaseComponent { + constructor( + public _defaultErrorStateMatcher: ErrorStateMatcher, + public _parentForm: NgForm, + public _parentFormGroup: FormGroupDirective, + public ngControl: NgControl + ) { super(); } +} +export const _CustomComponentMixinBase = mixinErrorState(CustomComponentBase); + @Component({ selector: 'app-single-auto-complete', templateUrl: './single-auto-complete.component.html', styleUrls: ['./single-auto-complete.component.scss'], providers: [{ provide: MatFormFieldControl, useExisting: SingleAutoCompleteComponent }], }) -export class SingleAutoCompleteComponent implements OnInit, MatFormFieldControl, ControlValueAccessor, OnDestroy { +export class SingleAutoCompleteComponent extends _CustomComponentMixinBase implements OnInit, MatFormFieldControl, ControlValueAccessor, OnDestroy, DoCheck, OnChanges { static nextId = 0; + @ViewChild('autocomplete', { static: true }) autocomplete: MatAutocomplete; + @ViewChild('autocompleteTrigger', { static: true }) autocompleteTrigger: MatAutocompleteTrigger; + @ViewChild('autocompleteInput', { static: true }) autocompleteInput: ElementRef; + + @Input() initialSelectedData: any; + @Input() + get configuration(): SingleAutoCompleteConfiguration { return this._configuration; } + set configuration(configuration: SingleAutoCompleteConfiguration) { + this._configuration = configuration; + //On startup, fill the input with the existing value + if (this.autocompleteInput && this.value) { + this.inputValue = this._displayFn(this.value); + } + } + private _configuration: SingleAutoCompleteConfiguration; - @Input() configuration: SingleAutoCompleteConfiguration; // Selected Option Event @Output() optionSelected: EventEmitter = new EventEmitter(); - // Removed Option Event - @Output() optionRemoved: EventEmitter = new EventEmitter(); id = `single-autocomplete-${SingleAutoCompleteComponent.nextId++}`; stateChanges = new Subject(); focused = false; - errorState = false; controlType = 'single-autocomplete'; describedBy = ''; - _inputValue: string; + inputValue = ''; _inputSubject = new Subject(); loading = false; _items: Observable; _groupedItems: Observable; - private requestDelay = 200; //ms - private minFilteringChars = 1; - private loadDataOnStart = true; - separatorKeysCodes: number[] = [ENTER, COMMA]; + _selectedItems: Map = new Map(); - get empty() { - return !this._inputValue || this._inputValue.length === 0; - } + + get empty() { return (this.value == null) && (!this.inputValue || this.inputValue.length === 0); } get shouldLabelFloat() { return this.focused || !this.empty; } @@ -80,7 +97,6 @@ export class SingleAutoCompleteComponent implements OnInit, MatFormFieldControl< } set value(value: any | null) { this._selectedValue = value; - this._inputValue = (value && value != "") ? " " : null; this.stateChanges.next(); } private _selectedValue; @@ -88,10 +104,14 @@ export class SingleAutoCompleteComponent implements OnInit, MatFormFieldControl< constructor( private fm: FocusMonitor, private elRef: ElementRef, - private router: Router, - @Optional() @Self() public ngControl: NgControl) { + @Optional() @Self() public ngControl: NgControl, + @Optional() _parentForm: NgForm, + @Optional() _parentFormGroup: FormGroupDirective, + _defaultErrorStateMatcher: ErrorStateMatcher + ) { + super(_defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl); - fm.monitor(elRef.nativeElement, true).subscribe((origin) => { + fm.monitor(elRef.nativeElement, true).pipe(takeUntil(this._destroyed)).subscribe((origin) => { this.focused = !!origin; this.stateChanges.next(); }); @@ -103,8 +123,43 @@ export class SingleAutoCompleteComponent implements OnInit, MatFormFieldControl< } } - ngOnInit() { + ngOnInit() { } + ngDoCheck(): void { + if (this.ngControl) { + this.updateErrorState(); + } + } + + ngOnChanges(changes: SimpleChanges) { + if (changes['initialSelectedData'] && changes['initialSelectedData'].currentValue && changes['initialSelectedData'].isFirstChange && this.configuration != null) { + this._selectedItems.set(JSON.stringify(this.configuration.valueAssign != null ? this.configuration.valueAssign(this.initialSelectedData) : this.initialSelectedData), this.initialSelectedData); + this.inputValue = this._displayFn(this.initialSelectedData); + } + + if (changes['configuration'] && changes['configuration'].isFirstChange) { + if (changes['initialSelectedData'] != null && this.value != null) { + if (this._valueToAssign(this.initialSelectedData) != this.value) { this.getSelectedItems(this.value); } + } else { + this.getSelectedItems(this.value); + } + } + } + + getSelectedItems(value: any) { + if (value != null && !this._selectedItems.has(JSON.stringify(value)) && this.configuration) { + if (this.configuration.getSelectedItem != null) { + this.configuration.getSelectedItem(value).pipe(takeUntil(this._destroyed)).subscribe(x => { + if (x != null) { + this._selectedItems.set(JSON.stringify(this.configuration.valueAssign != null ? this.configuration.valueAssign(x) : x), x); + this.inputValue = this._displayFn(x); + } + }); + } else { + this._selectedItems.set(JSON.stringify(this.configuration.valueAssign != null ? this.configuration.valueAssign(value) : value), value); + this.inputValue = this._displayFn(value); + } + } } filter(query: string): Observable { @@ -122,64 +177,40 @@ export class SingleAutoCompleteComponent implements OnInit, MatFormFieldControl< } } + stringify(value: any): string { + return JSON.stringify(value); + } + isNullOrEmpty(query: string): boolean { return typeof query !== 'string' || query === null || query.length === 0; } - _displayFn(item: any): string { - if (this.configuration.displayFn && item) { return this.configuration.displayFn(item); } - return item; - } - - _titleFn(item: any): string { - if (this.configuration.titleFn && item) { return this.configuration.titleFn(item); } - return item; - } - - _subtitleFn(item: any): string { - if (this.configuration.subtitleFn && item) { return this.configuration.subtitleFn(item); } - return null; - } - - _iconFn(item: any): string { - if (this.configuration.iconFn && item) { return this.configuration.iconFn(item); } - return null; - } - - _linkFn(item: any): string { - if (this.configuration.linkFn && item) { return this.configuration.linkFn(item); } - return null; - } - - _disableOption(item: any): boolean { - if (this.configuration.disableOption && item) { return this.configuration.disableOption(item); } - return null; - } - - _requestDelay(): number { - return this.configuration.requestDelay || this.requestDelay; - } - - _minFilteringChars(): number { - return this.configuration.minFilteringChars || this.minFilteringChars; - } - - _loadDataOnStart(): boolean { - return this.configuration.loadDataOnStart || this.loadDataOnStart; - } - _optionSelected(event: MatAutocompleteSelectedEvent) { - this._setValue(this.configuration.valueAssign ? this.configuration.valueAssign(event.option.value) : event.option.value); - //this._inputValue = " "; - this.stateChanges.next(); - this.optionSelected.emit(event.option.value); - if (this.configuration.removeAfterSelection) { - this.clearAutocomplete() - } + this.inputValue = this._displayFn(event.option.value); + this.optionSelectedInternal(event.option.value); } - private clearAutocomplete() { - this._setValue(null); + private optionSelectedInternal(item: any) { + const newValue = this._valueToAssign(item); + + //Update selected items + this._selectedItems.set(JSON.stringify(newValue), item); + + this._setValue(newValue); + + this.stateChanges.next(); + this.optionSelected.emit(item); + } + + public onKeyUp(event) { + this.inputValue = event.target.value; + // prevent filtering results if arrow were pressed + if (event.keyCode !== ENTER && (event.keyCode < 37 || event.keyCode > 40)) { + if (this.inputValue.length === 0 && this.value != null) { + this.optionSelectedInternal(null); + } + this._inputSubject.next(this.inputValue); + } } private _setValue(value: any) { @@ -194,72 +225,100 @@ export class SingleAutoCompleteComponent implements OnInit, MatFormFieldControl< startWith(null), debounceTime(this.requestDelay), distinctUntilChanged(), - tap(() => { this.loading = true; }), - switchMap(query => { - // If its a valid object, a selection just made and the object is set as the value of the form control. That means we should fire an extra request to the server. - if (this._isValidObject(query)) { return observableOf([]); } - - // Since the object is changed we need to clear any existing selections, except for the first time. - if (query !== null) { this.pushChanges(null); } - return this.filter(query); - }), - tap(() => { this.loading = false; })); + mergeMap(query => this.filter(query))); if (this.configuration.groupingFn) { this._groupedItems = this._items.pipe(map(items => this.configuration.groupingFn(items))); } } } - _inputValueChange(value: string) { - //this._inputValue = value; - this._inputSubject.next(value); - this.stateChanges.next(); - } - - _isValidObject(value: any): boolean { - try { - if (!value) { return false; } - if (typeof value !== 'object') { JSON.parse(value); } - } catch (e) { - return false; + public onBlur($event: MouseEvent) { + if (this.value != null) { + const inputLabel = this.inputValue; + const selectedLabel = this._displayFn(this._selectedItems.get(JSON.stringify(this.value))); + if (inputLabel && selectedLabel !== inputLabel) { + this.inputValue = selectedLabel; + } + } else if (this.inputValue && this.inputValue.length > 1 && this.autocomplete.options && this.autocomplete.options.length > 0 && this.autoSelectFirstOptionOnBlur) { + this.inputValue = this._displayFn(this.autocomplete.options.first.value); + this.optionSelectedInternal(this.autocomplete.options.first.value); } - return true; } onChange = (_: any) => { }; - onTouched = () => { }; - writeValue(value: any): void { this.value = value || ''; } + private _onTouched = () => { }; + writeValue(value: any): void { + this.value = value; + // Update chips observable + if (value != null) { this.getSelectedItems(value); } else { + if (this.autocompleteInput && this.autocompleteInput.nativeElement && this.autocompleteInput.nativeElement.value) { this.autocompleteInput.nativeElement.value = ''; } + this.inputValue = null; + } + } pushChanges(value: any) { this.onChange(value); } registerOnChange(fn: (_: any) => {}): void { this.onChange = fn; } - registerOnTouched(fn: () => {}): void { this.onTouched = fn; } + registerOnTouched(fn: () => {}): void { this._onTouched = fn; } setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; } - - setDescribedByIds(ids: string[]) { - this.describedBy = ids.join(' '); - } + setDescribedByIds(ids: string[]) { this.describedBy = ids.join(' '); } onContainerClick(event: MouseEvent) { - if ((event.target as Element).tagName.toLowerCase() !== 'input') { - this.elRef.nativeElement.querySelector('input').focus(); + event.stopPropagation(); + this._onInputFocus(); + if (this.disabled) { return; } + if (!this.autocomplete.isOpen) { + this.autocompleteTrigger.openPanel(); } } - chipRemove(): void { - this._setValue(null); - this.optionRemoved.emit(); - } - - linkToOption(value: any): void { - if (this._linkFn(value)) { - this.router.navigate([]).then(result => { window.open(this._linkFn(value), '_blank'); }); - } - } - - autoCompleteDisplayFn() { - return (val) => ""; - } - ngOnDestroy() { this.stateChanges.complete(); this.fm.stopMonitoring(this.elRef.nativeElement); } + + //Configuration getters + _displayFn(item: any): string { + // console.log('_displayFn' + item); + if (this.configuration.displayFn && item) { return this.configuration.displayFn(item); } + return item; + } + + _titleFn(item: any): string { + if (this.configuration.titleFn && item) { return this.configuration.titleFn(item); } + return item; + } + + _optionTemplate(item: any): TemplateRef { + if (this.configuration.optionTemplate && item) { return this.configuration.optionTemplate; } + return null; + } + + _selectedValueTemplate(item: any): TemplateRef { + if (this.configuration.selectedValueTemplate && item) { return this.configuration.selectedValueTemplate; } + return null; + } + + _subtitleFn(item: any): string { + if (this.configuration.subtitleFn && item) { return this.configuration.subtitleFn(item); } + return null; + } + + _valueToAssign(item: any): any { + if (this.configuration.valueAssign && item) { return this.configuration.valueAssign(item); } + return item; + } + + get requestDelay(): number { + return this.configuration.requestDelay != null ? this.configuration.requestDelay : 200; + } + + get minFilteringChars(): number { + return this.configuration.minFilteringChars != null ? this.configuration.minFilteringChars : 1; + } + + get loadDataOnStart(): boolean { + return this.configuration.loadDataOnStart != null ? this.configuration.loadDataOnStart : true; + } + + get autoSelectFirstOptionOnBlur(): boolean { + return this.configuration.autoSelectFirstOptionOnBlur != null ? this.configuration.autoSelectFirstOptionOnBlur : false; + } } diff --git a/dmp-frontend/src/app/library/confirmation-dialog/confirmation-dialog.component.scss b/dmp-frontend/src/app/library/confirmation-dialog/confirmation-dialog.component.scss deleted file mode 100644 index 025bfb9d5..000000000 --- a/dmp-frontend/src/app/library/confirmation-dialog/confirmation-dialog.component.scss +++ /dev/null @@ -1,44 +0,0 @@ -.confirmation-dialog { - .confirmation { - padding-bottom: 20px; - } - - .privacy-policy-names { - font-weight: 700; - padding: 1em; - } - - .close-btn { - margin-left: auto; - cursor: pointer; - } - - .warn-text { - color: #f44336; - } - - .cancel { - background-color: #aaaaaa; - color: #ffffff; - } - - .confirm { - background-color: #2cba6c; - color: #ffffff; - } - - .delete { - background-color: #ba2c2c; - color: #ffffff; - } - - .checkbox-privacy { - padding: 0em 1em; - } - - .required-policy { - padding: 0em 1.2em 1em; - font-size: smaller; - color: #f44336; - } -} diff --git a/dmp-frontend/src/app/library/confirmation-dialog/confirmation-dialog.module.ts b/dmp-frontend/src/app/library/confirmation-dialog/confirmation-dialog.module.ts deleted file mode 100644 index cda63242d..000000000 --- a/dmp-frontend/src/app/library/confirmation-dialog/confirmation-dialog.module.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { ConfirmationDialogComponent } from './confirmation-dialog.component'; - -@NgModule({ - imports: [CommonUiModule], - declarations: [ConfirmationDialogComponent], - exports: [ConfirmationDialogComponent], - entryComponents: [ConfirmationDialogComponent] -}) -export class ConfirmationDialogModule { - constructor() { } -} diff --git a/dmp-frontend/src/app/library/deactivate/can-deactivate.guard.ts b/dmp-frontend/src/app/library/deactivate/can-deactivate.guard.ts index aac88736e..75d89ac2d 100644 --- a/dmp-frontend/src/app/library/deactivate/can-deactivate.guard.ts +++ b/dmp-frontend/src/app/library/deactivate/can-deactivate.guard.ts @@ -1,12 +1,12 @@ import { Injectable } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { CanDeactivate } from '@angular/router'; -import { Observable } from 'rxjs'; +import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; +import { BaseComponent } from '@common/base/base.component'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { TranslateService } from '@ngx-translate/core'; +import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import { BaseComponent } from '../../core/common/base/base.component'; -import { CheckDeactivateBaseComponent } from './deactivate.component'; -import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component'; @Injectable() export class CanDeactivateGuard extends BaseComponent implements CanDeactivate { @@ -21,19 +21,19 @@ export class CanDeactivateGuard extends BaseComponent implements CanDeactivate { if (component.canDeactivate()) { - return true; - } else { - const dialogRef = this.dialog.open(ConfirmationDialogComponent, { - maxWidth: '700px', - data: { + return true; + } else { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + maxWidth: '700px', + data: { message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.LEAVE-PAGE'), warning: this.language.instant('GENERAL.CONFIRMATION-DIALOG.LEAVE-WARNING'), - cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), + cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.LEAVE'), icon: 'error_outline' - } - }); - return dialogRef.afterClosed().pipe(map(x => x ? true : false)); - } + } + }); + return dialogRef.afterClosed().pipe(map(x => x ? true : false)); + } } } diff --git a/dmp-frontend/src/app/library/deactivate/deactivate.component.ts b/dmp-frontend/src/app/library/deactivate/deactivate.component.ts index ce05a6632..2b854f125 100644 --- a/dmp-frontend/src/app/library/deactivate/deactivate.component.ts +++ b/dmp-frontend/src/app/library/deactivate/deactivate.component.ts @@ -1,5 +1,5 @@ -import { BaseComponent } from '../../core/common/base/base.component'; import { HostListener } from '@angular/core'; +import { BaseComponent } from '@common/base/base.component'; export abstract class CheckDeactivateBaseComponent extends BaseComponent { diff --git a/dmp-frontend/src/app/library/export-method-dialog/export-method-dialog.module.ts b/dmp-frontend/src/app/library/export-method-dialog/export-method-dialog.module.ts index 327bc17e7..b72241c53 100644 --- a/dmp-frontend/src/app/library/export-method-dialog/export-method-dialog.module.ts +++ b/dmp-frontend/src/app/library/export-method-dialog/export-method-dialog.module.ts @@ -1,6 +1,6 @@ import { NgModule } from '@angular/core'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { ExportMethodDialogComponent } from './export-method-dialog.component'; +import { ExportMethodDialogComponent } from '@app/library/export-method-dialog/export-method-dialog.component'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [CommonUiModule], diff --git a/dmp-frontend/src/app/library/notification/notification.component.ts b/dmp-frontend/src/app/library/notification/notification.component.ts index 20527fe02..2bc6c31b6 100644 --- a/dmp-frontend/src/app/library/notification/notification.component.ts +++ b/dmp-frontend/src/app/library/notification/notification.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { MatSnackBar } from '@angular/material/snack-bar'; +import { PopupNotification, SnackBarNotification, SnackBarNotificationLevel, UiNotificationService, UiNotificationType } from '@app/core/services/notification/ui-notification-service'; +import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component'; +import { SnackBarNotificationComponent } from '@app/library/notification/snack-bar/snack-bar-notification.component'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../core/common/base/base.component'; -import { UiNotificationService, UiNotificationType, PopupNotification, SnackBarNotification, SnackBarNotificationLevel } from '../../core/services/notification/ui-notification-service'; -import { PopupNotificationDialogComponent } from './popup/popup-notification.component'; -import { SnackBarNotificationComponent } from './snack-bar/snack-bar-notification.component'; @Component({ selector: 'app-notification', diff --git a/dmp-frontend/src/app/library/notification/notification.module.ts b/dmp-frontend/src/app/library/notification/notification.module.ts index 7d7a194d5..2abf82c9d 100644 --- a/dmp-frontend/src/app/library/notification/notification.module.ts +++ b/dmp-frontend/src/app/library/notification/notification.module.ts @@ -1,8 +1,8 @@ import { NgModule } from '@angular/core'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { NotificationComponent } from './notification.component'; -import { PopupNotificationDialogComponent } from './popup/popup-notification.component'; -import { SnackBarNotificationComponent } from './snack-bar/snack-bar-notification.component'; +import { NotificationComponent } from '@app/library/notification/notification.component'; +import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component'; +import { SnackBarNotificationComponent } from '@app/library/notification/snack-bar/snack-bar-notification.component'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/library/url-listing/url-listing.module.ts b/dmp-frontend/src/app/library/url-listing/url-listing.module.ts index c0112e256..3ee5b0996 100644 --- a/dmp-frontend/src/app/library/url-listing/url-listing.module.ts +++ b/dmp-frontend/src/app/library/url-listing/url-listing.module.ts @@ -1,7 +1,7 @@ import { NgModule } from '@angular/core'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { FormattingModule } from '../../core/formatting.module'; -import { UrlListingComponent } from './url-listing.component'; +import { FormattingModule } from '@app/core/formatting.module'; +import { UrlListingComponent } from '@app/library/url-listing/url-listing.component'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/about/about.module.ts b/dmp-frontend/src/app/ui/about/about.module.ts index e6830d4b2..0d119dc88 100644 --- a/dmp-frontend/src/app/ui/about/about.module.ts +++ b/dmp-frontend/src/app/ui/about/about.module.ts @@ -1,7 +1,7 @@ import { NgModule } from '@angular/core'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { AboutComponent } from './about.component'; -import { AboutRoutingModule } from './about.routing'; +import { AboutComponent } from '@app/ui/about/about.component'; +import { AboutRoutingModule } from '@app/ui/about/about.routing'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/page-editor-model.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/page-editor-model.ts index 1a35db433..6f16b2c02 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/page-editor-model.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/page-editor-model.ts @@ -1,7 +1,7 @@ import { FormGroup, Validators } from '@angular/forms'; -import { Page } from '../../../../core/model/admin/dataset-profile/dataset-profile'; -import { BaseFormModel } from '../../../../core/model/base-form-model'; -import { Guid } from '../../../../common/types/guid'; +import { Page } from '@app/core/model/admin/dataset-profile/dataset-profile'; +import { BaseFormModel } from '@app/core/model/base-form-model'; +import { Guid } from '@common/types/guid'; export class PageEditorModel extends BaseFormModel { public title: string; diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/dataset-profile.module.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/dataset-profile.module.ts index c4fdba9cc..1e7c9eb19 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/dataset-profile.module.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/dataset-profile.module.ts @@ -1,32 +1,32 @@ import { NgModule } from '@angular/core'; -import { CommonFormsModule } from '../../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../../common/ui/common-ui.module'; -import { FormattingModule } from '../../../core/formatting.module'; -import { DatasetProfileRoutingModule } from './dataset-profile.routing'; -import { DatasetProfileEditorDefaultValueComponent } from './editor/components/composite-profile-editor-default-value/component-profile-editor-default-value.component'; -import { DatasetProfileEditorCompositeFieldComponent } from './editor/components/composite-field/dataset-profile-editor-composite-field.component'; -import { DatasetProfileEditorAutoCompleteFieldComponent } from './editor/components/field-type/auto-complete/dataset-profile-editor-auto-complete-field.component'; -import { DatasetProfileEditorBooleanDecisionFieldComponent } from './editor/components/field-type/boolean-decision/dataset-profile-editor-boolean-decision-field.component'; -import { DatasetProfileEditorCheckboxFieldComponent } from './editor/components/field-type/checkbox/dataset-profile-editor-checkbox-field.component'; -import { DatasetProfileEditorComboBoxFieldComponent } from './editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component'; -import { DatasetProfileEditorFreeTextFieldComponent } from './editor/components/field-type/free-text/dataset-profile-editor-free-text-field.component'; -import { DatasetProfileEditorRadioBoxFieldComponent } from './editor/components/field-type/radio-box/dataset-profile-editor-radio-box-field.component'; -import { DatasetProfileEditorTextAreaFieldComponent } from './editor/components/field-type/textarea/dataset-profile-editor-text-area-field.component'; -import { DatasetProfileEditorWordListFieldComponent } from './editor/components/field-type/word-list/dataset-profile-editor-word-list-field.component'; -import { DatasetProfileEditorFieldComponent } from './editor/components/field/dataset-profile-editor-field.component'; -import { DatasetProfileEditorPageComponent } from './editor/components/page/dataset-profile-editor-page.component'; -import { DatasetProfileEditorRuleComponent } from './editor/components/rule/dataset-profile-editor-rule.component'; -import { DatasetProfileEditorSectionComponent } from './editor/components/section/dataset-profile-editor-section.component'; -import { DatasetProfileEditorComponent } from './editor/dataset-profile-editor.component'; -import { DatasetProfileCriteriaComponent } from './listing/criteria/dataset-profile.component'; -import { DatasetProfileListingComponent } from './listing/dataset-profile-listing.component'; -import { ConfirmationDialogModule } from '../../../library/confirmation-dialog/confirmation-dialog.module'; -import { DatasetProfileEditorDatePickerFieldComponent } from './editor/components/field-type/datepicker/dataset-profile-editor-date-picker-field.component'; -import { DialodConfirmationUploadDatasetProfiles } from './listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; -import { DatasetProfileEditorInternalDmpEntitiesFieldComponent } from './editor/components/field-type/internal-dmp-entities/dataset-profile-editor-internal-dmp-entities-field.component'; -import { DatasetProfileEditorResearchersAutoCompleteFieldComponent } from './editor/components/field-type/researchers-auto-complete/dataset-profile-editor-researchers-auto-complete-field.component'; -import { DatasetProfileEditorDatasetsAutoCompleteFieldComponent } from './editor/components/field-type/datasets-auto-complete/dataset-profile-editor-datasets-autocomplete-field.component'; -import { DatasetProfileEditorDmpsAutoCompleteFieldComponent } from './editor/components/field-type/dmps-auto-complete/dataset-profile-editor-dmps-autocomplete-field.component'; +import { FormattingModule } from '@app/core/formatting.module'; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; +import { DatasetProfileRoutingModule } from '@app/ui/admin/dataset-profile/dataset-profile.routing'; +import { DatasetProfileEditorCompositeFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component'; +import { DatasetProfileEditorDefaultValueComponent } from '@app/ui/admin/dataset-profile/editor/components/composite-profile-editor-default-value/component-profile-editor-default-value.component'; +import { DatasetProfileEditorAutoCompleteFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/auto-complete/dataset-profile-editor-auto-complete-field.component'; +import { DatasetProfileEditorBooleanDecisionFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/boolean-decision/dataset-profile-editor-boolean-decision-field.component'; +import { DatasetProfileEditorCheckboxFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/checkbox/dataset-profile-editor-checkbox-field.component'; +import { DatasetProfileEditorComboBoxFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component'; +import { DatasetProfileEditorDatasetsAutoCompleteFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/datasets-auto-complete/dataset-profile-editor-datasets-autocomplete-field.component'; +import { DatasetProfileEditorDatePickerFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/datepicker/dataset-profile-editor-date-picker-field.component'; +import { DatasetProfileEditorDmpsAutoCompleteFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/dmps-auto-complete/dataset-profile-editor-dmps-autocomplete-field.component'; +import { DatasetProfileEditorFreeTextFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/free-text/dataset-profile-editor-free-text-field.component'; +import { DatasetProfileEditorInternalDmpEntitiesFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/internal-dmp-entities/dataset-profile-editor-internal-dmp-entities-field.component'; +import { DatasetProfileEditorRadioBoxFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/radio-box/dataset-profile-editor-radio-box-field.component'; +import { DatasetProfileEditorResearchersAutoCompleteFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/researchers-auto-complete/dataset-profile-editor-researchers-auto-complete-field.component'; +import { DatasetProfileEditorTextAreaFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/textarea/dataset-profile-editor-text-area-field.component'; +import { DatasetProfileEditorWordListFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field-type/word-list/dataset-profile-editor-word-list-field.component'; +import { DatasetProfileEditorFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component'; +import { DatasetProfileEditorPageComponent } from '@app/ui/admin/dataset-profile/editor/components/page/dataset-profile-editor-page.component'; +import { DatasetProfileEditorRuleComponent } from '@app/ui/admin/dataset-profile/editor/components/rule/dataset-profile-editor-rule.component'; +import { DatasetProfileEditorSectionComponent } from '@app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component'; +import { DatasetProfileEditorComponent } from '@app/ui/admin/dataset-profile/editor/dataset-profile-editor.component'; +import { DatasetProfileCriteriaComponent } from '@app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component'; +import { DialodConfirmationUploadDatasetProfiles } from '@app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; +import { DatasetProfileListingComponent } from '@app/ui/admin/dataset-profile/listing/dataset-profile-listing.component'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.ts index e0ed0479f..e4fd16dfa 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormArray, FormControl, FormGroup } from '@angular/forms'; import { FieldEditorModel } from '../../../admin/field-editor-model'; -import { Guid } from '../../../../../../common/types/guid'; +import { Guid } from '@common/types/guid'; @Component({ selector: 'app-dataset-profile-editor-composite-field-component', diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component.ts index 4770e4ce9..86cc30d8d 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component.ts @@ -1,11 +1,11 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; +import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profile-combo-box-type'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { AutoCompleteFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/auto-complete-field-data-editor-model'; +import { WordListFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/word-list-field-data-editor-model'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../../../../core/common/base/base.component'; -import { DatasetProfileComboBoxType } from '../../../../../../../core/common/enum/dataset-profile-combo-box-type'; -import { EnumUtils } from '../../../../../../../core/services/utilities/enum-utils.service'; -import { AutoCompleteFieldDataEditorModel } from '../../../../admin/field-data/auto-complete-field-data-editor-model'; -import { WordListFieldDataEditorModel } from '../../../../admin/field-data/word-list-field-data-editor-model'; @Component({ selector: 'app-dataset-profile-editor-combo-box-field-component', diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/internal-dmp-entities/dataset-profile-editor-internal-dmp-entities-field.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/internal-dmp-entities/dataset-profile-editor-internal-dmp-entities-field.component.ts index 533669c20..2c7163000 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/internal-dmp-entities/dataset-profile-editor-internal-dmp-entities-field.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/internal-dmp-entities/dataset-profile-editor-internal-dmp-entities-field.component.ts @@ -1,13 +1,12 @@ -import { DatasetProfileInternalDmpEntitiesType } from "../../../../../../../core/common/enum/dataset-profile-internal-dmp-entities-type"; -import { EnumUtils } from "../../../../../../../core/services/utilities/enum-utils.service"; -import { Component, Input, OnInit } from "@angular/core"; -import { FormGroup } from "@angular/forms"; -import { BaseComponent } from "../../../../../../../core/common/base/base.component"; -import { takeUntil } from "rxjs/operators"; -import { ResearchersAutoCompleteFieldDataEditorModel } from "../../../../admin/field-data/researchers-auto-complete-field-data-editor-model"; -import { DatasetsAutoCompleteFieldDataEditorModel } from "../../../../admin/field-data/datasets-autocomplete-field-data-editor-mode"; -import { DmpsAutoCompleteFieldDataEditorModel } from "../../../../admin/field-data/dmps-autocomplete-field-data-editor-model"; - +import { Component, Input, OnInit } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { DatasetProfileInternalDmpEntitiesType } from '@app/core/common/enum/dataset-profile-internal-dmp-entities-type'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { DatasetsAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/datasets-autocomplete-field-data-editor-mode'; +import { DmpsAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/dmps-autocomplete-field-data-editor-model'; +import { ResearchersAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/researchers-auto-complete-field-data-editor-model'; +import { BaseComponent } from '@common/base/base.component'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-dataset-profile-internal-dmp-entities-field-component', diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.ts index bdc243b73..c9b082e4f 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.ts @@ -1,22 +1,21 @@  import { Component, Input, OnInit } from '@angular/core'; import { FormArray, FormControl, FormGroup } from '@angular/forms'; +import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style'; +import { ValidationType } from '@app/core/common/enum/validation-type'; +import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { BooleanDecisionFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/boolean-decision-field-data-editor-model'; +import { CheckBoxFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/check-box-field-data-editor-model'; +import { DatePickerDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/date-picker-data-editor-models'; +import { FreeTextFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/free-text-field-data-editor-model'; +import { RadioBoxFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/radio-box-field-data-editor-model'; +import { ResearchersAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/researchers-auto-complete-field-data-editor-model'; +import { TextAreaFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/text-area-field-data-editor-model'; +import { WordListFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/word-list-field-data-editor-model'; +import { RuleEditorModel } from '@app/ui/admin/dataset-profile/admin/rule-editor-model'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../../../core/common/base/base.component'; -import { DatasetProfileFieldViewStyle } from '../../../../../../core/common/enum/dataset-profile-field-view-style'; -import { ValidationType } from '../../../../../../core/common/enum/validation-type'; -import { EnumUtils } from '../../../../../../core/services/utilities/enum-utils.service'; -import { BooleanDecisionFieldDataEditorModel } from '../../../admin/field-data/boolean-decision-field-data-editor-model'; -import { CheckBoxFieldDataEditorModel } from '../../../admin/field-data/check-box-field-data-editor-model'; -import { FreeTextFieldDataEditorModel } from '../../../admin/field-data/free-text-field-data-editor-model'; -import { RadioBoxFieldDataEditorModel } from '../../../admin/field-data/radio-box-field-data-editor-model'; -import { TextAreaFieldDataEditorModel } from '../../../admin/field-data/text-area-field-data-editor-model'; -import { WordListFieldDataEditorModel } from '../../../admin/field-data/word-list-field-data-editor-model'; -import { RuleEditorModel } from '../../../admin/rule-editor-model'; -import { DatePickerDataEditorModel } from '../../../admin/field-data/date-picker-data-editor-models'; -import { ResearchersAutoCompleteFieldDataEditorModel } from '../../../admin/field-data/researchers-auto-complete-field-data-editor-model'; -import { DatasetProfileInternalDmpEntitiesType } from '../../../../../../core/common/enum/dataset-profile-internal-dmp-entities-type'; -import { DatasetProfileService } from "../../../../../../core/services/dataset-profile/dataset-profile.service"; @Component({ selector: 'app-dataset-profile-editor-field-component', diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.ts index 92a3dc424..9f54487c6 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.ts @@ -1,11 +1,11 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormArray, FormGroup } from '@angular/forms'; +import { FieldEditorModel } from '@app/ui/admin/dataset-profile/admin/field-editor-model'; +import { FieldSetEditorModel } from '@app/ui/admin/dataset-profile/admin/field-set-editor-model'; +import { SectionEditorModel } from '@app/ui/admin/dataset-profile/admin/section-editor-model'; +import { BaseComponent } from '@common/base/base.component'; +import { Guid } from '@common/types/guid'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../../../core/common/base/base.component'; -import { FieldEditorModel } from '../../../admin/field-editor-model'; -import { FieldSetEditorModel } from '../../../admin/field-set-editor-model'; -import { SectionEditorModel } from '../../../admin/section-editor-model'; -import { Guid } from '../../../../../../common/types/guid'; @Component({ selector: 'app-dataset-profile-editor-section-component', @@ -32,10 +32,10 @@ export class DatasetProfileEditorSectionComponent extends BaseComponent implemen addField() { const fieldSet: FieldSetEditorModel = new FieldSetEditorModel(); const field: FieldEditorModel = new FieldEditorModel(); - field.id=Guid.create().toString(); + field.id = Guid.create().toString(); fieldSet.fields.push(field); if (this.dataModel.fieldSets) { - fieldSet.id=Guid.create().toString(); + fieldSet.id = Guid.create().toString(); this.dataModel.fieldSets.push(fieldSet); } (this.form.get('fieldSets')).push(fieldSet.buildForm()); @@ -48,7 +48,7 @@ export class DatasetProfileEditorSectionComponent extends BaseComponent implemen } DeleteSectionInSection(index) { - this.dataModel.sections.splice(index,1); + this.dataModel.sections.splice(index, 1); (this.form.get('sections')).removeAt(index); } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts index 4dd912dfa..3d102781d 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts @@ -8,21 +8,20 @@ import { MatHorizontalStepper } from '@angular/material/stepper'; import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { map, takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { DatasetProfile } from '../../../../core/model/admin/dataset-profile/dataset-profile'; -import { DatasetWizardModel } from '../../../../core/model/dataset/dataset-wizard'; -import { DatasetProfileService } from '../../../../core/services/dataset-profile/dataset-profile.service'; -import { LoggingService } from '../../../../core/services/logging/logging-service'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../../core/services/notification/ui-notification-service'; -import { PageEditorModel } from '../admin/page-editor-model'; -import { SectionEditorModel } from '../admin/section-editor-model'; -import { DatasetProfileEditorModel } from './dataset-profile-editor-model'; -import { ConfirmationDialogComponent } from '../../../../library/confirmation-dialog/confirmation-dialog.component'; -import { DatasetProfileEnum } from '../../../../core/common/enum/dataset-profile'; import * as FileSaver from 'file-saver'; -import { BreadcrumbItem } from '../../../misc/breadcrumb/definition/breadcrumb-item'; -import { DatasetStatus } from '../../../../core/common/enum/dataset-status'; -//import * as data from 'src/assets/resources/skipDisable.json'; +import { BaseComponent } from '@common/base/base.component'; +import { DatasetProfileEditorModel } from '@app/ui/admin/dataset-profile/editor/dataset-profile-editor-model'; +import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; +import { LoggingService } from '@app/core/services/logging/logging-service'; +import { UiNotificationService, SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service'; +import { DatasetProfile } from '@app/core/model/admin/dataset-profile/dataset-profile'; +import { DatasetProfileEnum } from '@app/core/common/enum/dataset-profile'; +import { SectionEditorModel } from '@app/ui/admin/dataset-profile/admin/section-editor-model'; +import { PageEditorModel } from '@app/ui/admin/dataset-profile/admin/page-editor-model'; +import { DatasetStatus } from '@app/core/common/enum/dataset-status'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json'); diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.ts index 3b39d931b..f0b1b3e17 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.ts @@ -1,12 +1,12 @@ import { Component, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; +import { DialodConfirmationUploadDatasetProfiles } from '@app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; +import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; -import { ValidationErrorModel } from '../../../../../common/forms/validation/error-model/validation-error-model'; -import { DatasetProfileCriteria } from '../../../../../core/query/dataset-profile/dataset-profile-criteria'; -import { DatasetProfileService } from '../../../../../core/services/dataset-profile/dataset-profile.service'; -import { BaseCriteriaComponent } from '../../../../misc/criteria/base-criteria.component'; -import { DialodConfirmationUploadDatasetProfiles } from './dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; @Component({ selector: 'app-dataset-profile-criteria-component', diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.ts index ffa8c646b..8582c490d 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.ts @@ -3,19 +3,19 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { ActivatedRoute, Params, Router } from '@angular/router'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { DatasetProfileCriteriaComponent } from '@app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import { merge as observableMerge, Observable, of as observableOf } from 'rxjs'; import { map, startWith, switchMap, takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { DataTableRequest } from '../../../../core/model/data-table/data-table-request'; -import { DatasetListingModel } from '../../../../core/model/dataset/dataset-listing'; -import { DmpModel } from '../../../../core/model/dmp/dmp'; -import { DatasetProfileCriteria } from '../../../../core/query/dataset-profile/dataset-profile-criteria'; -import { DatasetProfileService } from '../../../../core/services/dataset-profile/dataset-profile.service'; -import { DmpService } from '../../../../core/services/dmp/dmp.service'; -import { UiNotificationService } from '../../../../core/services/notification/ui-notification-service'; -import { BreadcrumbItem } from '../../../misc/breadcrumb/definition/breadcrumb-item'; -import { DatasetProfileCriteriaComponent } from './criteria/dataset-profile.component'; @Component({ selector: 'app-dataset-profile-listing-component', diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/preview/dataset-profile-preview.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/preview/dataset-profile-preview.component.ts index 97ea7d06d..092d41f6a 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/preview/dataset-profile-preview.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/preview/dataset-profile-preview.component.ts @@ -1,10 +1,10 @@ -import { Component, Inject, OnInit } from '@angular/core'; +import { Inject, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; +import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { DatasetProfileService } from '../../../../core/services/dataset-profile/dataset-profile.service'; -import { DatasetWizardEditorModel } from '../../../dataset/dataset-wizard/dataset-wizard-editor.model'; // @Component({ // selector: 'app-dataset-profile-preview-component', diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/dmp-profile.module.ts b/dmp-frontend/src/app/ui/admin/dmp-profile/dmp-profile.module.ts index 373432037..4e4e79439 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/dmp-profile.module.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-profile/dmp-profile.module.ts @@ -1,14 +1,14 @@ import { NgModule } from "@angular/core"; -import { CommonFormsModule } from "../../../common/forms/common-forms.module"; -import { CommonUiModule } from "../../../common/ui/common-ui.module"; -import { ConfirmationDialogModule } from "../../../library/confirmation-dialog/confirmation-dialog.module"; -import { UrlListingModule } from "../../../library/url-listing/url-listing.module"; -import { DmpProfileRoutingModule } from "./dmp-profile.routing"; -import { DmpProfileEditorComponent } from "./editor/dmp-profile-editor.component"; -import { DmpProfileCriteriaComponent } from "./listing/criteria/dmp-profile-criteria.component"; -import { DmpProfileListingComponent } from "./listing/dmp-profile-listing.component"; -import { DialodConfirmationUploadDmpProfiles } from "./listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component"; -import { DmpProfileExternalAutocompleteFieldEditorComponent } from "./editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component"; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; +import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; +import { DmpProfileRoutingModule } from './dmp-profile.routing'; +import { DmpProfileEditorComponent } from './editor/dmp-profile-editor.component'; +import { DmpProfileExternalAutocompleteFieldEditorComponent } from './editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component'; +import { DialodConfirmationUploadDmpProfiles } from './listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; +import { DmpProfileCriteriaComponent } from './listing/criteria/dmp-profile-criteria.component'; +import { DmpProfileListingComponent } from './listing/dmp-profile-listing.component'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.ts b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.ts index f56b1843f..51fe8a1c7 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.ts @@ -1,25 +1,25 @@ -import {of as observableOf, Observable } from 'rxjs'; - -import {map, takeUntil } from 'rxjs/operators'; -import { AfterViewInit, Component, OnInit } from '@angular/core'; +import { AfterViewInit, Component } from '@angular/core'; import { AbstractControl, FormArray, FormControl, FormGroup } 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'; +import { DmpProfileType } from '@app/core/common/enum/dmp-profile-type'; +import { DmpProfile } from '@app/core/model/dmp-profile/dmp-profile'; +import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { DmpProfileEditorModel, DmpProfileFieldEditorModel } from '@app/ui/admin/dmp-profile/editor/dmp-profile-editor.model'; +import { DmpProfileExternalAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { BaseComponent } from '@common/base/base.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; +import { environment } from 'environments/environment'; import * as FileSaver from 'file-saver'; -import { environment } from '../../../../../environments/environment'; -import { ValidationErrorModel } from '../../../../common/forms/validation/error-model/validation-error-model'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { DmpProfileFieldDataType } from '../../../../core/common/enum/dmp-profile-field-type'; -import { DmpProfileStatus } from '../../../../core/common/enum/dmp-profile-status'; -import { DmpProfileType } from '../../../../core/common/enum/dmp-profile-type'; -import { DmpProfile } from '../../../../core/model/dmp-profile/dmp-profile'; -import { DmpProfileService } from '../../../../core/services/dmp/dmp-profile.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../../core/services/notification/ui-notification-service'; -import { EnumUtils } from '../../../../core/services/utilities/enum-utils.service'; -import { DmpProfileEditorModel, DmpProfileFieldEditorModel } from './dmp-profile-editor.model'; -import { BreadcrumbItem } from '../../../misc/breadcrumb/definition/breadcrumb-item'; -import { DmpProfileExternalAutoCompleteFieldDataEditorModel } from './external-autocomplete/dmp-profile-external-autocomplete-field-editor.model'; +import { Observable, of as observableOf } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; + @Component({ selector: 'app-dmp-profile-editor-component', @@ -99,8 +99,8 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie this.dmpProfileService.createDmp(this.formGroup.value) .pipe(takeUntil(this._destroyed)) .subscribe( - complete => this.onCallbackSuccess(), - error => this.onCallbackError(error) + complete => this.onCallbackSuccess(), + error => this.onCallbackError(error) ); } @@ -202,8 +202,8 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie this.dmpProfileService.createDmp(this.formGroup.value) .pipe(takeUntil(this._destroyed)) .subscribe( - complete => this.onCallbackSuccess(), - error => this.onCallbackError(error) + complete => this.onCallbackSuccess(), + error => this.onCallbackError(error) ); } diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.model.ts b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.model.ts index cd32c2d40..aa8b71b81 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.model.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.model.ts @@ -1,10 +1,10 @@ import { FormBuilder, FormGroup } from '@angular/forms'; -import { ValidationErrorModel } from '../../../../common/forms/validation/error-model/validation-error-model'; -import { DmpProfileFieldDataType } from '../../../../core/common/enum/dmp-profile-field-type'; -import { DmpProfileType } from '../../../../core/common/enum/dmp-profile-type'; -import { DmpProfile, DmpProfileDefinition } from '../../../../core/model/dmp-profile/dmp-profile'; -import { DmpProfileField } from '../../../../core/model/dmp-profile/dmp-profile-field'; -import { DmpProfileExternalAutoCompleteFieldDataEditorModel } from './external-autocomplete/dmp-profile-external-autocomplete-field-editor.model'; +import { DmpProfileFieldDataType } from '@app/core/common/enum/dmp-profile-field-type'; +import { DmpProfileType } from '@app/core/common/enum/dmp-profile-type'; +import { DmpProfile, DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; +import { DmpProfileField } from '@app/core/model/dmp-profile/dmp-profile-field'; +import { DmpProfileExternalAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; export class DmpProfileEditorModel { diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component.ts b/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component.ts index def43eae6..bac44b696 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component.ts @@ -1,14 +1,14 @@ import { Component, Input, OnInit } from '@angular/core'; -import { ValidationErrorModel } from '../../../../../common/forms/validation/error-model/validation-error-model'; -import { GrantListingModel } from '../../../../../core/model/grant/grant-listing'; -import { DmpCriteria } from '../../../../../core/query/dmp/dmp-criteria'; -import { DmpProfileCriteria } from '../../../../../core/query/dmp/dmp-profile-criteria'; -import { BaseCriteriaComponent } from '../../../../misc/criteria/base-criteria.component'; -import { DialodConfirmationUploadDmpProfiles } from './dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; -import { MatDialog } from '@angular/material/dialog'; +import { MatDialog } from '@angular/material'; +import { GrantListingModel } from '@app/core/model/grant/grant-listing'; +import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; +import { DmpProfileCriteria } from '@app/core/query/dmp/dmp-profile-criteria'; +import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DialodConfirmationUploadDmpProfiles } from '@app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; +import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; -import { DmpProfileService } from '../../../../../core/services/dmp/dmp-profile.service'; @Component({ selector: 'app-dmp-profile-criteria-component', diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.ts b/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.ts index 856548bc0..6a954910d 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.ts @@ -1,21 +1,21 @@ -import {merge as observableMerge, of as observableOf, Observable } from 'rxjs'; - -import {map, switchMap, startWith, takeUntil } from 'rxjs/operators'; import { DataSource } from '@angular/cdk/table'; import { Component, OnInit, ViewChild } from '@angular/core'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSort } from '@angular/material/sort'; import { ActivatedRoute, Params, Router } from '@angular/router'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DmpProfileListing } from '@app/core/model/dmp-profile/dmp-profile-listing'; +import { DmpProfileCriteria } from '@app/core/query/dmp/dmp-profile-criteria'; +import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpProfileCriteriaComponent } from '@app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { DmpProfileListing } from '../../../../core/model/dmp-profile/dmp-profile-listing'; -import { DmpProfileCriteria } from '../../../../core/query/dmp/dmp-profile-criteria'; -import { DmpProfileService } from '../../../../core/services/dmp/dmp-profile.service'; -import { DataTableRequest } from '../../../../core/model/data-table/data-table-request'; -import { DmpProfileCriteriaComponent } from './criteria/dmp-profile-criteria.component'; -import { BreadcrumbItem } from '../../../misc/breadcrumb/definition/breadcrumb-item'; +import { merge as observableMerge, Observable, of as observableOf } from 'rxjs'; +import { map, startWith, switchMap, takeUntil } from 'rxjs/operators'; + @Component({ selector: 'app-dmp-profile-listing-component', @@ -131,7 +131,7 @@ export class DatasetDataSource extends DataSource { if (!result) { return []; } if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; } return result.data; - }),); + })); } disconnect() { diff --git a/dmp-frontend/src/app/ui/admin/user/listing/criteria/user-criteria.component.ts b/dmp-frontend/src/app/ui/admin/user/listing/criteria/user-criteria.component.ts index ffa011faf..5431debc9 100644 --- a/dmp-frontend/src/app/ui/admin/user/listing/criteria/user-criteria.component.ts +++ b/dmp-frontend/src/app/ui/admin/user/listing/criteria/user-criteria.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; +import { AppRole } from '@app/core/common/enum/app-role'; +import { UserCriteria } from '@app/core/query/user/user-criteria'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { debounceTime, takeUntil } from 'rxjs/operators'; -import { ValidationErrorModel } from '../../../../../common/forms/validation/error-model/validation-error-model'; -import { AppRole } from '../../../../../core/common/enum/app-role'; -import { UserCriteria } from '../../../../../core/query/user/user-criteria'; -import { EnumUtils } from '../../../../../core/services/utilities/enum-utils.service'; -import { BaseCriteriaComponent } from '../../../../misc/criteria/base-criteria.component'; @Component({ selector: 'app-user-criteria-component', diff --git a/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.ts b/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.ts index ca4393546..1e1c7a10f 100644 --- a/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.ts +++ b/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.ts @@ -1,14 +1,14 @@ import { Component, Input, OnInit } from '@angular/core'; import { AbstractControl, FormArray, FormBuilder, FormControl, FormGroup } from '@angular/forms'; +import { AppRole } from '@app/core/common/enum/app-role'; +import { UserListingModel } from '@app/core/model/user/user-listing'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { UserService } from '@app/core/services/user/user.service'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { BaseComponent } from '@common/base/base.component'; +import { Validation, ValidationContext } from '@common/forms/validation/validation-context'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; -import { Validation, ValidationContext } from '../../../../../common/forms/validation/validation-context'; -import { BaseComponent } from '../../../../../core/common/base/base.component'; -import { AppRole } from '../../../../../core/common/enum/app-role'; -import { UserListingModel } from '../../../../../core/model/user/user-listing'; -import { UserService } from '../../../../../core/services/user/user.service'; -import { EnumUtils } from '../../../../../core/services/utilities/enum-utils.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../../../core/services/notification/ui-notification-service'; @Component({ selector: 'app-user-role-editor-component', @@ -26,7 +26,7 @@ export class UserRoleEditorComponent extends BaseComponent implements OnInit { private userService: UserService, private formBuilder: FormBuilder, private enumUtils: EnumUtils, - private uiNotificationService:UiNotificationService + private uiNotificationService: UiNotificationService ) { super(); } ngOnInit() { @@ -117,12 +117,12 @@ export class UserRoleEditorComponent extends BaseComponent implements OnInit { onCallbackSuccess() { this.nowEditing = false; this.formGroup.disable(); - this.uiNotificationService.snackBarNotification( this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); + this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); } onCallbackError(error: any) { this.validateAllFormFields(this.formGroup); - this.uiNotificationService.snackBarNotification( this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Error); + this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Error); } getPrincipalAppRoleValues(): Number[] { diff --git a/dmp-frontend/src/app/ui/admin/user/user.module.ts b/dmp-frontend/src/app/ui/admin/user/user.module.ts index 18257c942..38dae797a 100644 --- a/dmp-frontend/src/app/ui/admin/user/user.module.ts +++ b/dmp-frontend/src/app/ui/admin/user/user.module.ts @@ -1,7 +1,7 @@ import { NgModule } from '@angular/core'; -import { CommonFormsModule } from '../../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../../common/ui/common-ui.module'; -import { FormattingModule } from '../../../core/formatting.module'; +import { FormattingModule } from '@app/core/formatting.module'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; import { UserCriteriaComponent } from './listing/criteria/user-criteria.component'; import { UserRoleEditorComponent } from './listing/role-editor/user-role-editor.component'; import { UserListingComponent } from './listing/user-listing.component'; diff --git a/dmp-frontend/src/app/ui/auth/admin-login/admin-login.component.ts b/dmp-frontend/src/app/ui/auth/admin-login/admin-login.component.ts index ece1c430d..61c1cadf5 100644 --- a/dmp-frontend/src/app/ui/auth/admin-login/admin-login.component.ts +++ b/dmp-frontend/src/app/ui/auth/admin-login/admin-login.component.ts @@ -1,13 +1,12 @@ import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; +import { Credential } from '@app/core/model/auth/credential'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { CultureService } from '@app/core/services/culture/culture-service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { Credential } from '../../../core/model/auth/credential'; -import { CultureService } from '../../../core/services/culture/culture-service'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../core/services/notification/ui-notification-service'; -import { AuthService } from '../../../core/services/auth/auth.service'; - @Component({ selector: 'app-admin-login', templateUrl: './admin-login.component.html', diff --git a/dmp-frontend/src/app/ui/auth/admin-login/admin-login.module.ts b/dmp-frontend/src/app/ui/auth/admin-login/admin-login.module.ts index c4c98b17d..766ca5e31 100644 --- a/dmp-frontend/src/app/ui/auth/admin-login/admin-login.module.ts +++ b/dmp-frontend/src/app/ui/auth/admin-login/admin-login.module.ts @@ -1,8 +1,8 @@ import { NgModule } from '@angular/core'; -import { CommonFormsModule } from '../../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../../common/ui/common-ui.module'; -import { AdminLoginComponent } from './admin-login.component'; -import { AdminLoginRoutingModule } from './admin-login.routing'; +import { AdminLoginComponent } from '@app/ui/auth/admin-login/admin-login.component'; +import { AdminLoginRoutingModule } from '@app/ui/auth/admin-login/admin-login.routing'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/auth/login/b2access/b2access-login.component.ts b/dmp-frontend/src/app/ui/auth/login/b2access/b2access-login.component.ts index a0c38b6ec..bdba62c6c 100644 --- a/dmp-frontend/src/app/ui/auth/login/b2access/b2access-login.component.ts +++ b/dmp-frontend/src/app/ui/auth/login/b2access/b2access-login.component.ts @@ -1,12 +1,12 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Params } from '@angular/router'; +import { AuthProvider } from '@app/core/common/enum/auth-provider'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { LoginService } from '@app/ui/auth/login/utilities/login.service'; +import { BaseComponent } from '@common/base/base.component'; +import { environment } from 'environments/environment'; import { takeUntil } from 'rxjs/operators'; -import { environment } from '../../../../../environments/environment'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { AuthProvider } from '../../../../core/common/enum/auth-provider'; -import { AuthService } from '../../../../core/services/auth/auth.service'; -import { LoginService } from '../utilities/login.service'; @Component({ selector: 'app-b2access-login', @@ -37,10 +37,10 @@ export class B2AccessLoginComponent extends BaseComponent implements OnInit { public b2AccessGetAuthCode() { window.location.href = environment.loginProviders.b2accessConfiguration.oauthUrl - + '?response_type=code&client_id=' + environment.loginProviders.b2accessConfiguration.clientId - + '&redirect_uri=' + environment.loginProviders.b2accessConfiguration.redirectUri - + '&state=' + environment.loginProviders.b2accessConfiguration.state - + '&scope=USER_PROFILE'; + + '?response_type=code&client_id=' + environment.loginProviders.b2accessConfiguration.clientId + + '&redirect_uri=' + environment.loginProviders.b2accessConfiguration.redirectUri + + '&state=' + environment.loginProviders.b2accessConfiguration.state + + '&scope=USER_PROFILE'; } public b2AccessLogin(code: String) { diff --git a/dmp-frontend/src/app/ui/auth/login/configurable-login/configurable-login.component.ts b/dmp-frontend/src/app/ui/auth/login/configurable-login/configurable-login.component.ts index dfeef2274..95f170f8d 100644 --- a/dmp-frontend/src/app/ui/auth/login/configurable-login/configurable-login.component.ts +++ b/dmp-frontend/src/app/ui/auth/login/configurable-login/configurable-login.component.ts @@ -1,14 +1,14 @@ -import { Component, OnInit, Input } from "@angular/core"; -import { BaseComponent } from "../../../../core/common/base/base.component"; -import { ActivatedRoute, Router, Params } from "@angular/router"; -import { HttpClient } from "@angular/common/http"; -import { LoginService } from "../utilities/login.service"; -import { AuthService } from "../../../../core/services/auth/auth.service"; -import { takeUntil } from "rxjs/operators"; -import { environment } from "../../../../../environments/environment"; -import { AuthProvider } from "../../../../core/common/enum/auth-provider"; -import { ConfigurableProvider } from "../../../../core/model/configurable-provider/configurableProvider"; -import { ConfigurableProvidersService } from "../utilities/configurableProviders.service"; +import { HttpClient } from '@angular/common/http'; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute, Params, Router } from '@angular/router'; +import { AuthProvider } from '@app/core/common/enum/auth-provider'; +import { ConfigurableProvider } from '@app/core/model/configurable-provider/configurableProvider'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { ConfigurableProvidersService } from '@app/ui/auth/login/utilities/configurableProviders.service'; +import { LoginService } from '@app/ui/auth/login/utilities/login.service'; +import { BaseComponent } from '@common/base/base.component'; +import { environment } from 'environments/environment'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-configurable-login', diff --git a/dmp-frontend/src/app/ui/auth/login/email-confirmation/email-confirmation.component.ts b/dmp-frontend/src/app/ui/auth/login/email-confirmation/email-confirmation.component.ts index fdffc2199..fb12bf926 100644 --- a/dmp-frontend/src/app/ui/auth/login/email-confirmation/email-confirmation.component.ts +++ b/dmp-frontend/src/app/ui/auth/login/email-confirmation/email-confirmation.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from "@angular/core"; -import { ActivatedRoute, Params, Router } from "@angular/router"; +import { FormControl } from '@angular/forms'; +import { ActivatedRoute, Router } from "@angular/router"; +import { EmailConfirmationService } from '@app/core/services/email-confirmation/email-confirmation.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { BaseComponent } from '@common/base/base.component'; +import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from "rxjs/operators"; -import { BaseComponent } from "../../../../core/common/base/base.component"; -import { EmailConfirmationService } from "../../../../core/services/email-confirmation/email-confirmation.service"; -import { UiNotificationService, SnackBarNotificationLevel } from "../../../../core/services/notification/ui-notification-service"; -import { TranslateService } from "@ngx-translate/core"; -import { FormControl } from "@angular/forms"; @Component({ selector: 'app-email-confirmation-component', @@ -35,8 +35,8 @@ export class EmailConfirmation extends BaseComponent implements OnInit { this.emailConfirmationService.emailConfirmation(token) .pipe(takeUntil(this._destroyed)) .subscribe( - result => this.onCallbackEmailConfirmationSuccess(), - error => this.onCallbackError(error) + result => this.onCallbackEmailConfirmationSuccess(), + error => this.onCallbackError(error) ) } else { this.showForm = true; @@ -48,8 +48,8 @@ export class EmailConfirmation extends BaseComponent implements OnInit { this.emailConfirmationService.sendConfirmationEmail(this.emailFormControl.value) .pipe(takeUntil(this._destroyed)) .subscribe( - result => this.onCallbackSuccess(), - error => this.onCallbackError(error) + result => this.onCallbackSuccess(), + error => this.onCallbackError(error) ) } diff --git a/dmp-frontend/src/app/ui/auth/login/linkedin-login/linkedin-login.component.ts b/dmp-frontend/src/app/ui/auth/login/linkedin-login/linkedin-login.component.ts index bf2981f99..4d6acf28e 100644 --- a/dmp-frontend/src/app/ui/auth/login/linkedin-login/linkedin-login.component.ts +++ b/dmp-frontend/src/app/ui/auth/login/linkedin-login/linkedin-login.component.ts @@ -1,12 +1,12 @@ +import { HttpClient } from "@angular/common/http"; import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Params, Router } from '@angular/router'; +import { AuthProvider } from '@app/core/common/enum/auth-provider'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { LoginService } from '@app/ui/auth/login/utilities/login.service'; +import { BaseComponent } from '@common/base/base.component'; +import { environment } from 'environments/environment'; import { takeUntil } from 'rxjs/operators'; -import { environment } from '../../../../../environments/environment'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { AuthProvider } from '../../../../core/common/enum/auth-provider'; -import { AuthService } from '../../../../core/services/auth/auth.service'; -import { LoginService } from '../utilities/login.service'; -import { HttpClient } from "@angular/common/http"; @Component({ selector: 'app-linkedin-login', diff --git a/dmp-frontend/src/app/ui/auth/login/login.component.ts b/dmp-frontend/src/app/ui/auth/login/login.component.ts index 8de93aac9..3f2662445 100644 --- a/dmp-frontend/src/app/ui/auth/login/login.component.ts +++ b/dmp-frontend/src/app/ui/auth/login/login.component.ts @@ -1,13 +1,14 @@ import { AfterViewInit, Component, OnInit } from '@angular/core'; import { ActivatedRoute, Params, Router } from '@angular/router'; +import { AuthProvider } from '@app/core/common/enum/auth-provider'; +import { ConfigurableProvider } from '@app/core/model/configurable-provider/configurableProvider'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { ConfigurableProvidersService } from '@app/ui/auth/login/utilities/configurableProviders.service'; +import { LoginService } from '@app/ui/auth/login/utilities/login.service'; +import { BaseComponent } from '@common/base/base.component'; +import { environment } from 'environments/environment'; import { takeUntil } from 'rxjs/operators'; -import { environment } from '../../../../environments/environment'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { AuthProvider } from '../../../core/common/enum/auth-provider'; -import { AuthService } from '../../../core/services/auth/auth.service'; -import { LoginService } from './utilities/login.service'; -import { ConfigurableProvider } from "../../../core/model/configurable-provider/configurableProvider"; -import { ConfigurableProvidersService } from "./utilities/configurableProviders.service"; + /// /// diff --git a/dmp-frontend/src/app/ui/auth/login/login.module.ts b/dmp-frontend/src/app/ui/auth/login/login.module.ts index 898fb98cb..cfa773be0 100644 --- a/dmp-frontend/src/app/ui/auth/login/login.module.ts +++ b/dmp-frontend/src/app/ui/auth/login/login.module.ts @@ -1,17 +1,17 @@ import { NgModule } from '@angular/core'; -import { CommonFormsModule } from '../../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../../common/ui/common-ui.module'; -import { LinkedInLoginComponent } from './linkedin-login/linkedin-login.component'; -import { LoginComponent } from './login.component'; -import { LoginRoutingModule } from './login.routing'; -import { TwitterLoginComponent } from './twitter-login/twitter-login.component'; -import { LoginService } from './utilities/login.service'; -import { B2AccessLoginComponent } from './b2access/b2access-login.component'; -import { OrcidLoginComponent } from './orcid-login/orcid-login.component'; -import { EmailConfirmation } from './email-confirmation/email-confirmation.component'; -import { OpenAireLoginComponent } from "./openaire-login/openaire-login.component"; -import { ConfigurableLoginComponent } from "./configurable-login/configurable-login.component"; -import { ConfigurableProvidersService } from "./utilities/configurableProviders.service"; +import { B2AccessLoginComponent } from '@app/ui/auth/login/b2access/b2access-login.component'; +import { ConfigurableLoginComponent } from '@app/ui/auth/login/configurable-login/configurable-login.component'; +import { EmailConfirmation } from '@app/ui/auth/login/email-confirmation/email-confirmation.component'; +import { LinkedInLoginComponent } from '@app/ui/auth/login/linkedin-login/linkedin-login.component'; +import { LoginComponent } from '@app/ui/auth/login/login.component'; +import { LoginRoutingModule } from '@app/ui/auth/login/login.routing'; +import { OpenAireLoginComponent } from '@app/ui/auth/login/openaire-login/openaire-login.component'; +import { OrcidLoginComponent } from '@app/ui/auth/login/orcid-login/orcid-login.component'; +import { TwitterLoginComponent } from '@app/ui/auth/login/twitter-login/twitter-login.component'; +import { ConfigurableProvidersService } from '@app/ui/auth/login/utilities/configurableProviders.service'; +import { LoginService } from '@app/ui/auth/login/utilities/login.service'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/auth/login/openaire-login/openaire-login.component.ts b/dmp-frontend/src/app/ui/auth/login/openaire-login/openaire-login.component.ts index 14754d688..d621cd22a 100644 --- a/dmp-frontend/src/app/ui/auth/login/openaire-login/openaire-login.component.ts +++ b/dmp-frontend/src/app/ui/auth/login/openaire-login/openaire-login.component.ts @@ -1,12 +1,12 @@ +import { HttpClient } from '@angular/common/http'; import { Component, OnInit } from "@angular/core"; -import { BaseComponent } from "../../../../core/common/base/base.component"; -import { ActivatedRoute, Router, Params } from "@angular/router"; -import { LoginService } from "../utilities/login.service"; -import { AuthService } from "../../../../core/services/auth/auth.service"; -import { HttpClient } from "@angular/common/http"; -import { takeUntil } from "rxjs/operators"; -import { environment } from "../../../../../environments/environment"; -import { AuthProvider } from "../../../../core/common/enum/auth-provider"; +import { ActivatedRoute, Params, Router } from '@angular/router'; +import { AuthProvider } from '@app/core/common/enum/auth-provider'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { LoginService } from '@app/ui/auth/login/utilities/login.service'; +import { BaseComponent } from '@common/base/base.component'; +import { environment } from 'environments/environment'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-openaire-login', diff --git a/dmp-frontend/src/app/ui/auth/login/orcid-login/orcid-login.component.ts b/dmp-frontend/src/app/ui/auth/login/orcid-login/orcid-login.component.ts index 68b0ddd89..ea7b24e93 100644 --- a/dmp-frontend/src/app/ui/auth/login/orcid-login/orcid-login.component.ts +++ b/dmp-frontend/src/app/ui/auth/login/orcid-login/orcid-login.component.ts @@ -1,14 +1,14 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { LoginService } from '../utilities/login.service'; -import { ActivatedRoute, Params } from '@angular/router'; -import { takeUntil } from 'rxjs/operators'; -import { environment } from '../../../../../environments/environment'; -import { AuthService } from '../../../../core/services/auth/auth.service'; -import { AuthProvider } from '../../../../core/common/enum/auth-provider'; -import { HttpHeaders, HttpClient } from '@angular/common/http'; -import { OrcidUser } from '../../../../core/model/orcid/orcidUser'; import { FormControl } from '@angular/forms'; +import { ActivatedRoute, Params } from '@angular/router'; +import { AuthProvider } from '@app/core/common/enum/auth-provider'; +import { OrcidUser } from '@app/core/model/orcid/orcidUser'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { LoginService } from '@app/ui/auth/login/utilities/login.service'; +import { BaseComponent } from '@common/base/base.component'; +import { environment } from 'environments/environment'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-orcid-login', @@ -63,8 +63,8 @@ export class OrcidLoginComponent extends BaseComponent implements OnInit { this.authService.login({ ticket: this.accessToken, provider: AuthProvider.ORCID, data: this.orcidUser }) .pipe(takeUntil(this._destroyed)) .subscribe( - res => this.loginService.onLogInSuccess(res, this.returnUrl), - error => this.loginService.onLogInError(error) + res => this.loginService.onLogInSuccess(res, this.returnUrl), + error => this.loginService.onLogInError(error) ); }); } @@ -74,8 +74,8 @@ export class OrcidLoginComponent extends BaseComponent implements OnInit { this.authService.login({ ticket: this.accessToken, provider: AuthProvider.ORCID, data: this.orcidUser }) .pipe(takeUntil(this._destroyed)) .subscribe( - res => this.loginService.onLogInSuccess(res, this.returnUrl), - error => this.loginService.onLogInError(error) + res => this.loginService.onLogInSuccess(res, this.returnUrl), + error => this.loginService.onLogInError(error) ); } } diff --git a/dmp-frontend/src/app/ui/auth/login/twitter-login/twitter-login.component.ts b/dmp-frontend/src/app/ui/auth/login/twitter-login/twitter-login.component.ts index 98304ba65..66729e3c6 100644 --- a/dmp-frontend/src/app/ui/auth/login/twitter-login/twitter-login.component.ts +++ b/dmp-frontend/src/app/ui/auth/login/twitter-login/twitter-login.component.ts @@ -1,13 +1,13 @@ import { HttpHeaders } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Params } from '@angular/router'; +import { AuthProvider } from '@app/core/common/enum/auth-provider'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { BaseHttpService } from '@app/core/services/http/base-http.service'; +import { LoginService } from '@app/ui/auth/login/utilities/login.service'; +import { BaseComponent } from '@common/base/base.component'; +import { environment } from 'environments/environment'; import { takeUntil } from 'rxjs/operators'; -import { environment } from '../../../../../environments/environment'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { AuthService } from '../../../../core/services/auth/auth.service'; -import { BaseHttpService } from '../../../../core/services/http/base-http.service'; -import { LoginService } from '../utilities/login.service'; -import { AuthProvider } from '../../../../core/common/enum/auth-provider'; @Component({ selector: 'app-twitter-login', diff --git a/dmp-frontend/src/app/ui/auth/login/utilities/configurableProviders.service.ts b/dmp-frontend/src/app/ui/auth/login/utilities/configurableProviders.service.ts index 64ef44970..0c269b45d 100644 --- a/dmp-frontend/src/app/ui/auth/login/utilities/configurableProviders.service.ts +++ b/dmp-frontend/src/app/ui/auth/login/utilities/configurableProviders.service.ts @@ -1,6 +1,6 @@ import { Injectable } from "@angular/core"; -import { BaseService } from "../../../../core/common/base/base.service"; -import { ConfigurableProvider } from "../../../../core/model/configurable-provider/configurableProvider"; +import { BaseService } from '@common/base/base.service'; +import { ConfigurableProvider } from '@app/core/model/configurable-provider/configurableProvider'; @Injectable() export class ConfigurableProvidersService extends BaseService { diff --git a/dmp-frontend/src/app/ui/auth/login/utilities/login.service.ts b/dmp-frontend/src/app/ui/auth/login/utilities/login.service.ts index 59426a466..121f54bb1 100644 --- a/dmp-frontend/src/app/ui/auth/login/utilities/login.service.ts +++ b/dmp-frontend/src/app/ui/auth/login/utilities/login.service.ts @@ -1,10 +1,10 @@ import { Injectable, NgZone } from '@angular/core'; import { Router } from '@angular/router'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { CultureService } from '@app/core/services/culture/culture-service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { BaseService } from '@common/base/base.service'; import { TranslateService } from '@ngx-translate/core'; -import { BaseService } from '../../../../core/common/base/base.service'; -import { CultureService } from '../../../../core/services/culture/culture-service'; -import { UiNotificationService, SnackBarNotificationLevel } from '../../../../core/services/notification/ui-notification-service'; -import { AuthService } from '../../../../core/services/auth/auth.service'; @Injectable() export class LoginService extends BaseService { diff --git a/dmp-frontend/src/app/ui/contact/contact-content/contact-content.component.ts b/dmp-frontend/src/app/ui/contact/contact-content/contact-content.component.ts index b7b4dcc70..b1275e92a 100644 --- a/dmp-frontend/src/app/ui/contact/contact-content/contact-content.component.ts +++ b/dmp-frontend/src/app/ui/contact/contact-content/contact-content.component.ts @@ -1,13 +1,13 @@ -import { FormGroup, AbstractControl, FormControl, FormArray } from '@angular/forms'; -import { Component, OnInit, Input } from '@angular/core'; import { Location } from '@angular/common'; -import { takeUntil } from 'rxjs/operators'; +import { Component, Input, OnInit } from '@angular/core'; +import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; +import { ContactEmailFormModel } from '@app/core/model/contact/contact-email-form-model'; +import { ContactSupportService } from '@app/core/services/contact-support/contact-support.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { BaseComponent } from '@common/base/base.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; -import { ContactEmailFormModel } from '../../../core/model/contact/contact-email-form-model'; -import { ContactSupportService } from '../../../core/services/contact-support/contact-support.service'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { UiNotificationService, SnackBarNotificationLevel } from '../../../core/services/notification/ui-notification-service'; -import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-contact-content', diff --git a/dmp-frontend/src/app/ui/contact/contact.module.ts b/dmp-frontend/src/app/ui/contact/contact.module.ts index ec900601e..ce8dc2912 100644 --- a/dmp-frontend/src/app/ui/contact/contact.module.ts +++ b/dmp-frontend/src/app/ui/contact/contact.module.ts @@ -1,9 +1,9 @@ import { NgModule } from '@angular/core'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { ContactRoutingModule } from './contact.routing'; -import { ContactContentComponent } from './contact-content/contact-content.component'; -import { ContactDialogComponent } from './contact-dialog/contact-dialog.component'; import { ReactiveFormsModule } from '@angular/forms'; +import { ContactContentComponent } from '@app/ui/contact/contact-content/contact-content.component'; +import { ContactDialogComponent } from '@app/ui/contact/contact-dialog/contact-dialog.component'; +import { ContactRoutingModule } from '@app/ui/contact/contact.routing'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts b/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts index b8cb32450..7eafd961e 100644 --- a/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts @@ -1,33 +1,32 @@ -import {of as observableOf, Observable } from 'rxjs'; - -import {mergeMap, takeUntil } from 'rxjs/operators'; import { Component, OnInit } from '@angular/core'; import { FormControl } from '@angular/forms'; -import { Router, ActivatedRoute, Params } from '@angular/router'; -import { BaseComponent } from '../../core/common/base/base.component'; -import { RecentActivityType } from '../../core/common/enum/recent-activity-type'; -import { DashboardStatisticsModel } from '../../core/model/dashboard/dashboard-statistics-model'; -import { SearchBarItem } from '../../core/model/dashboard/search-bar-item'; -import { GrantCriteria } from '../../core/query/grant/grant-criteria'; -import { AuthService } from '../../core/services/auth/auth.service'; -import { DashboardService } from '../../core/services/dashboard/dashboard.service'; -import { GrantService } from '../../core/services/grant/grant.service'; -import { SearchBarService } from '../../core/services/search-bar/search-bar.service'; -import { UserService } from '../../core/services/user/user.service'; -import { SingleAutoCompleteConfiguration } from '../../library/auto-complete/single/single-auto-complete-configuration'; -import { RequestItem } from '../../core/query/request-item'; -import { DmpListingModel } from '../../core/model/dmp/dmp-listing'; -import { DmpService } from '../../core/services/dmp/dmp.service'; -import { DataTableRequest } from '../../core/model/data-table/data-table-request'; -import { DmpCriteria } from '../../core/query/dmp/dmp-criteria'; -import { ExploreDmpCriteriaModel } from '../../core/query/explore-dmp/explore-dmp-criteria'; -import { DatasetListingModel } from '../../core/model/dataset/dataset-listing'; -import { DatasetService } from '../../core/services/dataset/dataset.service'; -import { ExploreDatasetCriteriaModel } from '../../core/query/explore-dataset/explore-dataset-criteria'; +import { ActivatedRoute, Router } from '@angular/router'; +import { RecentActivityType } from '@app/core/common/enum/recent-activity-type'; +import { DashboardStatisticsModel } from '@app/core/model/dashboard/dashboard-statistics-model'; +import { SearchBarItem } from '@app/core/model/dashboard/search-bar-item'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing'; +import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; +import { ExploreDatasetCriteriaModel } from '@app/core/query/explore-dataset/explore-dataset-criteria'; +import { ExploreDmpCriteriaModel } from '@app/core/query/explore-dmp/explore-dmp-criteria'; +import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { DashboardService } from '@app/core/services/dashboard/dashboard.service'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { GrantService } from '@app/core/services/grant/grant.service'; +import { SearchBarService } from '@app/core/services/search-bar/search-bar.service'; +import { UserService } from '@app/core/services/user/user.service'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { BaseComponent } from '@common/base/base.component'; +import { Observable, of as observableOf } from 'rxjs'; +import { mergeMap, takeUntil } from 'rxjs/operators'; import { BreadcrumbItem } from '../misc/breadcrumb/definition/breadcrumb-item'; import { IBreadCrumbComponent } from '../misc/breadcrumb/definition/IBreadCrumbComponent'; + @Component({ selector: 'app-dashboard', templateUrl: './dashboard.component.html', diff --git a/dmp-frontend/src/app/ui/dashboard/dashboard.module.ts b/dmp-frontend/src/app/ui/dashboard/dashboard.module.ts index 95dac0bc1..3408a76e1 100644 --- a/dmp-frontend/src/app/ui/dashboard/dashboard.module.ts +++ b/dmp-frontend/src/app/ui/dashboard/dashboard.module.ts @@ -1,25 +1,26 @@ import { NgModule } from '@angular/core'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { CardComponent } from './card/card.component'; -import { DashboardComponent } from './dashboard.component'; -import { DashboardRoutingModule } from './dashboard.routing'; -import { DraftsComponent } from './drafts/drafts.component'; -import { InfoCounterComponent } from './info-counter/info-counter.component'; -import { QuickWizardCreateAdd } from './quick-wizard-create-add/quick-wizard-create-add.component'; -import { RecentActivityComponent } from './recent-activity/recent-activity.component'; -import { RecentEditedActivityComponent } from './recent-edited-activity/recent-edited-activity.component'; -import { RecentVisitedActivityComponent } from './recent-visited-activity/recent-visited-activity.component'; -import { WizardComponent } from './wizard/wizard.component'; -import { DmpInfoCounterComponent } from './dmp-info-counter/dmp-info-counter.component'; -import { DatasetInfoCounterComponent } from './dataset-info-counter/dataset-info-counter.component'; -import { ExportMethodDialogModule } from '../../library/export-method-dialog/export-method-dialog.module'; - +import { ExportMethodDialogModule } from '@app/library/export-method-dialog/export-method-dialog.module'; +import { CardComponent } from '@app/ui/dashboard/card/card.component'; +import { DashboardComponent } from '@app/ui/dashboard/dashboard.component'; +import { DashboardRoutingModule } from '@app/ui/dashboard/dashboard.routing'; +import { DatasetInfoCounterComponent } from '@app/ui/dashboard/dataset-info-counter/dataset-info-counter.component'; +import { DmpInfoCounterComponent } from '@app/ui/dashboard/dmp-info-counter/dmp-info-counter.component'; +import { DraftsComponent } from '@app/ui/dashboard/drafts/drafts.component'; +import { InfoCounterComponent } from '@app/ui/dashboard/info-counter/info-counter.component'; +import { QuickWizardCreateAdd } from '@app/ui/dashboard/quick-wizard-create-add/quick-wizard-create-add.component'; +import { RecentActivityComponent } from '@app/ui/dashboard/recent-activity/recent-activity.component'; +import { RecentEditedActivityComponent } from '@app/ui/dashboard/recent-edited-activity/recent-edited-activity.component'; +import { RecentVisitedActivityComponent } from '@app/ui/dashboard/recent-visited-activity/recent-visited-activity.component'; +import { WizardComponent } from '@app/ui/dashboard/wizard/wizard.component'; +import { CommonUiModule } from '@common/ui/common-ui.module'; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; @NgModule({ imports: [ CommonUiModule, DashboardRoutingModule, - ExportMethodDialogModule + ExportMethodDialogModule, + ConfirmationDialogModule ], declarations: [ DashboardComponent, diff --git a/dmp-frontend/src/app/ui/dashboard/quick-wizard-create-add/quick-wizard-create-add.component.ts b/dmp-frontend/src/app/ui/dashboard/quick-wizard-create-add/quick-wizard-create-add.component.ts index b0a82ffca..d64a2de98 100644 --- a/dmp-frontend/src/app/ui/dashboard/quick-wizard-create-add/quick-wizard-create-add.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/quick-wizard-create-add/quick-wizard-create-add.component.ts @@ -1,8 +1,8 @@ -import { BaseComponent } from "../../../core/common/base/base.component"; -import { OnInit, Component } from "@angular/core"; -import { Router, ActivatedRoute } from "@angular/router"; -import { TranslateService } from "@ngx-translate/core"; +import { Component, OnInit } from "@angular/core"; import { MatSnackBar } from "@angular/material/snack-bar"; +import { ActivatedRoute, Router } from "@angular/router"; +import { BaseComponent } from '@common/base/base.component'; +import { TranslateService } from "@ngx-translate/core"; @Component({ selector: 'app-quick-wizard-create-add-component', @@ -22,15 +22,15 @@ export class QuickWizardCreateAdd extends BaseComponent implements OnInit { ngOnInit(): void { - + } - navigateToCreate(){ + navigateToCreate() { this.router.navigate(["/quick-wizard"]); } - - navigateToAdd(){ + + navigateToAdd() { this.router.navigate(["/datasetcreatewizard"]); } diff --git a/dmp-frontend/src/app/ui/dashboard/recent-activity/recent-activity.component.ts b/dmp-frontend/src/app/ui/dashboard/recent-activity/recent-activity.component.ts index 31d188f9a..012acfe46 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-activity/recent-activity.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/recent-activity/recent-activity.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; +import { RecentActivityType } from '@app/core/common/enum/recent-activity-type'; +import { UserService } from '@app/core/services/user/user.service'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { RecentActivityType } from '../../../core/common/enum/recent-activity-type'; -import { UserService } from '../../../core/services/user/user.service'; @Component({ selector: 'app-recent-activity', diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts index c1d40d0cd..6e9b89b8b 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts @@ -1,19 +1,18 @@ import { Component, OnInit } from '@angular/core'; -import { DmpListingModel } from '../../../core/model/dmp/dmp-listing'; -import { EnumUtils } from '../../../core/services/utilities/enum-utils.service'; -import { AuthService } from '../../../core/services/auth/auth.service'; -import { DataTableRequest } from '../../../core/model/data-table/data-table-request'; -import { DmpCriteria } from '../../../core/query/dmp/dmp-criteria'; -import { DmpService } from '../../../core/services/dmp/dmp.service'; -import { RecentActivityType } from '../../../core/common/enum/recent-activity-type'; +import { MatDialog } from '@angular/material'; import { Router } from '@angular/router'; -import { Principal } from '../../../core/model/auth/Principal'; +import { RecentActivityType } from '@app/core/common/enum/recent-activity-type'; +import { Principal } from '@app/core/model/auth/Principal'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; +import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; -import { ConfirmationDialogComponent } from '../../../library/confirmation-dialog/confirmation-dialog.component'; -import { MatDialog } from '@angular/material/dialog'; -import { ExportMethodDialogComponent } from '../../../library/export-method-dialog/export-method-dialog.component'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { UiNotificationService, SnackBarNotificationLevel } from '../../../core/services/notification/ui-notification-service'; import * as FileSaver from 'file-saver'; import { takeUntil } from 'rxjs/operators'; @@ -80,8 +79,8 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn this.dmpService.delete(dmp.id) .pipe(takeUntil(this._destroyed)) .subscribe( - complete => { this.onCallbackSuccess() }, - error => this.onDeleteCallbackError(error) + complete => { this.onCallbackSuccess() }, + error => this.onDeleteCallbackError(error) ); } }); diff --git a/dmp-frontend/src/app/ui/dashboard/recent-visited-activity/recent-visited-activity.component.ts b/dmp-frontend/src/app/ui/dashboard/recent-visited-activity/recent-visited-activity.component.ts index ddae74f9e..6cb7c8111 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-visited-activity/recent-visited-activity.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/recent-visited-activity/recent-visited-activity.component.ts @@ -1,15 +1,13 @@ import { Component, OnInit } from "@angular/core"; -import { RecentActivityType } from "../../../core/common/enum/recent-activity-type"; -import { BaseComponent } from "../../../core/common/base/base.component"; -import { Router } from "@angular/router"; -import { AuthService } from "../../../core/services/auth/auth.service"; -import { UserService } from "../../../core/services/user/user.service"; -import { takeUntil } from "rxjs/operators"; -import { DmpService } from "../../../core/services/dmp/dmp.service"; -import { DataTableRequest } from "../../../core/model/data-table/data-table-request"; -import { DmpCriteria } from "../../../core/query/dmp/dmp-criteria"; -import { DmpListingModel } from "../../../core/model/dmp/dmp-listing"; -import { EnumUtils } from "../../../core/services/utilities/enum-utils.service"; +import { Router } from '@angular/router'; +import { RecentActivityType } from '@app/core/common/enum/recent-activity-type'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; +import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { BaseComponent } from '@common/base/base.component'; @Component({ selector: "app-recent-visited-activity", diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.ts b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.ts index cfa7614b2..4e39559ed 100644 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.ts @@ -1,22 +1,21 @@ -import { of as observableOf, Observable } from 'rxjs'; import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormGroup, FormArray } from '@angular/forms'; +import { FormArray, FormBuilder, FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { MatStepper } from '@angular/material/stepper'; import { Router } from '@angular/router'; -import { BaseComponent } from '../../core/common/base/base.component'; -import { QuickWizardService } from '../../core/services/quick-wizard/quick-wizard.service'; -import { DatasetCreateWizardModel } from './dataset-create-wizard.model'; -import { IBreadCrumbComponent } from '../misc/breadcrumb/definition/IBreadCrumbComponent'; -import { takeUntil } from 'rxjs/operators'; -import { BreadcrumbItem } from '../misc/breadcrumb/definition/breadcrumb-item'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../core/services/notification/ui-notification-service'; +import { DatasetStatus } from '@app/core/common/enum/dataset-status'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { QuickWizardService } from '@app/core/services/quick-wizard/quick-wizard.service'; +import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; +import { DatasetCreateWizardModel } from '@app/ui/dataset-create-wizard/dataset-create-wizard.model'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { DatasetEditorWizardComponent } from '@app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { TranslateService } from '@ngx-translate/core'; -import { DatasetEditorWizardComponent } from '../quick-wizard/dataset-editor/dataset-editor-wizard.component'; -import { DatasetStatus } from '../../core/common/enum/dataset-status'; -import { ConfirmationDialogComponent } from '../../library/confirmation-dialog/confirmation-dialog.component'; -import { CheckDeactivateBaseComponent } from '../../library/deactivate/deactivate.component'; +import { Observable, of as observableOf } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'dataset-create-wizard.component', diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.model.ts b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.model.ts index a0ef11de6..159489cbf 100644 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.model.ts +++ b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.model.ts @@ -1,10 +1,10 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms"; -import { BackendErrorValidator } from "../../common/forms/validation/custom-validator"; -import { ValidationErrorModel } from "../../common/forms/validation/error-model/validation-error-model"; -import { ValidationContext } from "../../common/forms/validation/validation-context"; -import { DmpCreateWizardFormModel } from "../../core/model/dmp/dmp-create-wizard/dmp-create-wizard-form.model"; -import { DatasetWizardEditorModel } from "../dataset/dataset-wizard/dataset-wizard-editor.model"; -import { DatasetEditorWizardModel } from "../quick-wizard/dataset-editor/dataset-editor-wizard-model"; +import { DmpCreateWizardFormModel } from '@app/core/model/dmp/dmp-create-wizard/dmp-create-wizard-form.model'; +import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; +import { DatasetEditorWizardModel } from '@app/ui/quick-wizard/dataset-editor/dataset-editor-wizard-model'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; export class DatasetCreateWizardModel { diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.module.ts b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.module.ts index 8c5d790ec..ae3a5c492 100644 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.module.ts +++ b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.module.ts @@ -1,18 +1,17 @@ import { NgModule } from '@angular/core'; -import { CommonFormsModule } from '../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { FormattingModule } from '../../core/formatting.module'; -import { AutoCompleteModule } from '../../library/auto-complete/auto-complete.module'; -import { ConfirmationDialogModule } from '../../library/confirmation-dialog/confirmation-dialog.module'; -import { UrlListingModule } from '../../library/url-listing/url-listing.module'; -import { DatasetDescriptionFormModule } from '../misc/dataset-description-form/dataset-description-form.module'; -import { OuickWizardModule } from '../quick-wizard/quick-wizard.module'; -import { DatasetCreateWizard } from './dataset-create-wizard.component'; -import { DatasetCreateWizardRoutingModule } from './dataset-create-wizard.routing'; -import { DatasetDmpSelector } from './dmp-selector/dataset-dmp-selector.component'; -import { QuickWizardRoutingModule } from '../quick-wizard/quick-wizard.routing'; -import { CanDeactivateGuard } from '../../library/deactivate/can-deactivate.guard'; - +import { FormattingModule } from '@app/core/formatting.module'; +import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; +import { CanDeactivateGuard } from '@app/library/deactivate/can-deactivate.guard'; +import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; +import { DatasetCreateWizard } from '@app/ui/dataset-create-wizard/dataset-create-wizard.component'; +import { DatasetCreateWizardRoutingModule } from '@app/ui/dataset-create-wizard/dataset-create-wizard.routing'; +import { DatasetDmpSelector } from '@app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component'; +import { DatasetDescriptionFormModule } from '@app/ui/misc/dataset-description-form/dataset-description-form.module'; +import { OuickWizardModule } from '@app/ui/quick-wizard/quick-wizard.module'; +import { QuickWizardRoutingModule } from '@app/ui/quick-wizard/quick-wizard.routing'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts b/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts index 5cd431fe7..21105181b 100644 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts +++ b/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts @@ -3,21 +3,21 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormArray, FormControl, FormGroup } from '@angular/forms'; import { MatStepper } from '@angular/material/stepper'; import { ActivatedRoute, Router } from '@angular/router'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { BaseComponent } from '@common/base/base.component'; import { Observable } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { DmpStatus } from '../../../core/common/enum/dmp-status'; -import { DataTableRequest } from '../../../core/model/data-table/data-table-request'; -import { DatasetProfileModel } from '../../../core/model/dataset/dataset-profile'; -import { DmpListingModel } from '../../../core/model/dmp/dmp-listing'; -import { DatasetProfileCriteria } from '../../../core/query/dataset-profile/dataset-profile-criteria'; -import { DmpCriteria } from '../../../core/query/dmp/dmp-criteria'; -import { RequestItem } from '../../../core/query/request-item'; -import { DatasetWizardService } from '../../../core/services/dataset-wizard/dataset-wizard.service'; -import { DmpService } from '../../../core/services/dmp/dmp.service'; -import { SingleAutoCompleteConfiguration } from '../../../library/auto-complete/single/single-auto-complete-configuration'; -import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '../../misc/breadcrumb/definition/IBreadCrumbComponent'; @Component({ selector: 'dataset-dmp-selector-component', diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component.ts index 93b237741..3f729cc18 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component.ts @@ -1,5 +1,5 @@ -import {map} from 'rxjs/operators'; +import { map, filter } from 'rxjs/operators'; import { Component } from "@angular/core"; import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog"; import { SingleAutoCompleteConfiguration } from "../../../../library/auto-complete/single/single-auto-complete-configuration"; @@ -37,8 +37,6 @@ export class DatasetCopyDialogueComponent { initialItems: (extraData) => this.searchDmp(''), displayFn: (item) => item['label'], titleFn: (item) => item['label'], - disableOption: (item) => !this.existsDatasetDescriptionTemplate(item['associatedProfiles']), - subtitleFn: (item) => !this.existsDatasetDescriptionTemplate(item['associatedProfiles']) ? this.getErrorMessage() : null }; } @@ -52,7 +50,7 @@ export class DatasetCopyDialogueComponent { this.dialogRef.close(this.data); } else if (!this.data.datasetProfileExist) { - this.data.formControl.setErrors({'incorrect': true}); + this.data.formControl.setErrors({ 'incorrect': true }); } }); } @@ -63,7 +61,7 @@ export class DatasetCopyDialogueComponent { const dmpDataTableRequest: DataTableRequest = new DataTableRequest(0, null, { fields: fields }); dmpDataTableRequest.criteria = new DmpCriteria(); dmpDataTableRequest.criteria.like = query; - return this.dmpService.getPaged(dmpDataTableRequest, "autocomplete").pipe(map(x => x.data)); + return this.dmpService.getPaged(dmpDataTableRequest, "autocomplete").pipe(map(x => x.data), map(x => x.filter(y => this.existsDatasetDescriptionTemplate(y.associatedProfiles)))); } existsDatasetDescriptionTemplate(associatedProfiles: DmpAssociatedProfileModel[]): boolean { @@ -79,7 +77,7 @@ export class DatasetCopyDialogueComponent { this.data.datasetProfileExist = true; } }) - }),); + })); } getErrorMessage() { diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-editor/dataset-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-editor/dataset-editor.component.ts index fbe61f231..d2cad6024 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-editor/dataset-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-editor/dataset-editor.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; -import { BaseComponent } from '../../../../core/common/base/base.component'; +import { BaseComponent } from '@common/base/base.component'; @Component({ selector: 'app-dataset-editor-component', diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard-editor.model.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard-editor.model.ts index ebce512d8..052d4e68f 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard-editor.model.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard-editor.model.ts @@ -1,17 +1,17 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms"; -import { BackendErrorValidator } from "../../../common/forms/validation/custom-validator"; -import { ValidationErrorModel } from "../../../common/forms/validation/error-model/validation-error-model"; -import { ValidationContext } from "../../../common/forms/validation/validation-context"; -import { ExternalDatasetType } from "../../../core/common/enum/external-dataset-type"; -import { DataRepositoryModel } from "../../../core/model/data-repository/data-repository"; -import { DatasetProfileModel } from "../../../core/model/dataset/dataset-profile"; -import { DatasetWizardModel } from "../../../core/model/dataset/dataset-wizard"; -import { DmpModel } from "../../../core/model/dmp/dmp"; -import { ExternalDatasetModel } from "../../../core/model/external-dataset/external-dataset"; -import { RegistryModel } from "../../../core/model/registry/registry"; -import { ServiceModel } from "../../../core/model/service/service"; -import { TagModel } from "../../../core/model/tag/tag"; -import { DatasetDescriptionFormEditorModel } from "../../misc/dataset-description-form/dataset-description-form.model"; +import { ExternalDatasetType } from '@app/core/common/enum/external-dataset-type'; +import { DataRepositoryModel } from '@app/core/model/data-repository/data-repository'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { ExternalDatasetModel } from '@app/core/model/external-dataset/external-dataset'; +import { RegistryModel } from '@app/core/model/registry/registry'; +import { ServiceModel } from '@app/core/model/service/service'; +import { TagModel } from '@app/core/model/tag/tag'; +import { DatasetDescriptionFormEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; export class DatasetWizardEditorModel { public id: string; diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts index c938fceee..dd9bed9a2 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts @@ -1,37 +1,36 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { MatStepper } from '@angular/material/stepper'; import { ActivatedRoute, Router } from '@angular/router'; +import { DatasetStatus } from '@app/core/common/enum/dataset-status'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { ExternalSourcesConfigurationService } from '@app/core/services/external-sources/external-sources-configuration.service'; +import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { DatasetCopyDialogueComponent } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; +import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { DatasetDescriptionFormEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; +import { LinkToScroll } from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents'; +import { BaseComponent } from '@common/base/base.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; import * as FileSaver from 'file-saver'; import { Observable, of as observableOf } from 'rxjs'; import { catchError, map, takeUntil } from 'rxjs/operators'; -import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { DatasetStatus } from '../../../core/common/enum/dataset-status'; -import { DmpStatus } from '../../../core/common/enum/dmp-status'; -import { DataTableRequest } from '../../../core/model/data-table/data-table-request'; -import { DatasetProfileModel } from '../../../core/model/dataset/dataset-profile'; -import { DmpModel } from '../../../core/model/dmp/dmp'; -import { DmpListingModel } from '../../../core/model/dmp/dmp-listing'; -import { DatasetProfileCriteria } from '../../../core/query/dataset-profile/dataset-profile-criteria'; -import { DmpCriteria } from '../../../core/query/dmp/dmp-criteria'; -import { RequestItem } from '../../../core/query/request-item'; -import { DatasetWizardService } from '../../../core/services/dataset-wizard/dataset-wizard.service'; -import { DmpService } from '../../../core/services/dmp/dmp.service'; -import { ExternalSourcesConfigurationService } from '../../../core/services/external-sources/external-sources-configuration.service'; -import { ExternalSourcesService } from '../../../core/services/external-sources/external-sources.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../core/services/notification/ui-notification-service'; -import { SingleAutoCompleteConfiguration } from '../../../library/auto-complete/single/single-auto-complete-configuration'; -import { ConfirmationDialogComponent } from '../../../library/confirmation-dialog/confirmation-dialog.component'; -import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '../../misc/breadcrumb/definition/IBreadCrumbComponent'; -import { DatasetDescriptionFormEditorModel } from '../../misc/dataset-description-form/dataset-description-form.model'; -import { LinkToScroll } from '../../misc/dataset-description-form/tableOfContentsMaterial/table-of-contents'; -import { DatasetCopyDialogueComponent } from './dataset-copy-dialogue/dataset-copy-dialogue.component'; -import { DatasetWizardEditorModel } from './dataset-wizard-editor.model'; @Component({ selector: 'app-dataset-wizard-component', @@ -397,7 +396,7 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr public isSemiFormValid(formGroup: FormGroup): boolean { var isValid: boolean = true; Object.keys(formGroup.controls).forEach(controlName => { - if (controlName != 'datasetProfileDefinition' && !formGroup.get(controlName).disabled && !(formGroup.get(controlName).valid)) { + if (controlName != 'datasetProfileDefinition' && !formGroup.get(controlName).disabled && !(formGroup.get(controlName).valid)) { isValid = false; } }); diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts index 6b3ba5f13..57a63660e 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts @@ -2,26 +2,26 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormArray, FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { Router } from '@angular/router'; +import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item'; +import { ExternalSourcesConfiguration } from '@app/core/model/external-sources/external-sources-configuration'; +import { DataRepositoryCriteria } from '@app/core/query/data-repository/data-repository-criteria'; +import { ExternalDatasetCriteria } from '@app/core/query/external-dataset/external-dataset-criteria'; +import { RegistryCriteria } from '@app/core/query/registry/registry-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { ServiceCriteria } from '@app/core/query/service/service-criteria'; +import { TagCriteria } from '@app/core/query/tag/tag-criteria'; +import { ExternalSourcesConfigurationService } from '@app/core/services/external-sources/external-sources-configuration.service'; +import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { ExternalDataRepositoryEditorModel, ExternalDatasetEditorModel, ExternalRegistryEditorModel, ExternalServiceEditorModel, ExternalTagEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; +import { DatasetExternalDataRepositoryDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component'; +import { DatasetExternalDatasetDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component'; +import { DatasetExternalRegistryDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component'; +import { DatasetExternalServiceDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component'; +import { BaseComponent } from '@common/base/base.component'; +import { TranslateService } from '@ngx-translate/core'; import { Observable } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { ExternalSourceItemModel } from '../../../../core/model/external-sources/external-source-item'; -import { ExternalSourcesConfiguration } from '../../../../core/model/external-sources/external-sources-configuration'; -import { DataRepositoryCriteria } from '../../../../core/query/data-repository/data-repository-criteria'; -import { ExternalDatasetCriteria } from '../../../../core/query/external-dataset/external-dataset-criteria'; -import { RegistryCriteria } from '../../../../core/query/registry/registry-criteria'; -import { ServiceCriteria } from '../../../../core/query/service/service-criteria'; -import { TagCriteria } from '../../../../core/query/tag/tag-criteria'; -import { ExternalSourcesConfigurationService } from '../../../../core/services/external-sources/external-sources-configuration.service'; -import { ExternalSourcesService } from '../../../../core/services/external-sources/external-sources.service'; -import { SingleAutoCompleteConfiguration } from '../../../../library/auto-complete/single/single-auto-complete-configuration'; -import { RequestItem } from '../../../../core/query/request-item'; -import { ExternalDataRepositoryEditorModel, ExternalDatasetEditorModel, ExternalRegistryEditorModel, ExternalServiceEditorModel, ExternalTagEditorModel } from '../dataset-wizard-editor.model'; -import { DatasetExternalDataRepositoryDialogEditorComponent } from './editors/data-repository/dataset-external-data-repository-dialog-editor.component'; -import { DatasetExternalDatasetDialogEditorComponent } from './editors/external-dataset/dataset-external-dataset-dialog-editor.component'; -import { DatasetExternalRegistryDialogEditorComponent } from './editors/registry/dataset-external-registry-dialog-editor.component'; -import { DatasetExternalServiceDialogEditorComponent } from './editors/service/dataset-external-service-dialog-editor.component'; -import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-dataset-external-references-editor-component', @@ -33,11 +33,45 @@ export class DatasetExternalReferencesEditorComponent extends BaseComponent impl @Input() formGroup: FormGroup = null; @Input() viewOnly = false; - externalDatasetAutoCompleteConfiguration: SingleAutoCompleteConfiguration; - registriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration; - dataRepositoriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration; - servicesAutoCompleteConfiguration: SingleAutoCompleteConfiguration; - tagsAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + externalDatasetAutoCompleteConfiguration: SingleAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalDatasets.bind(this), + initialItems: (type) => this.searchDatasetExternalDatasets('', type),//.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1), + displayFn: (item) => item ? item.name : null, + titleFn: (item) => item ? item.name : null, + subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') + }; + + registriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalRegistries.bind(this), + initialItems: (type) => this.searchDatasetExternalRegistries('', type), + displayFn: (item) => item ? item.name : null, + titleFn: (item) => item ? item.name : null, + subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') + }; + + dataRepositoriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalDataRepositories.bind(this), + initialItems: (type) => this.searchDatasetExternalDataRepositories('', type), + displayFn: (item) => item ? item.name : null, + titleFn: (item) => item ? item.name : null, + subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') + }; + + servicesAutoCompleteConfiguration: SingleAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalServices.bind(this), + initialItems: (type) => this.searchDatasetExternalServices('', type), + displayFn: (item) => item ? item.label : null, + titleFn: (item) => item ? item.label : null, + subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') + }; + + tagsAutoCompleteConfiguration: SingleAutoCompleteConfiguration = { + filterFn: this.searchDatasetTags.bind(this), + initialItems: (type) => this.searchDatasetTags('', type), + displayFn: (item) => item ? item.name : null, + titleFn: (item) => item ? item.name : null, + subtitleFn: (item) => item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') + }; externalSourcesConfiguration: ExternalSourcesConfiguration; @@ -63,51 +97,6 @@ export class DatasetExternalReferencesEditorComponent extends BaseComponent impl this.externalSourcesConfiguration.services.push({ key: '', label: 'All' }); this.externalSourcesConfiguration.tags.push({ key: '', label: 'All' }); }); - - this.dataRepositoriesAutoCompleteConfiguration = { - filterFn: this.searchDatasetExternalDataRepositories.bind(this), - removeAfterSelection: true, - initialItems: (type) => this.searchDatasetExternalDataRepositories('', type), - displayFn: (item) => item ? item.name : null, - titleFn: (item) => item ? item.name : null, - subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') - }; - - this.externalDatasetAutoCompleteConfiguration = { - filterFn: this.searchDatasetExternalDatasets.bind(this), - removeAfterSelection: true, - initialItems: (type) => this.searchDatasetExternalDatasets('', type),//.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1), - displayFn: (item) => item ? item.name : null, - titleFn: (item) => item ? item.name : null, - subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') - }; - - this.registriesAutoCompleteConfiguration = { - filterFn: this.searchDatasetExternalRegistries.bind(this), - removeAfterSelection: true, - initialItems: (type) => this.searchDatasetExternalRegistries('', type), - displayFn: (item) => item ? item.name : null, - titleFn: (item) => item ? item.name : null, - subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') - }; - - this.servicesAutoCompleteConfiguration = { - filterFn: this.searchDatasetExternalServices.bind(this), - removeAfterSelection: true, - initialItems: (type) => this.searchDatasetExternalServices('', type), - displayFn: (item) => item ? item.label : null, - titleFn: (item) => item ? item.label : null, - subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') - }; - - this.tagsAutoCompleteConfiguration = { - filterFn: this.searchDatasetTags.bind(this), - removeAfterSelection: true, - initialItems: (type) => this.searchDatasetTags('', type), - displayFn: (item) => item ? item.name : null, - titleFn: (item) => item ? item.name : null, - subtitleFn: (item) => item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') - }; } public cancel(): void { diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts index 7215a1d49..f162b0c9c 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts @@ -1,10 +1,10 @@ import { Component, Inject, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { ExternalDataRepositoryService } from '@app/core/services/external-sources/data-repository/extternal-data-repository.service'; +import { ExternalDataRepositoryEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../../../core/common/base/base.component'; -import { ExternalDataRepositoryService } from '../../../../../../core/services/external-sources/data-repository/extternal-data-repository.service'; -import { ExternalDataRepositoryEditorModel } from '../../../dataset-wizard-editor.model'; @Component({ templateUrl: 'dataset-external-data-repository-dialog-editor.component.html', diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts index 88914f5f2..27fd2d062 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts @@ -1,10 +1,10 @@ import { Component, Inject, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { ExternalDatasetService } from '@app/core/services/external-sources/dataset/external-dataset.service'; +import { ExternalDatasetEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../../../core/common/base/base.component'; -import { ExternalDatasetService } from '../../../../../../core/services/external-sources/dataset/external-dataset.service'; -import { ExternalDatasetEditorModel } from '../../../dataset-wizard-editor.model'; @Component({ templateUrl: 'dataset-external-dataset-dialog-editor.component.html', diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts index 96e538083..bad2db7e6 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts @@ -1,10 +1,10 @@ import { Component, Inject, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { ExternalRegistryService } from '@app/core/services/external-sources/registry/external-registry.service'; +import { ExternalRegistryEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../../../core/common/base/base.component'; -import { ExternalRegistryService } from '../../../../../../core/services/external-sources/registry/external-registry.service'; -import { ExternalRegistryEditorModel } from '../../../dataset-wizard-editor.model'; @Component({ templateUrl: 'dataset-external-registry-dialog-editor.component.html', diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.ts index f97c8b685..a2b4a9dfe 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.ts @@ -1,10 +1,10 @@ import { Component, Inject, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { ExternalServiceService } from '@app/core/services/external-sources/service/external-service.service'; +import { ExternalServiceEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../../../core/common/base/base.component'; -import { ExternalServiceService } from '../../../../../../core/services/external-sources/service/external-service.service'; -import { ExternalServiceEditorModel } from '../../../dataset-wizard-editor.model'; @Component({ templateUrl: 'dataset-external-service-dialog-editor.component.html', diff --git a/dmp-frontend/src/app/ui/dataset/dataset.module.ts b/dmp-frontend/src/app/ui/dataset/dataset.module.ts index c2a467d1e..0a041cd64 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset.module.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset.module.ts @@ -1,27 +1,27 @@ import { NgModule } from '@angular/core'; +import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; +import { ExportMethodDialogModule } from '@app/library/export-method-dialog/export-method-dialog.module'; +import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; +import { DatasetCopyDialogueComponent } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; +import { DatasetEditorComponent } from '@app/ui/dataset/dataset-wizard/dataset-editor/dataset-editor.component'; +import { DatasetWizardComponent } from '@app/ui/dataset/dataset-wizard/dataset-wizard.component'; +import { DatasetExternalReferencesEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component'; +import { DatasetExternalDataRepositoryDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component'; +import { DatasetExternalDatasetDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component'; +import { DatasetExternalRegistryDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component'; +import { DatasetExternalServiceDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component'; +import { DatasetRoutingModule } from '@app/ui/dataset/dataset.routing'; +import { DatasetCriteriaComponent } from '@app/ui/dataset/listing/criteria/dataset-criteria.component'; +import { DatasetUploadDialogue } from '@app/ui/dataset/listing/criteria/dataset-upload-dialogue/dataset-upload-dialogue.component'; +import { DatasetListingComponent } from '@app/ui/dataset/listing/dataset-listing.component'; +import { DatasetListingItemComponent } from '@app/ui/dataset/listing/listing-item/dataset-listing-item.component'; +import { DatasetDescriptionFormModule } from '@app/ui/misc/dataset-description-form/dataset-description-form.module'; +import { TableOfContentsModule } from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.module'; +import { ExternalSourcesModule } from '@app/ui/misc/external-sources/external-sources.module'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; import { AngularStickyThingsModule } from '@w11k/angular-sticky-things'; -import { CommonFormsModule } from '../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { AutoCompleteModule } from '../../library/auto-complete/auto-complete.module'; -import { ConfirmationDialogModule } from '../../library/confirmation-dialog/confirmation-dialog.module'; -import { ExportMethodDialogModule } from '../../library/export-method-dialog/export-method-dialog.module'; -import { UrlListingModule } from '../../library/url-listing/url-listing.module'; -import { DatasetDescriptionFormModule } from '../misc/dataset-description-form/dataset-description-form.module'; -import { TableOfContentsModule } from '../misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.module'; -import { ExternalSourcesModule } from '../misc/external-sources/external-sources.module'; -import { DatasetCopyDialogueComponent } from './dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; -import { DatasetEditorComponent } from './dataset-wizard/dataset-editor/dataset-editor.component'; -import { DatasetWizardComponent } from './dataset-wizard/dataset-wizard.component'; -import { DatasetExternalReferencesEditorComponent } from './dataset-wizard/external-references/dataset-external-references-editor.component'; -import { DatasetExternalDataRepositoryDialogEditorComponent } from './dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component'; -import { DatasetExternalDatasetDialogEditorComponent } from './dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component'; -import { DatasetExternalRegistryDialogEditorComponent } from './dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component'; -import { DatasetExternalServiceDialogEditorComponent } from './dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component'; -import { DatasetRoutingModule } from './dataset.routing'; -import { DatasetCriteriaComponent } from './listing/criteria/dataset-criteria.component'; -import { DatasetUploadDialogue } from './listing/criteria/dataset-upload-dialogue/dataset-upload-dialogue.component'; -import { DatasetListingComponent } from './listing/dataset-listing.component'; -import { DatasetListingItemComponent } from './listing/listing-item/dataset-listing-item.component'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.ts b/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.ts index cfcee2add..21f2ee355 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.ts +++ b/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.ts @@ -4,35 +4,35 @@ import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { MatSnackBar } from '@angular/material/snack-bar'; import { Router } from '@angular/router'; +import { DatasetStatus } from '@app/core/common/enum/dataset-status'; +import { DataTableData } from '@app/core/model/data-table/data-table-data'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; +import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria'; +import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; +import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; +import { OrganisationCriteria } from '@app/core/query/organisation/organisation-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { TagCriteria } from '@app/core/query/tag/tag-criteria'; +import { UserCriteria } from '@app/core/query/user/user-criteria'; +import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; +import { GrantService } from '@app/core/services/grant/grant.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { OrganisationService } from '@app/core/services/organisation/organisation.service'; +import { UserService } from '@app/core/services/user/user.service'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; +import { DatasetUploadDialogue } from '@app/ui/dataset/listing/criteria/dataset-upload-dialogue/dataset-upload-dialogue.component'; +import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; import { Observable } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import { ValidationErrorModel } from '../../../../common/forms/validation/error-model/validation-error-model'; -import { DatasetStatus } from '../../../../core/common/enum/dataset-status'; -import { DataTableData } from '../../../../core/model/data-table/data-table-data'; -import { DataTableRequest } from '../../../../core/model/data-table/data-table-request'; -import { DmpListingModel } from '../../../../core/model/dmp/dmp-listing'; -import { ExternalSourceItemModel } from '../../../../core/model/external-sources/external-source-item'; -import { DatasetProfileCriteria } from '../../../../core/query/dataset-profile/dataset-profile-criteria'; -import { DatasetCriteria } from '../../../../core/query/dataset/dataset-criteria'; -import { DmpCriteria } from '../../../../core/query/dmp/dmp-criteria'; -import { GrantCriteria } from '../../../../core/query/grant/grant-criteria'; -import { OrganisationCriteria } from '../../../../core/query/organisation/organisation-criteria'; -import { RequestItem } from '../../../../core/query/request-item'; -import { TagCriteria } from '../../../../core/query/tag/tag-criteria'; -import { UserCriteria } from '../../../../core/query/user/user-criteria'; -import { DatasetWizardService } from '../../../../core/services/dataset-wizard/dataset-wizard.service'; -import { DatasetService } from '../../../../core/services/dataset/dataset.service'; -import { DmpService } from '../../../../core/services/dmp/dmp.service'; -import { ExternalSourcesService } from '../../../../core/services/external-sources/external-sources.service'; -import { GrantService } from '../../../../core/services/grant/grant.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../../core/services/notification/ui-notification-service'; -import { OrganisationService } from '../../../../core/services/organisation/organisation.service'; -import { UserService } from '../../../../core/services/user/user.service'; -import { EnumUtils } from '../../../../core/services/utilities/enum-utils.service'; -import { MultipleAutoCompleteConfiguration } from '../../../../library/auto-complete/multiple/multiple-auto-complete-configuration'; -import { BaseCriteriaComponent } from '../../../misc/criteria/base-criteria.component'; -import { DatasetUploadDialogue } from './dataset-upload-dialogue/dataset-upload-dialogue.component'; @Component({ selector: 'app-dataset-criteria-component', @@ -64,14 +64,14 @@ export class DatasetCriteriaComponent extends BaseCriteriaComponent implements O tagsAutoCompleteConfiguration = { filterFn: this.filterTags.bind(this), - initialItems: (excludedItems: any[]) => this.filterTags('').pipe(map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + initialItems: (excludedItems: any[]) => this.filterTags('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['name'], titleFn: (item) => item['name'] }; datasetTemplateAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { filterFn: this.filterDatasetTemplate.bind(this), - initialItems: (excludedItems: any[]) => this.filterDatasetTemplate('').pipe(map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + initialItems: (excludedItems: any[]) => this.filterDatasetTemplate('').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'] @@ -86,21 +86,21 @@ export class DatasetCriteriaComponent extends BaseCriteriaComponent implements O collaboratorsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { filterFn: this.filterCollaborators.bind(this), - initialItems: (excludedItems: any[]) => this.filterCollaborators('').pipe(map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + initialItems: (excludedItems: any[]) => this.filterCollaborators('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['name'], titleFn: (item) => item['name'] }; grantAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { filterFn: this.filterGrant.bind(this), - initialItems: (excludedItems: any[]) => this.filterGrant('').pipe(map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + initialItems: (excludedItems: any[]) => this.filterGrant('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['label'], titleFn: (item) => item['label'] }; organisationAutoCompleteConfiguration: 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))), + 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'] } diff --git a/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-upload-dialogue/dataset-upload-dialogue.component.ts b/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-upload-dialogue/dataset-upload-dialogue.component.ts index d4aeef786..7921bcbd8 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-upload-dialogue/dataset-upload-dialogue.component.ts +++ b/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-upload-dialogue/dataset-upload-dialogue.component.ts @@ -1,22 +1,21 @@ -import {map, takeUntil } from 'rxjs/operators'; import { Component, Inject, OnInit } from '@angular/core'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { DataTableData } from '@app/core/model/data-table/data-table-data'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria'; +import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { Observable } from 'rxjs'; -import { DataTableData } from '../../../../../core/model/data-table/data-table-data'; -import { DmpListingModel } from '../../../../../core/model/dmp/dmp-listing'; -import { DataTableRequest } from '../../../../../core/model/data-table/data-table-request'; -import { DmpCriteria } from '../../../../../core/query/dmp/dmp-criteria'; -import { DmpService } from '../../../../../core/services/dmp/dmp.service'; -import { ValidationErrorModel } from '../../../../../common/forms/validation/error-model/validation-error-model'; -import { BaseCriteriaComponent } from '../../../../misc/criteria/base-criteria.component'; -import { DmpModel } from '../../../../../core/model/dmp/dmp'; -import { DatasetProfileModel } from '../../../../../core/model/dataset/dataset-profile'; -import { DatasetWizardService } from '../../../../../core/services/dataset-wizard/dataset-wizard.service'; -import { RequestItem } from '../../../../../core/query/request-item'; -import { DatasetProfileCriteria } from '../../../../../core/query/dataset-profile/dataset-profile-criteria'; -import { DatasetCriteria } from '../../../../../core/query/dataset/dataset-criteria'; -import { DatasetCriteriaComponent } from '../dataset-criteria.component'; +import { map, takeUntil } from 'rxjs/operators'; @Component({ selector: 'dataset-upload-dialogue', diff --git a/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts b/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts index 01e4afd8a..c843dfe12 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts +++ b/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts @@ -1,21 +1,21 @@ -import { of as observableOf, Observable } from 'rxjs'; import { Component, OnInit, ViewChild } from '@angular/core'; -import { MatPaginator, PageEvent } from '@angular/material/paginator'; +import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { ActivatedRoute, Params, Router } from '@angular/router'; -import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { DataTableRequest } from '../../../core/model/data-table/data-table-request'; -import { DatasetListingModel } from '../../../core/model/dataset/dataset-listing'; -import { DatasetCriteria } from '../../../core/query/dataset/dataset-criteria'; -import { DatasetService } from '../../../core/services/dataset/dataset.service'; -import { DmpService } from '../../../core/services/dmp/dmp.service'; -import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '../../misc/breadcrumb/definition/IBreadCrumbComponent'; -import { DatasetCriteriaComponent } from './criteria/dataset-criteria.component'; +import { DatasetStatus } from '@app/core/common/enum/dataset-status'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing'; +import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { DatasetCriteriaComponent } from '@app/ui/dataset/listing/criteria/dataset-criteria.component'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; -import { DatasetStatus } from '../../../core/common/enum/dataset-status'; +import { Observable, of as observableOf } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-dataset-listing-component', diff --git a/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts b/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts index f9c8bd81d..35279871e 100644 --- a/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts +++ b/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts @@ -1,22 +1,22 @@ -import {of as observableOf, Observable } from 'rxjs'; - -import {map, takeUntil } from 'rxjs/operators'; -import { Component, OnInit } from '@angular/core'; -import { DmpWizardEditorModel } from '../wizard/dmp-wizard-editor.model'; -import { FormGroup } from '@angular/forms'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { ActivatedRoute, Params, Router } from '@angular/router'; -import { DmpModel } from '../../../core/model/dmp/dmp'; -import { TranslateService } from '@ngx-translate/core'; -import { DmpService } from '../../../core/services/dmp/dmp.service'; -import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item'; -import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model'; -import { UiNotificationService, SnackBarNotificationLevel } from '../../../core/services/notification/ui-notification-service'; -import { FunderFormModel } from '../editor/grant-tab/funder-form-model'; -import { ProjectFormModel } from '../editor/grant-tab/project-form-model'; -import { GrantTabModel } from '../editor/grant-tab/grant-tab-model'; import { HttpErrorResponse } from '@angular/common/http'; +import { Component, OnInit } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { ActivatedRoute, Params, Router } from '@angular/router'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; +import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model'; +import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; +import { DmpWizardEditorModel } from '@app/ui/dmp/wizard/dmp-wizard-editor.model'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { BaseComponent } from '@common/base/base.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable, of as observableOf } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; + @Component({ selector: 'app-dmp-clone', diff --git a/dmp-frontend/src/app/ui/dmp/dmp.module.ts b/dmp-frontend/src/app/ui/dmp/dmp.module.ts index 22702fe5b..b701a8e40 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp.module.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp.module.ts @@ -1,34 +1,35 @@ import { NgModule } from '@angular/core'; -import { CommonFormsModule } from '../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { FormattingModule } from '../../core/formatting.module'; -import { AutoCompleteModule } from '../../library/auto-complete/auto-complete.module'; -import { ConfirmationDialogModule } from '../../library/confirmation-dialog/confirmation-dialog.module'; -import { UrlListingModule } from '../../library/url-listing/url-listing.module'; -import { DmpRoutingModule } from './dmp.routing'; -import { AddResearcherComponent } from './editor/add-researcher/add-researcher.component'; -import { AvailableProfilesComponent } from './editor/available-profiles/available-profiles.component'; -import { DmpEditorComponent } from './editor/dmp-editor.component'; -import { DmpFinalizeDialogComponent } from './editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; -import { DynamicDmpFieldResolverComponent } from './editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component'; -import { DynamicFieldGrantComponent } from './editor/dynamic-fields-grant/dynamic-field-grant/dynamic-field-grant.component'; -import { DynamicFieldsGrantComponent } from './editor/dynamic-fields-grant/dynamic-fields-grant.component'; -import { InvitationAcceptedComponent } from './invitation/accepted/dmp-invitation-accepted.component'; -import { DmpInvitationDialogComponent } from './invitation/dmp-invitation.component'; -import { DmpCriteriaComponent } from './listing/criteria/dmp-criteria.component'; -import { DmpUploadDialogue } from './listing/criteria/upload-dialogue/dmp-upload-dialogue.component'; -import { DmpListingComponent } from './listing/dmp-listing.component'; -import { DmpListingItemComponent } from './listing/listing-item/dmp-listing-item.component'; -import { DmpWizardComponent } from './wizard/dmp-wizard.component'; -import { DmpWizardEditorComponent } from './wizard/editor/dmp-wizard-editor.component'; -import { DmpWizardDatasetListingComponent } from './wizard/listing/dmp-wizard-dataset-listing.component'; -import { ExportMethodDialogModule } from '../../library/export-method-dialog/export-method-dialog.module'; -import { GeneralTabComponent } from './editor/general-tab/general-tab.component'; -import { PeopleTabComponent } from './editor/people-tab/people-tab.component'; -import { GrantTabComponent } from './editor/grant-tab/grant-tab.component'; -import { DatasetsTabComponent } from './editor/datasets-tab/datasets-tab.component'; -import { DmpOverviewModule } from './overview/dmp-overview.module'; -import { DmpCloneComponent } from './clone/dmp-clone.component'; +import { FormattingModule } from '@app/core/formatting.module'; +import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; +import { ExportMethodDialogModule } from '@app/library/export-method-dialog/export-method-dialog.module'; +import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; +import { DmpCloneComponent } from '@app/ui/dmp/clone/dmp-clone.component'; +import { DmpRoutingModule } from '@app/ui/dmp/dmp.routing'; +import { AddResearcherComponent } from '@app/ui/dmp/editor/add-researcher/add-researcher.component'; +import { AvailableProfilesComponent } from '@app/ui/dmp/editor/available-profiles/available-profiles.component'; +import { DatasetsTabComponent } from '@app/ui/dmp/editor/datasets-tab/datasets-tab.component'; +import { DmpEditorComponent } from '@app/ui/dmp/editor/dmp-editor.component'; +import { DmpFinalizeDialogComponent } from '@app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; +import { DynamicDmpFieldResolverComponent } from '@app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component'; +import { DynamicFieldGrantComponent } from '@app/ui/dmp/editor/dynamic-fields-grant/dynamic-field-grant/dynamic-field-grant.component'; +import { DynamicFieldsGrantComponent } from '@app/ui/dmp/editor/dynamic-fields-grant/dynamic-fields-grant.component'; +import { GeneralTabComponent } from '@app/ui/dmp/editor/general-tab/general-tab.component'; +import { GrantTabComponent } from '@app/ui/dmp/editor/grant-tab/grant-tab.component'; +import { PeopleTabComponent } from '@app/ui/dmp/editor/people-tab/people-tab.component'; +import { InvitationAcceptedComponent } from '@app/ui/dmp/invitation/accepted/dmp-invitation-accepted.component'; +import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation.component'; +import { DmpCriteriaComponent } from '@app/ui/dmp/listing/criteria/dmp-criteria.component'; +import { DmpUploadDialogue } from '@app/ui/dmp/listing/criteria/upload-dialogue/dmp-upload-dialogue.component'; +import { DmpListingComponent } from '@app/ui/dmp/listing/dmp-listing.component'; +import { DmpListingItemComponent } from '@app/ui/dmp/listing/listing-item/dmp-listing-item.component'; +import { DmpOverviewModule } from '@app/ui/dmp/overview/dmp-overview.module'; +import { DmpWizardComponent } from '@app/ui/dmp/wizard/dmp-wizard.component'; +import { DmpWizardEditorComponent } from '@app/ui/dmp/wizard/editor/dmp-wizard-editor.component'; +import { DmpWizardDatasetListingComponent } from '@app/ui/dmp/wizard/listing/dmp-wizard-dataset-listing.component'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { FormValidationErrorsDialogModule } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ @@ -40,7 +41,8 @@ import { DmpCloneComponent } from './clone/dmp-clone.component'; FormattingModule, AutoCompleteModule, DmpRoutingModule, - DmpOverviewModule + DmpOverviewModule, + FormValidationErrorsDialogModule ], declarations: [ DmpListingComponent, diff --git a/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.component.ts b/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.component.ts index 7d677020e..ca87c4f60 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.component.ts @@ -1,11 +1,10 @@ import { Component, Inject, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { ExternalResearcherService } from '@app/core/services/external-sources/researcher/external-researcher.service'; +import { ResearcherEditorModel } from '@app/ui/dmp/editor/add-researcher/add-researcher.model'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { ExternalResearcherService } from '../../../../core/services/external-sources/researcher/external-researcher.service'; -import { ResearcherEditorModel } from './add-researcher.model'; -import { ResearcherModel } from '../../../../core/model/researcher/researcher'; @Component({ selector: 'app-add-researcher-component', @@ -30,7 +29,7 @@ export class AddResearcherComponent extends BaseComponent implements OnInit { this.externalResearcherService.createResearcher(this.formGroup.value) .pipe(takeUntil(this._destroyed)) .subscribe( - null, null, () => this.dialogRef.close() + null, null, () => this.dialogRef.close() ); } diff --git a/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.model.ts b/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.model.ts index a5fa6df33..80dca6276 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.model.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/add-researcher/add-researcher.model.ts @@ -1,8 +1,8 @@ import { FormBuilder, FormGroup } from '@angular/forms'; -import { ResearcherModel } from '../../../../core/model/researcher/researcher'; -import { ValidationContext } from "../../../../common/forms/validation/validation-context"; -import { BackendErrorValidator } from "../../../../common/forms/validation/custom-validator"; -import { ValidationErrorModel } from "../../../../common/forms/validation/error-model/validation-error-model"; +import { ResearcherModel } from '@app/core/model/researcher/researcher'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; export class ResearcherEditorModel { public id: String; diff --git a/dmp-frontend/src/app/ui/dmp/editor/available-profiles/available-profiles.component.ts b/dmp-frontend/src/app/ui/dmp/editor/available-profiles/available-profiles.component.ts index 8045b1195..12dea9dad 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/available-profiles/available-profiles.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/available-profiles/available-profiles.component.ts @@ -1,12 +1,12 @@ import { Component, Inject, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { DatasetProfileModel } from '../../../../core/model/dataset/dataset-profile'; -import { DatasetService } from '../../../../core/services/dataset/dataset.service'; -import { DataTableRequest } from "../../../../core/model/data-table/data-table-request"; -import { DatasetProfileCriteria } from "../../../../core/query/dataset-profile/dataset-profile-criteria"; @Component({ selector: 'app-available-profiles-component', diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.html b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.html index 1f9240f5f..e96507cb5 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.html @@ -107,15 +107,15 @@
- -
-
diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts index 4f01c3b24..8cac4012b 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts @@ -1,39 +1,41 @@ -import { of as observableOf, Observable } from 'rxjs'; - -import { map, takeUntil } from 'rxjs/operators'; import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Params, Router } from '@angular/router'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { Status } from '@app/core/common/enum/Status'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; +import { DmpProfileListing } from '@app/core/model/dmp-profile/dmp-profile-listing'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { UserModel } from '@app/core/model/user/user'; +import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; +import { BaseCriteria } from '@app/core/query/base-criteria'; +import { DmpProfileCriteria } from '@app/core/query/dmp/dmp-profile-criteria'; +import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { DmpEditorModel } from '@app/ui/dmp/editor/dmp-editor.model'; +import { DmpFinalizeDialogComponent, DmpFinalizeDialogInput } from '@app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; +import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; +import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model'; +import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { BaseComponent } from '@common/base/base.component'; +import { FormService } from '@common/forms/form-service'; +import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; import * as FileSaver from 'file-saver'; -import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { DmpStatus } from '../../../core/common/enum/dmp-status'; -import { Status } from '../../../core/common/enum/Status'; -import { DataTableRequest } from '../../../core/model/data-table/data-table-request'; -import { DmpProfileDefinition } from '../../../core/model/dmp-profile/dmp-profile'; -import { DmpProfileListing } from '../../../core/model/dmp-profile/dmp-profile-listing'; -import { DmpModel } from '../../../core/model/dmp/dmp'; -import { UserModel } from '../../../core/model/user/user'; -import { BaseCriteria } from '../../../core/query/base-criteria'; -import { DmpProfileCriteria } from '../../../core/query/dmp/dmp-profile-criteria'; -import { GrantCriteria } from '../../../core/query/grant/grant-criteria'; -import { RequestItem } from '../../../core/query/request-item'; -import { DmpProfileService } from '../../../core/services/dmp/dmp-profile.service'; -import { DmpService } from '../../../core/services/dmp/dmp.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../core/services/notification/ui-notification-service'; -import { ConfirmationDialogComponent } from '../../../library/confirmation-dialog/confirmation-dialog.component'; -import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '../../misc/breadcrumb/definition/IBreadCrumbComponent'; -import { DmpEditorModel } from './dmp-editor.model'; -import { DmpFinalizeDialogComponent, DmpFinalizeDialogInput } from './dmp-finalize-dialog/dmp-finalize-dialog.component'; -import { AuthService } from '../../../core/services/auth/auth.service'; -import { UserInfoListingModel } from '../../../core/model/user/user-info-listing'; -import { GrantTabModel } from './grant-tab/grant-tab-model'; -import { ProjectFormModel } from './grant-tab/project-form-model'; -import { FunderFormModel } from './grant-tab/funder-form-model'; +import { Observable, of as observableOf } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; +import { Guid } from '@common/types/guid'; @Component({ selector: 'app-dmp-editor-component', @@ -69,6 +71,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC private dialog: MatDialog, private uiNotificationService: UiNotificationService, private authService: AuthService, + private formService: FormService ) { super(); } @@ -223,15 +226,29 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC // } formSubmit(showAddDatasetDialog?: boolean): void { - //this.touchAllFormFields(this.formGroup); - if (!this.isFormValid()) { return; } + this.formService.touchAllFormFields(this.formGroup); + if (!this.isFormValid()) { + this.showValidationErrorsDialog(); + return; + } this.onSubmit(showAddDatasetDialog); } public isFormValid() { - return this.formGroup.get('label').valid && this.formGroup.get('profiles').valid && - (this.formGroup.get('funder').get('label').valid || this.formGroup.get('funder').get('existFunder').valid) && - (this.formGroup.get('grant').get('label').valid || this.formGroup.get('grant').get('existGrant').valid); + return this.formGroup.valid; + // return this.formGroup.get('label').valid && this.formGroup.get('profiles').valid && + // (this.formGroup.get('funder').get('label').valid || this.formGroup.get('funder').get('existFunder').valid) && + // (this.formGroup.get('grant').get('label').valid || this.formGroup.get('grant').get('existGrant').valid); + } + + private showValidationErrorsDialog(projectOnly?: boolean) { + const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { + disableClose: true, + data: { + formGroup: this.formGroup, + projectOnly: projectOnly + }, + }); } onSubmit(showAddDatasetDialog?: boolean): void { @@ -242,7 +259,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC if (showAddDatasetDialog) { this.addDatasetOpenDialog(complete); } - else { this.onCallbackSuccess() } + else { this.onCallbackSuccess(complete) } }, error => { this.formGroup.get('status').setValue(DmpStatus.Draft); @@ -252,9 +269,9 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC } - onCallbackSuccess(): void { + onCallbackSuccess(id?: String): void { this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); - this.router.navigate(['/plans']); + id != null ? this.router.navigate(['/plans', 'edit', id]) : this.router.navigate(['/plans']); } onCallbackError(error: any) { @@ -430,7 +447,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC if (result) { this.router.navigate(['datasets/new/' + id]); } else { - this.router.navigate(['/plans']); + id != null ? this.router.navigate(['/plans', 'edit', id]) : this.router.navigate(['/plans']); } }); } diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.model.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.model.ts index 2eaee767b..3becc2b75 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.model.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.model.ts @@ -1,25 +1,25 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms"; -import { BackendErrorValidator } from "../../../common/forms/validation/custom-validator"; -import { ValidationErrorModel } from "../../../common/forms/validation/error-model/validation-error-model"; -import { ValidationContext } from "../../../common/forms/validation/validation-context"; -import { Status } from "../../../core/common/enum/Status"; -import { DmpProfile, DmpProfileDefinition } from "../../../core/model/dmp-profile/dmp-profile"; -import { DmpModel } from "../../../core/model/dmp/dmp"; -import { DmpDynamicField } from "../../../core/model/dmp/dmp-dynamic-field"; -import { DmpDynamicFieldDependency } from "../../../core/model/dmp/dmp-dynamic-field-dependency"; -import { OrganizationModel } from "../../../core/model/organisation/organization"; -import { ResearcherModel } from "../../../core/model/researcher/researcher"; -import { UserModel } from "../../../core/model/user/user"; -import { ValidJsonValidator } from "../../../library/auto-complete/auto-complete-custom-validator"; -import { UserInfoListingModel } from "../../../core/model/user/user-info-listing"; -import { DatasetModel } from "../../../core/model/dataset/dataset"; -import { GrantTabModel } from "./grant-tab/grant-tab-model"; -import { DmpProfileExternalAutoCompleteFieldDataEditorModel } from "../../admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model"; -import { DmpProfileType } from "../../../core/common/enum/dmp-profile-type"; -import { DmpProfileFieldDataType } from "../../../core/common/enum/dmp-profile-field-type"; -import { DmpProfileField } from "../../../core/model/dmp-profile/dmp-profile-field"; -import { ProjectFormModel } from "./grant-tab/project-form-model"; -import { FunderFormModel } from "./grant-tab/funder-form-model"; +import { DmpProfileFieldDataType } from '@app/core/common/enum/dmp-profile-field-type'; +import { DmpProfileType } from '@app/core/common/enum/dmp-profile-type'; +import { Status } from '@app/core/common/enum/Status'; +import { DatasetModel } from '@app/core/model/dataset/dataset'; +import { DmpProfile, DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; +import { DmpProfileField } from '@app/core/model/dmp-profile/dmp-profile-field'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { DmpDynamicField } from '@app/core/model/dmp/dmp-dynamic-field'; +import { DmpDynamicFieldDependency } from '@app/core/model/dmp/dmp-dynamic-field-dependency'; +import { OrganizationModel } from '@app/core/model/organisation/organization'; +import { ResearcherModel } from '@app/core/model/researcher/researcher'; +import { UserModel } from '@app/core/model/user/user'; +import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; +import { ValidJsonValidator } from '@app/library/auto-complete/auto-complete-custom-validator'; +import { DmpProfileExternalAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model'; +import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; +import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model'; +import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; export class DmpEditorModel { public id: string; diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component.ts index 9708fff9a..c8aca013d 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component.ts @@ -1,9 +1,9 @@ import { Component, Inject, OnInit } from '@angular/core'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { Router } from '@angular/router'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { DatasetStatus } from '../../../../core/common/enum/dataset-status'; -import { DatasetService } from '../../../../core/services/dataset/dataset.service'; +import { DatasetStatus } from '@app/core/common/enum/dataset-status'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { BaseComponent } from '@common/base/base.component'; @Component({ selector: 'app-dmp-finalize-dialog-component', diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts index d678e2dab..99f8a01b9 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts @@ -2,24 +2,24 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; +import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { DmpProfileCriteria } from '@app/core/query/dmp/dmp-profile-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; +import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { AddResearcherComponent } from '@app/ui/dmp/editor/add-researcher/add-researcher.component'; +import { AvailableProfilesComponent } from '@app/ui/dmp/editor/available-profiles/available-profiles.component'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import { Observable } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { DataTableRequest } from '../../../../core/model/data-table/data-table-request'; -import { DatasetProfileModel } from '../../../../core/model/dataset/dataset-profile'; -import { DmpProfileDefinition } from '../../../../core/model/dmp-profile/dmp-profile'; -import { ExternalSourceItemModel } from '../../../../core/model/external-sources/external-source-item'; -import { DatasetProfileCriteria } from '../../../../core/query/dataset-profile/dataset-profile-criteria'; -import { DmpProfileCriteria } from '../../../../core/query/dmp/dmp-profile-criteria'; -import { RequestItem } from '../../../../core/query/request-item'; -import { DmpProfileService } from '../../../../core/services/dmp/dmp-profile.service'; -import { DmpService } from '../../../../core/services/dmp/dmp.service'; -import { ExternalSourcesService } from '../../../../core/services/external-sources/external-sources.service'; -import { MultipleAutoCompleteConfiguration } from '../../../../library/auto-complete/multiple/multiple-auto-complete-configuration'; -import { SingleAutoCompleteConfiguration } from '../../../../library/auto-complete/single/single-auto-complete-configuration'; -import { AddResearcherComponent } from '../add-researcher/add-researcher.component'; -import { AvailableProfilesComponent } from '../available-profiles/available-profiles.component'; @Component({ selector: 'app-general-tab', diff --git a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/funder-form-model.ts b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/funder-form-model.ts index 50a229331..76adf4e24 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/funder-form-model.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/funder-form-model.ts @@ -1,9 +1,10 @@ -import { Status } from "../../../../core/common/enum/Status"; -import { FunderModel } from "../../../../core/model/funder/funder"; -import { ValidationErrorModel } from "../../../../common/forms/validation/error-model/validation-error-model"; -import { ValidationContext } from "../../../../common/forms/validation/validation-context"; -import { FormGroup, FormBuilder, Validators } from "@angular/forms"; -import { BackendErrorValidator } from "../../../../common/forms/validation/custom-validator"; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Status } from '@app/core/common/enum/Status'; +import { FunderModel } from '@app/core/model/funder/funder'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; + export class FunderFormModel { public id: string; diff --git a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab-model.ts b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab-model.ts index f89ca6cce..afba9fce2 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab-model.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab-model.ts @@ -1,10 +1,11 @@ -import { Status } from "../../../../core/common/enum/Status"; -import { GrantListingModel } from "../../../../core/model/grant/grant-listing"; -import { ValidationErrorModel } from "../../../../common/forms/validation/error-model/validation-error-model"; -import { ValidationContext } from "../../../../common/forms/validation/validation-context"; -import { FormBuilder, FormGroup, Validators } from "@angular/forms"; -import { BackendErrorValidator } from "../../../../common/forms/validation/custom-validator"; -import { ValidJsonValidator } from "../../../../library/auto-complete/auto-complete-custom-validator"; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Status } from '@app/core/common/enum/Status'; +import { GrantListingModel } from '@app/core/model/grant/grant-listing'; +import { ValidJsonValidator } from '@app/library/auto-complete/auto-complete-custom-validator'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; + export class GrantTabModel { public id: string; diff --git a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts index f76bf72e1..b39fe23fe 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts @@ -1,17 +1,17 @@ -import { Component, OnInit, Input } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { SingleAutoCompleteConfiguration } from '../../../../library/auto-complete/single/single-auto-complete-configuration'; -import { RequestItem } from '../../../../core/query/request-item'; -import { GrantCriteria } from '../../../../core/query/grant/grant-criteria'; -import { GrantService } from '../../../../core/services/grant/grant.service'; -import { GrantTabModel } from './grant-tab-model'; -import { ProjectService } from '../../../../core/services/project/project.service'; -import { FunderService } from '../../../../core/services/funder/funder.service'; -import { FunderCriteria } from '../../../../core/query/funder/funder-criteria'; -import { ProjectCriteria } from '../../../../core/query/project/project-criteria'; +import { FunderCriteria } from '@app/core/query/funder/funder-criteria'; +import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; +import { ProjectCriteria } from '@app/core/query/project/project-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { FunderService } from '@app/core/services/funder/funder.service'; +import { GrantService } from '@app/core/services/grant/grant.service'; +import { ProjectService } from '@app/core/services/project/project.service'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; -import { takeUntil } from "rxjs/operators"; -import { BaseComponent } from "../../../../core/common/base/base.component"; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-grant-tab', diff --git a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/project-form-model.ts b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/project-form-model.ts index 15e46491a..797dfee69 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/project-form-model.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/project-form-model.ts @@ -1,10 +1,10 @@ -import { Status } from "../../../../core/common/enum/Status"; -import { ProjectModel } from "../../../../core/model/project/project"; -import { ValidationErrorModel } from "../../../../common/forms/validation/error-model/validation-error-model"; -import { ValidationContext } from "../../../../common/forms/validation/validation-context"; -import { FormGroup, FormBuilder, Validators } from "@angular/forms"; -import { BackendErrorValidator } from "../../../../common/forms/validation/custom-validator"; -import { ValidJsonValidator } from "../../../../library/auto-complete/auto-complete-custom-validator"; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Status } from '@app/core/common/enum/Status'; +import { ProjectModel } from '@app/core/model/project/project'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; + export class ProjectFormModel { public id: string; diff --git a/dmp-frontend/src/app/ui/dmp/editor/people-tab/people-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/people-tab/people-tab.component.ts index 33678428f..1c303c446 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/people-tab/people-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/people-tab/people-tab.component.ts @@ -1,12 +1,12 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { TranslateService } from '@ngx-translate/core'; import { Principal } from '../../../../core/model/auth/Principal'; import { UserInfoListingModel } from '../../../../core/model/user/user-info-listing'; import { AuthService } from '../../../../core/services/auth/auth.service'; import { DmpService } from '../../../../core/services/dmp/dmp.service'; -import { ConfirmationDialogComponent } from '../../../../library/confirmation-dialog/confirmation-dialog.component'; import { DmpInvitationDialogComponent } from '../../invitation/dmp-invitation.component'; import { DmpEditorModel } from '../dmp-editor.model'; diff --git a/dmp-frontend/src/app/ui/dmp/invitation/accepted/dmp-invitation-accepted.component.ts b/dmp-frontend/src/app/ui/dmp/invitation/accepted/dmp-invitation-accepted.component.ts index 8441d4d6d..4f9f8726b 100644 --- a/dmp-frontend/src/app/ui/dmp/invitation/accepted/dmp-invitation-accepted.component.ts +++ b/dmp-frontend/src/app/ui/dmp/invitation/accepted/dmp-invitation-accepted.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; +import { DmpInvitationService } from '@app/core/services/dmp/dmp-invitation.service'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { DmpInvitationService } from '../../../../core/services/dmp/dmp-invitation.service'; @Component({ selector: 'app-dmp-invitation-accepted-component', diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation.component.ts b/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation.component.ts index ed144faf8..bbda70d88 100644 --- a/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation.component.ts +++ b/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation.component.ts @@ -1,22 +1,19 @@ -import {map, takeUntil } from 'rxjs/operators'; import { COMMA, ENTER } from '@angular/cdk/keycodes'; import { Component, Inject, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatChipInputEvent } from '@angular/material/chips'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { ActivatedRoute, Router } from '@angular/router'; +import { DmpInvitation } from '@app/core/model/dmp/invitation/dmp-invitation'; +import { DmpInvitationUser } from '@app/core/model/dmp/invitation/dmp-invitation-user'; +import { DmpInvitationUserCriteria } from '@app/core/query/dmp/dmp-invitation-user-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { DmpInvitationService } from '@app/core/services/dmp/dmp-invitation.service'; +import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; +import { BaseComponent } from '@common/base/base.component'; import { Observable } from 'rxjs'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { DmpInvitation } from '../../../core/model/dmp/invitation/dmp-invitation'; -import { DmpInvitationUser } from '../../../core/model/dmp/invitation/dmp-invitation-user'; -import { DmpInvitationUserCriteria } from '../../../core/query/dmp/dmp-invitation-user-criteria'; -import { RequestItem } from '../../../core/query/request-item'; -import { DmpInvitationService } from '../../../core/services/dmp/dmp-invitation.service'; -import { MultipleAutoCompleteConfiguration } from '../../../library/auto-complete/multiple/multiple-auto-complete-configuration'; - - - +import { map, takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-invitation-component', @@ -38,7 +35,7 @@ export class DmpInvitationDialogComponent extends BaseComponent implements OnIni usersAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { filterFn: this.filterUsers.bind(this), - initialItems: (excludedItems: any[]) => this.filterUsers('').pipe(map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + initialItems: (excludedItems: any[]) => this.filterUsers('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item.name, titleFn: (item) => item.name }; diff --git a/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.ts b/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.ts index 88b4a0940..d6b20728d 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.ts @@ -1,25 +1,25 @@ -import {map, takeUntil } from 'rxjs/operators'; import { Component, Input, OnInit } from '@angular/core'; import { FormBuilder, FormControl } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { GrantListingModel } from '@app/core/model/grant/grant-listing'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; +import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; +import { OrganisationCriteria } from '@app/core/query/organisation/organisation-criteria'; +import { UserCriteria } from '@app/core/query/user/user-criteria'; +import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { GrantService } from '@app/core/services/grant/grant.service'; +import { OrganisationService } from '@app/core/services/organisation/organisation.service'; +import { UserService } from '@app/core/services/user/user.service'; +import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; +import { DmpUploadDialogue } from '@app/ui/dmp/listing/criteria/upload-dialogue/dmp-upload-dialogue.component'; +import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; -import { ValidationErrorModel } from '../../../../common/forms/validation/error-model/validation-error-model'; -import { DataTableRequest } from '../../../../core/model/data-table/data-table-request'; -import { GrantListingModel } from '../../../../core/model/grant/grant-listing'; -import { DmpCriteria } from '../../../../core/query/dmp/dmp-criteria'; -import { OrganisationCriteria } from '../../../../core/query/organisation/organisation-criteria'; -import { GrantCriteria } from '../../../../core/query/grant/grant-criteria'; -import { UserCriteria } from '../../../../core/query/user/user-criteria'; -import { DmpService } from '../../../../core/services/dmp/dmp.service'; -import { OrganisationService } from '../../../../core/services/organisation/organisation.service'; -import { GrantService } from '../../../../core/services/grant/grant.service'; -import { UserService } from '../../../../core/services/user/user.service'; -import { MultipleAutoCompleteConfiguration } from '../../../../library/auto-complete/multiple/multiple-auto-complete-configuration'; -import { BaseCriteriaComponent } from '../../../misc/criteria/base-criteria.component'; -import { DmpUploadDialogue } from './upload-dialogue/dmp-upload-dialogue.component'; -import { DatasetProfileCriteria } from '../../../../core/query/dataset-profile/dataset-profile-criteria'; -import { DatasetProfileService } from '../../../../core/services/dataset-profile/dataset-profile.service'; +import { map, takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-dmp-criteria-component', @@ -47,14 +47,14 @@ export class DmpCriteriaComponent extends BaseCriteriaComponent implements OnIni collaboratorsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { filterFn: this.filterCollaborators.bind(this), - initialItems: (excludedItems: any[]) => this.filterCollaborators('').pipe(map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + initialItems: (excludedItems: any[]) => this.filterCollaborators('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['name'], titleFn: (item) => item['name'] }; datasetTemplateAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { filterFn: this.filterDatasetTemplate.bind(this), - initialItems: (excludedItems: any[]) => this.filterDatasetTemplate('').pipe(map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + initialItems: (excludedItems: any[]) => this.filterDatasetTemplate('').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'] @@ -62,14 +62,14 @@ export class DmpCriteriaComponent extends BaseCriteriaComponent implements OnIni grantAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { filterFn: this.filterGrant.bind(this), - initialItems: (excludedItems: any[]) => this.filterGrant('').pipe(map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + initialItems: (excludedItems: any[]) => this.filterGrant('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['label'], titleFn: (item) => item['label'] }; organisationAutoCompleteConfiguration: 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))), + 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'] } diff --git a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts index 6debbbd2c..b4bcedc2b 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts @@ -1,23 +1,23 @@ -import {of as observableOf, Observable } from 'rxjs'; import { Component, OnInit, ViewChild } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { ActivatedRoute, Router } from '@angular/router'; -import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { DataTableRequest } from '../../../core/model/data-table/data-table-request'; -import { DmpListingModel } from '../../../core/model/dmp/dmp-listing'; -import { GrantListingModel } from '../../../core/model/grant/grant-listing'; -import { DmpCriteria } from '../../../core/query/dmp/dmp-criteria'; -import { DmpService } from '../../../core/services/dmp/dmp.service'; -import { EnumUtils } from '../../../core/services/utilities/enum-utils.service'; -import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '../../misc/breadcrumb/definition/IBreadCrumbComponent'; -import { DmpInvitationDialogComponent } from '../invitation/dmp-invitation.component'; -import { DmpCriteriaComponent } from './criteria/dmp-criteria.component'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; +import { GrantListingModel } from '@app/core/model/grant/grant-listing'; +import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation.component'; +import { DmpCriteriaComponent } from '@app/ui/dmp/listing/criteria/dmp-criteria.component'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; +import { Observable, of as observableOf } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-dmp-listing-component', diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts index 39b5bc55f..8c6a92406 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts @@ -1,25 +1,25 @@ -import {of as observableOf, Observable } from 'rxjs'; import { Component, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Params, Router } from '@angular/router'; +import { DatasetStatus } from '@app/core/common/enum/dataset-status'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { Principal } from '@app/core/model/auth/Principal'; +import { DatasetOverviewModel } from '@app/core/model/dataset/dataset-overview'; +import { DatasetsToBeFinalized } from '@app/core/model/dataset/datasets-toBeFinalized'; +import { DmpOverviewModel } from '@app/core/model/dmp/dmp-overview'; +import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { DmpFinalizeDialogComponent, DmpFinalizeDialogInput, DmpFinalizeDialogOutput } from '@app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import * as FileSaver from 'file-saver'; +import { Observable, of as observableOf } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { DatasetStatus } from '../../../core/common/enum/dataset-status'; -import { DmpStatus } from '../../../core/common/enum/dmp-status'; -import { Principal } from '../../../core/model/auth/Principal'; -import { DatasetOverviewModel } from '../../../core/model/dataset/dataset-overview'; -import { DmpOverviewModel } from '../../../core/model/dmp/dmp-overview'; -import { UserInfoListingModel } from '../../../core/model/user/user-info-listing'; -import { AuthService } from '../../../core/services/auth/auth.service'; -import { DmpService } from '../../../core/services/dmp/dmp.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../core/services/notification/ui-notification-service'; -import { ConfirmationDialogComponent } from '../../../library/confirmation-dialog/confirmation-dialog.component'; -import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item'; -import { DmpFinalizeDialogComponent, DmpFinalizeDialogInput, DmpFinalizeDialogOutput } from '../editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; -import { DatasetsToBeFinalized } from '../../../core/model/dataset/datasets-toBeFinalized'; @Component({ selector: 'app-dmp-overview', diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.module.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.module.ts index 5969e5e58..269c70146 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.module.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.module.ts @@ -1,12 +1,12 @@ import { NgModule } from '@angular/core'; -import { CommonFormsModule } from '../../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../../common/ui/common-ui.module'; -import { FormattingModule } from '../../../core/formatting.module'; -import { AutoCompleteModule } from '../../../library/auto-complete/auto-complete.module'; -import { ConfirmationDialogModule } from '../../../library/confirmation-dialog/confirmation-dialog.module'; -import { UrlListingModule } from '../../../library/url-listing/url-listing.module'; -import { DmpOverviewComponent } from './dmp-overview.component'; -import { ExportMethodDialogModule } from '../../../library/export-method-dialog/export-method-dialog.module'; +import { FormattingModule } from '@app/core/formatting.module'; +import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; +import { ExportMethodDialogModule } from '@app/library/export-method-dialog/export-method-dialog.module'; +import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; +import { DmpOverviewComponent } from '@app/ui/dmp/overview/dmp-overview.component'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard-editor.model.ts b/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard-editor.model.ts index 1f42b1ab2..7b24cb3d6 100644 --- a/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard-editor.model.ts +++ b/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard-editor.model.ts @@ -1,20 +1,19 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms"; -import { BackendErrorValidator } from "../../../common/forms/validation/custom-validator"; -import { ValidationErrorModel } from "../../../common/forms/validation/error-model/validation-error-model"; -import { ValidationContext } from "../../../common/forms/validation/validation-context"; -import { Status } from "../../../core/common/enum/Status"; -import { DmpProfile, DmpProfileDefinition } from "../../../core/model/dmp-profile/dmp-profile"; -import { DmpModel } from "../../../core/model/dmp/dmp"; -import { DmpDynamicField } from "../../../core/model/dmp/dmp-dynamic-field"; -import { DmpDynamicFieldDependency } from "../../../core/model/dmp/dmp-dynamic-field-dependency"; -import { OrganizationModel } from "../../../core/model/organisation/organization"; -import { GrantListingModel } from "../../../core/model/grant/grant-listing"; -import { ResearcherModel } from "../../../core/model/researcher/researcher"; -import { UserModel } from "../../../core/model/user/user"; -import { ValidJsonValidator } from "../../../library/auto-complete/auto-complete-custom-validator"; -import { FunderFormModel } from "../editor/grant-tab/funder-form-model"; -import { ProjectFormModel } from "../editor/grant-tab/project-form-model"; -import { GrantTabModel } from "../editor/grant-tab/grant-tab-model"; +import { Status } from '@app/core/common/enum/Status'; +import { DmpProfile, DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { DmpDynamicField } from '@app/core/model/dmp/dmp-dynamic-field'; +import { DmpDynamicFieldDependency } from '@app/core/model/dmp/dmp-dynamic-field-dependency'; +import { OrganizationModel } from '@app/core/model/organisation/organization'; +import { ResearcherModel } from '@app/core/model/researcher/researcher'; +import { UserModel } from '@app/core/model/user/user'; +import { ValidJsonValidator } from '@app/library/auto-complete/auto-complete-custom-validator'; +import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; +import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model'; +import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; export class DmpWizardEditorModel { public id: string; diff --git a/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard.component.ts b/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard.component.ts index 10d9901b8..83e8444a8 100644 --- a/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard.component.ts @@ -1,24 +1,23 @@ -import {of as observableOf, Observable } from 'rxjs'; - -import {map, takeUntil } from 'rxjs/operators'; +import { HttpErrorResponse } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatSnackBar } from '@angular/material/snack-bar'; import { ActivatedRoute, Params, Router } from '@angular/router'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; +import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model'; +import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; +import { DmpWizardEditorModel } from '@app/ui/dmp/wizard/dmp-wizard-editor.model'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { BaseComponent } from '@common/base/base.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; -import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { DmpModel } from '../../../core/model/dmp/dmp'; -import { DmpService } from '../../../core/services/dmp/dmp.service'; -import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '../../misc/breadcrumb/definition/IBreadCrumbComponent'; -import { DmpWizardEditorModel } from './dmp-wizard-editor.model'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../core/services/notification/ui-notification-service'; -import { HttpErrorResponse } from '@angular/common/http'; -import { GrantTabModel } from '../editor/grant-tab/grant-tab-model'; -import { ProjectFormModel } from '../editor/grant-tab/project-form-model'; -import { FunderFormModel } from '../editor/grant-tab/funder-form-model'; +import { Observable, of as observableOf } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-dmp-wizard-component', diff --git a/dmp-frontend/src/app/ui/dmp/wizard/editor/dmp-wizard-editor.component.ts b/dmp-frontend/src/app/ui/dmp/wizard/editor/dmp-wizard-editor.component.ts index f62972f4e..90ba33cee 100644 --- a/dmp-frontend/src/app/ui/dmp/wizard/editor/dmp-wizard-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/wizard/editor/dmp-wizard-editor.component.ts @@ -1,25 +1,25 @@ -import {map, takeUntil } from 'rxjs/operators'; import { Component, Input, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatSnackBar } from '@angular/material/snack-bar'; import { ActivatedRoute, Router } from '@angular/router'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item'; +import { UserModel } from '@app/core/model/user/user'; +import { BaseCriteria } from '@app/core/query/base-criteria'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; +import { GrantService } from '@app/core/services/grant/grant.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import { Observable } from 'rxjs'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { DatasetProfileModel } from '../../../../core/model/dataset/dataset-profile'; -import { ExternalSourceItemModel } from '../../../../core/model/external-sources/external-source-item'; -import { UserModel } from '../../../../core/model/user/user'; -import { BaseCriteria } from '../../../../core/query/base-criteria'; -import { DatasetProfileCriteria } from '../../../../core/query/dataset-profile/dataset-profile-criteria'; -import { GrantCriteria } from '../../../../core/query/grant/grant-criteria'; -import { RequestItem } from '../../../../core/query/request-item'; -import { DmpService } from '../../../../core/services/dmp/dmp.service'; -import { ExternalSourcesService } from '../../../../core/services/external-sources/external-sources.service'; -import { GrantService } from '../../../../core/services/grant/grant.service'; -import { MultipleAutoCompleteConfiguration } from '../../../../library/auto-complete/multiple/multiple-auto-complete-configuration'; -import { SingleAutoCompleteConfiguration } from '../../../../library/auto-complete/single/single-auto-complete-configuration'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../../core/services/notification/ui-notification-service'; +import { map, takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-dmp-wizard-editor-component', @@ -73,21 +73,21 @@ export class DmpWizardEditorComponent extends BaseComponent implements OnInit { 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))), + 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'] }; this.organisationsAutoCompleteConfiguration = { 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))), + 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'] }; this.researchersAutoCompleteConfiguration = { 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))), + 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'] }; @@ -137,9 +137,9 @@ export class DmpWizardEditorComponent extends BaseComponent implements OnInit { } - availableProfiles() {} + availableProfiles() { } - addResearcher() {} + addResearcher() { } public cancel(): void { this.router.navigate(['/plans']); diff --git a/dmp-frontend/src/app/ui/dmp/wizard/listing/dmp-wizard-dataset-listing.component.ts b/dmp-frontend/src/app/ui/dmp/wizard/listing/dmp-wizard-dataset-listing.component.ts index 5d1d7c131..210b7034b 100644 --- a/dmp-frontend/src/app/ui/dmp/wizard/listing/dmp-wizard-dataset-listing.component.ts +++ b/dmp-frontend/src/app/ui/dmp/wizard/listing/dmp-wizard-dataset-listing.component.ts @@ -5,15 +5,15 @@ import { MatPaginator } from '@angular/material/paginator'; import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSort } from '@angular/material/sort'; import { ActivatedRoute, Params, Router } from '@angular/router'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing'; +import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { DatasetCriteriaComponent } from '@app/ui/dataset/listing/criteria/dataset-criteria.component'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../../core/common/base/base.component'; -import { DataTableRequest } from '../../../../core/model/data-table/data-table-request'; -import { DatasetListingModel } from '../../../../core/model/dataset/dataset-listing'; -import { DatasetCriteria } from '../../../../core/query/dataset/dataset-criteria'; -import { DatasetService } from '../../../../core/services/dataset/dataset.service'; -import { DmpService } from '../../../../core/services/dmp/dmp.service'; -import { DatasetCriteriaComponent } from '../../../dataset/listing/criteria/dataset-criteria.component'; @Component({ selector: 'app-dmp-wizard-dataset-listing-component', diff --git a/dmp-frontend/src/app/ui/explore-dataset/explore-dataset-listing.component.ts b/dmp-frontend/src/app/ui/explore-dataset/explore-dataset-listing.component.ts index cde24dce1..c3d83154b 100644 --- a/dmp-frontend/src/app/ui/explore-dataset/explore-dataset-listing.component.ts +++ b/dmp-frontend/src/app/ui/explore-dataset/explore-dataset-listing.component.ts @@ -1,18 +1,18 @@ -import {of as observableOf, Observable } from 'rxjs'; -import { Component, OnInit, ViewChild, ɵConsole } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; -import { Router, ActivatedRoute, Params } from '@angular/router'; -import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../core/common/base/base.component'; -import { DataTableRequest } from '../../core/model/data-table/data-table-request'; -import { DatasetListingModel } from '../../core/model/dataset/dataset-listing'; -import { ExploreDatasetCriteriaModel } from '../../core/query/explore-dataset/explore-dataset-criteria'; -import { DatasetService } from '../../core/services/dataset/dataset.service'; -import { IBreadCrumbComponent } from '../misc/breadcrumb/definition/IBreadCrumbComponent'; -import { BreadcrumbItem } from '../misc/breadcrumb/definition/breadcrumb-item'; +import { ActivatedRoute, Params, Router } from '@angular/router'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing'; +import { ExploreDatasetCriteriaModel } from '@app/core/query/explore-dataset/explore-dataset-criteria'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; -import { DmpService } from '../../core/services/dmp/dmp.service'; +import { Observable, of as observableOf } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { BreadcrumbItem } from '../misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '../misc/breadcrumb/definition/IBreadCrumbComponent'; @Component({ diff --git a/dmp-frontend/src/app/ui/explore-dataset/explore-dataset.module.ts b/dmp-frontend/src/app/ui/explore-dataset/explore-dataset.module.ts index d8598add3..b06554524 100644 --- a/dmp-frontend/src/app/ui/explore-dataset/explore-dataset.module.ts +++ b/dmp-frontend/src/app/ui/explore-dataset/explore-dataset.module.ts @@ -1,12 +1,12 @@ import { NgModule } from '@angular/core'; -import { CommonFormsModule } from '../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { AutoCompleteModule } from '../../library/auto-complete/auto-complete.module'; -import { ExploreDatasetListingComponent } from './explore-dataset-listing.component'; -import { ExploreDatasetRoutingModule } from './explore-dataset.routing'; -import { ExploreDatasetFilterItemComponent } from './filters/explore-dataset-filter-item/explore-dataset-filter-item.component'; -import { ExploreDatasetFiltersComponent } from './filters/explore-dataset-filters.component'; -import { ExploreDatasetListingItemComponent } from './listing-item/explore-dataset-listing-item.component'; +import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { ExploreDatasetListingComponent } from '@app/ui/explore-dataset/explore-dataset-listing.component'; +import { ExploreDatasetRoutingModule } from '@app/ui/explore-dataset/explore-dataset.routing'; +import { ExploreDatasetFilterItemComponent } from '@app/ui/explore-dataset/filters/explore-dataset-filter-item/explore-dataset-filter-item.component'; +import { ExploreDatasetFiltersComponent } from '@app/ui/explore-dataset/filters/explore-dataset-filters.component'; +import { ExploreDatasetListingItemComponent } from '@app/ui/explore-dataset/listing-item/explore-dataset-listing-item.component'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filter-item/explore-dataset-filter-item.component.ts b/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filter-item/explore-dataset-filter-item.component.ts index 718f7baea..fddaa4b57 100644 --- a/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filter-item/explore-dataset-filter-item.component.ts +++ b/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filter-item/explore-dataset-filter-item.component.ts @@ -1,12 +1,12 @@ -import {of as observableOf, Observable } from 'rxjs'; - -import {distinctUntilChanged, debounceTime, takeUntil } from 'rxjs/operators'; import { SelectionModel } from '@angular/cdk/collections'; import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { FormControl } from '@angular/forms'; import { MatListOption, MatSelectionList } from '@angular/material/list'; -import { BaseComponent } from '../../../../core/common/base/base.component'; +import { BaseComponent } from '@common/base/base.component'; +import { Observable, of as observableOf } from 'rxjs'; +import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; + @Component({ selector: 'app-explore-dataset-filter-item-component', @@ -53,7 +53,7 @@ export class ExploreDatasetFilterItemComponent extends BaseComponent implements ngOnInit(): void { if (!this.multipleSelect) { this.selectionList.selectedOptions = new SelectionModel(this.multipleSelect); } this.optionSearchControl.valueChanges.pipe(debounceTime(this.requestDelay), - distinctUntilChanged(),) + distinctUntilChanged()) .pipe(takeUntil(this._destroyed)) .subscribe(x => { if (this.filterOptions) { this.options = this.filterOptions(x); } }); } diff --git a/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.ts b/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.ts index 2a2fd6880..1f3bc2f4f 100644 --- a/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.ts +++ b/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.ts @@ -1,34 +1,34 @@ -import { of as observableOf, Observable } from 'rxjs'; - -import { map } from 'rxjs/operators'; import { AfterViewInit, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { MatAccordion } from '@angular/material/expansion'; import { ActivatedRoute } from '@angular/router'; +import { GrantStateType } from '@app/core/common/enum/grant-state-type'; +import { DataTableData } from '@app/core/model/data-table/data-table-data'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; +import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item'; +import { GrantListingModel } from '@app/core/model/grant/grant-listing'; +import { OrganizationModel } from '@app/core/model/organisation/organization'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { ExploreDatasetCriteriaModel } from '@app/core/query/explore-dataset/explore-dataset-criteria'; +import { ExploreDmpCriteriaModel } from '@app/core/query/explore-dmp/explore-dmp-criteria'; +import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; +import { OrganisationCriteria } from '@app/core/query/organisation/organisation-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { TagCriteria } from '@app/core/query/tag/tag-criteria'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; +import { GrantService } from '@app/core/services/grant/grant.service'; +import { OrganisationService } from '@app/core/services/organisation/organisation.service'; +import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { GrantStateType } from '../../../core/common/enum/grant-state-type'; -import { DatasetProfileModel } from '../../../core/model/dataset/dataset-profile'; -import { ExternalSourceItemModel } from '../../../core/model/external-sources/external-source-item'; -import { GrantListingModel } from '../../../core/model/grant/grant-listing'; -import { ExploreDatasetCriteriaModel } from '../../../core/query/explore-dataset/explore-dataset-criteria'; -import { GrantCriteria } from '../../../core/query/grant/grant-criteria'; -import { TagCriteria } from '../../../core/query/tag/tag-criteria'; -import { DatasetService } from '../../../core/services/dataset/dataset.service'; -import { ExternalSourcesService } from '../../../core/services/external-sources/external-sources.service'; -import { GrantService } from '../../../core/services/grant/grant.service'; -import { RequestItem } from '../../../core/query/request-item'; -import { DataTableRequest } from '../../../core/model/data-table/data-table-request'; -import { MultipleAutoCompleteConfiguration } from '../../../library/auto-complete/multiple/multiple-auto-complete-configuration'; -import { DmpService } from '../../../core/services/dmp/dmp.service'; -import { OrganisationCriteria } from '../../../core/query/organisation/organisation-criteria'; -import { OrganisationService } from '../../../core/services/organisation/organisation.service'; -import { OrganizationModel } from '../../../core/model/organisation/organization'; -import { DataTableData } from '../../../core/model/data-table/data-table-data'; -import { DmpListingModel } from '../../../core/model/dmp/dmp-listing'; -import { ExploreDmpCriteriaModel } from '../../../core/query/explore-dmp/explore-dmp-criteria'; -import { DatasetProfileCriteria } from "../../../core/query/dataset-profile/dataset-profile-criteria"; -import { AuthService } from '../../../core/services/auth/auth.service'; +import { Observable, of as observableOf } from 'rxjs'; +import { map } from 'rxjs/operators'; + @Component({ selector: 'app-explore-dataset-filters-component', @@ -65,7 +65,7 @@ export class ExploreDatasetFiltersComponent extends BaseComponent implements OnI tagsAutoCompleteConfiguration = { filterFn: this.filterTags.bind(this), - initialItems: (excludedItems: any[]) => this.filterTags('').pipe(map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + initialItems: (excludedItems: any[]) => this.filterTags('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['name'], titleFn: (item) => item['name'] }; @@ -81,7 +81,7 @@ export class ExploreDatasetFiltersComponent extends BaseComponent implements OnI filterFn: this.filterGrant.bind(this), initialItems: (excludedItems: any[]) => this.filterGrant('').pipe( - map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['label'], titleFn: (item) => item['label'] } @@ -90,7 +90,7 @@ export class ExploreDatasetFiltersComponent extends BaseComponent implements OnI filterFn: this.filterProfile.bind(this), initialItems: (excludedItems: any[]) => this.filterProfile('').pipe( - map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['label'], titleFn: (item) => item['label'] }; @@ -99,7 +99,7 @@ export class ExploreDatasetFiltersComponent extends BaseComponent implements OnI filterFn: this.filterOrganisation.bind(this), initialItems: (excludedItems: any[]) => this.getOrganisations().pipe( - map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['name'], titleFn: (item) => item['name'] } diff --git a/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filter-item/explore-dmp-filter-item.component.ts b/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filter-item/explore-dmp-filter-item.component.ts index 5b706d5e4..f18a44f34 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filter-item/explore-dmp-filter-item.component.ts +++ b/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filter-item/explore-dmp-filter-item.component.ts @@ -1,12 +1,12 @@ -import {of as observableOf, Observable } from 'rxjs'; - -import {distinctUntilChanged, debounceTime, takeUntil } from 'rxjs/operators'; import { SelectionModel } from '@angular/cdk/collections'; import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { FormControl } from '@angular/forms'; import { MatListOption, MatSelectionList } from '@angular/material/list'; -import { BaseComponent } from '../../../../core/common/base/base.component'; +import { BaseComponent } from '@common/base/base.component'; +import { Observable, of as observableOf } from 'rxjs'; +import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; + @Component({ selector: 'app-explore-dmp-filter-item-component', @@ -44,7 +44,7 @@ export class ExploreDmpFilterItemComponent extends BaseComponent implements OnIn ngOnInit(): void { if (!this.multipleSelect) { this.selectionList.selectedOptions = new SelectionModel(this.multipleSelect); } this.optionSearchControl.valueChanges.pipe(debounceTime(this.requestDelay), - distinctUntilChanged(),) + distinctUntilChanged()) .pipe(takeUntil(this._destroyed)) .subscribe(x => { if (this.filterOptions) { this.options = this.filterOptions(x); } }); } diff --git a/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component.ts b/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component.ts index 73c4f8048..d65d47541 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component.ts +++ b/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component.ts @@ -1,29 +1,29 @@ -import { of as observableOf, Observable } from 'rxjs'; - -import { map } from 'rxjs/operators'; import { AfterViewInit, Component, EventEmitter, Input, OnInit, Output, ViewChild } from "@angular/core"; import { MatAccordion } from "@angular/material/expansion"; import { ActivatedRoute } from "@angular/router"; +import { GrantStateType } from '@app/core/common/enum/grant-state-type'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { GrantListingModel } from '@app/core/model/grant/grant-listing'; +import { OrganizationModel } from '@app/core/model/organisation/organization'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { ExploreDmpCriteriaModel } from '@app/core/query/explore-dmp/explore-dmp-criteria'; +import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; +import { OrganisationCriteria } from '@app/core/query/organisation/organisation-criteria'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; +import { GrantService } from '@app/core/services/grant/grant.service'; +import { OrganisationService } from '@app/core/services/organisation/organisation.service'; +import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; +import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from "@ngx-translate/core"; -import { ValidationErrorModel } from "../../../common/forms/validation/error-model/validation-error-model"; -import { GrantStateType } from '../../../core/common/enum/grant-state-type'; -import { DataTableRequest } from "../../../core/model/data-table/data-table-request"; -import { DatasetProfileModel } from "../../../core/model/dataset/dataset-profile"; -import { GrantListingModel } from "../../../core/model/grant/grant-listing"; -import { ExploreDmpCriteriaModel } from "../../../core/query/explore-dmp/explore-dmp-criteria"; -import { GrantCriteria } from "../../../core/query/grant/grant-criteria"; -import { DatasetService } from "../../../core/services/dataset/dataset.service"; -import { DmpService } from "../../../core/services/dmp/dmp.service"; -import { ExternalSourcesService } from "../../../core/services/external-sources/external-sources.service"; -import { GrantService } from "../../../core/services/grant/grant.service"; -import { MultipleAutoCompleteConfiguration } from "../../../library/auto-complete/multiple/multiple-auto-complete-configuration"; -import { BaseCriteriaComponent } from "../../misc/criteria/base-criteria.component"; -import { OrganizationModel } from "../../../core/model/organisation/organization"; -import { OrganisationCriteria } from "../../../core/query/organisation/organisation-criteria"; -import { OrganisationService } from "../../../core/services/organisation/organisation.service"; -import { DatasetProfileCriteria } from "../../../core/query/dataset-profile/dataset-profile-criteria"; -import { AuthService } from '../../../core/services/auth/auth.service'; +import { Observable, of as observableOf } from 'rxjs'; +import { map } from 'rxjs/operators'; + @Component({ selector: 'app-explore-dmp-filters-component', @@ -69,7 +69,7 @@ export class ExploreDmpFiltersComponent extends BaseCriteriaComponent implements filterFn: this.filterProfile.bind(this), initialItems: (excludedItems: any[]) => this.filterProfile('').pipe( - map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['label'], titleFn: (item) => item['label'] }; @@ -78,7 +78,7 @@ export class ExploreDmpFiltersComponent extends BaseCriteriaComponent implements filterFn: this.filterOrganisation.bind(this), initialItems: (excludedItems: any[]) => this.getOrganisations().pipe( - map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['name'], titleFn: (item) => item['name'] } @@ -87,7 +87,7 @@ export class ExploreDmpFiltersComponent extends BaseCriteriaComponent implements filterFn: this.filterGrant.bind(this), initialItems: (excludedItems: any[]) => this.filterGrant('').pipe( - map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1))), + map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['label'], titleFn: (item) => item['label'] } diff --git a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.ts b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.ts index b9b735336..0ab48acfb 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.ts +++ b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.ts @@ -1,18 +1,18 @@ -import { of as observableOf, Observable } from 'rxjs'; import { Component, OnInit, ViewChild } from "@angular/core"; import { MatPaginator } from "@angular/material/paginator"; import { MatSort } from "@angular/material/sort"; -import { Router, ActivatedRoute } from "@angular/router"; -import { takeUntil } from "rxjs/operators"; -import { BaseComponent } from "../../core/common/base/base.component"; -import { DataTableRequest } from "../../core/model/data-table/data-table-request"; -import { DmpListingModel } from "../../core/model/dmp/dmp-listing"; -import { ExploreDmpCriteriaModel } from "../../core/query/explore-dmp/explore-dmp-criteria"; -import { DmpService } from "../../core/services/dmp/dmp.service"; -import { IBreadCrumbComponent } from "../misc/breadcrumb/definition/IBreadCrumbComponent"; -import { BreadcrumbItem } from "../misc/breadcrumb/definition/breadcrumb-item"; -import { TranslateService } from "@ngx-translate/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; +import { ExploreDmpCriteriaModel } from '@app/core/query/explore-dmp/explore-dmp-criteria'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { BaseComponent } from '@common/base/base.component'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable, of as observableOf } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-explore-dmp-listing-component', diff --git a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp.module.ts b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp.module.ts index d5b211fd8..51046c470 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp.module.ts +++ b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp.module.ts @@ -1,13 +1,13 @@ import { NgModule } from "@angular/core"; -import { CommonFormsModule } from "../../common/forms/common-forms.module"; -import { CommonUiModule } from "../../common/ui/common-ui.module"; -import { AutoCompleteModule } from "../../library/auto-complete/auto-complete.module"; -import { ExploreDmpFilterItemComponent } from "./dmp-explore-filters/explore-dmp-filter-item/explore-dmp-filter-item.component"; -import { ExploreDmpFiltersComponent } from "./dmp-explore-filters/explore-dmp-filters.component"; -import { ExploreDmpListingComponent } from "./explore-dmp-listing.component"; -import { ExploreDmpRoutingModule } from "./explore-dmp.routing"; -import { ExploreDmpListingItemComponent } from "./listing-item/explore-dmp-listing-item.component"; -import { DmpOverviewModule } from "../dmp/overview/dmp-overview.module"; +import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { DmpOverviewModule } from '@app/ui/dmp/overview/dmp-overview.module'; +import { ExploreDmpFilterItemComponent } from '@app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filter-item/explore-dmp-filter-item.component'; +import { ExploreDmpFiltersComponent } from '@app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component'; +import { ExploreDmpListingComponent } from '@app/ui/explore-dmp/explore-dmp-listing.component'; +import { ExploreDmpRoutingModule } from '@app/ui/explore-dmp/explore-dmp.routing'; +import { ExploreDmpListingItemComponent } from '@app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/faq/faq.module.ts b/dmp-frontend/src/app/ui/faq/faq.module.ts index 654c43b93..71b795ed3 100644 --- a/dmp-frontend/src/app/ui/faq/faq.module.ts +++ b/dmp-frontend/src/app/ui/faq/faq.module.ts @@ -1,8 +1,8 @@ import { NgModule } from '@angular/core'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { FaqRoutingModule } from './faq.routing'; +import { CommonUiModule } from '@common/ui/common-ui.module'; import { FaqDialogComponent } from './dialog/faq-dialog.component'; import { FaqContentComponent } from './faq-content/faq-content.component'; +import { FaqRoutingModule } from './faq.routing'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/glossary/glossary.module.ts b/dmp-frontend/src/app/ui/glossary/glossary.module.ts index 07cf5d1a6..c84ed0310 100644 --- a/dmp-frontend/src/app/ui/glossary/glossary.module.ts +++ b/dmp-frontend/src/app/ui/glossary/glossary.module.ts @@ -1,8 +1,8 @@ import { NgModule } from '@angular/core'; -import { GlossaryRoutingModule } from './glossary.routing'; -import { GlossaryContentComponent } from './glossary-content/glossary-content.component'; +import { CommonUiModule } from '@common/ui/common-ui.module'; import { GlossaryDialogComponent } from './dialog/glossary-dialog.component'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; +import { GlossaryContentComponent } from './glossary-content/glossary-content.component'; +import { GlossaryRoutingModule } from './glossary.routing'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/grant/editor/grant-editor.component.ts b/dmp-frontend/src/app/ui/grant/editor/grant-editor.component.ts index 6011e48a9..6310ae2da 100644 --- a/dmp-frontend/src/app/ui/grant/editor/grant-editor.component.ts +++ b/dmp-frontend/src/app/ui/grant/editor/grant-editor.component.ts @@ -1,25 +1,25 @@ -import {of as observableOf, Observable } from 'rxjs'; - -import {map, takeUntil } from 'rxjs/operators'; import { Component, OnInit } from '@angular/core'; import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { MatSnackBar } from '@angular/material/snack-bar'; import { ActivatedRoute, Params, Router } from '@angular/router'; +import { GrantType } from '@app/core/common/enum/grant-type'; +import { GrantListingModel } from '@app/core/model/grant/grant-listing'; +import { GrantFileUploadService } from '@app/core/services/grant/grant-file-upload.service'; +import { GrantService } from '@app/core/services/grant/grant.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { GrantEditorModel } from '@app/ui/grant/editor/grant-editor.model'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { BaseComponent } from '@common/base/base.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; -import { environment } from '../../../../environments/environment'; -import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { GrantType } from '../../../core/common/enum/grant-type'; -import { GrantListingModel } from '../../../core/model/grant/grant-listing'; -import { GrantFileUploadService } from '../../../core/services/grant/grant-file-upload.service'; -import { GrantService } from '../../../core/services/grant/grant.service'; -import { ConfirmationDialogComponent } from '../../../library/confirmation-dialog/confirmation-dialog.component'; -import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '../../misc/breadcrumb/definition/IBreadCrumbComponent'; -import { GrantEditorModel } from './grant-editor.model'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../core/services/notification/ui-notification-service'; +import { environment } from 'environments/environment'; +import { Observable, of as observableOf } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; + @Component({ selector: 'app-grant-editor-component', diff --git a/dmp-frontend/src/app/ui/grant/editor/grant-editor.model.ts b/dmp-frontend/src/app/ui/grant/editor/grant-editor.model.ts index 13128fb8f..8b783111c 100644 --- a/dmp-frontend/src/app/ui/grant/editor/grant-editor.model.ts +++ b/dmp-frontend/src/app/ui/grant/editor/grant-editor.model.ts @@ -1,7 +1,7 @@ -import { FormBuilder, FormGroup, Validators, AbstractControl } from '@angular/forms'; -import { BackendErrorValidator } from '../../../common/forms/validation/custom-validator'; -import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model'; -import { ValidationContext } from '../../../common/forms/validation/validation-context'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; import { GrantType } from '../../../core/common/enum/grant-type'; import { Status } from '../../../core/common/enum/Status'; import { ContentFile, GrantListingModel } from '../../../core/model/grant/grant-listing'; @@ -51,7 +51,7 @@ export class GrantEditorModel { startDate: [{ value: this.startDate, disabled: disabled }, context.getValidation('startDate').validators], endDate: [{ value: this.endDate, disabled: disabled }, context.getValidation('endDate').validators], files: [{ value: this.files, disabled: disabled }, context.getValidation('files').validators] - },{ validator: startEndValidator }); + }, { validator: startEndValidator }); return formGroup; } @@ -76,9 +76,8 @@ export class GrantEditorModel { export function startEndValidator(formGroup: FormGroup) { const start = formGroup.get('startDate').value; const end = formGroup.get('endDate').value; - if(start!=null && end != null && end { - if (x) { this.onItemChange.emit(x); } + if (x) { + this.onItemChange.emit(x); + this.formControl.reset(); + } }); } diff --git a/dmp-frontend/src/app/ui/misc/help-content/help-content.component.ts b/dmp-frontend/src/app/ui/misc/help-content/help-content.component.ts index fa4aa9f41..5ca816123 100644 --- a/dmp-frontend/src/app/ui/misc/help-content/help-content.component.ts +++ b/dmp-frontend/src/app/ui/misc/help-content/help-content.component.ts @@ -3,10 +3,10 @@ */ import { Component, Input, OnInit } from '@angular/core'; import { ActivatedRoute, NavigationStart, Router } from '@angular/router'; +import { PageHelpContent } from '@app/core/model/help-content/page-help-content'; +import { HelpContentService } from '@app/core/services/help-content/help-content.service'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { PageHelpContent } from '../../../core/model/help-content/page-help-content'; -import { HelpContentService } from '../../../core/services/help-content/help-content.service'; @Component({ selector: 'app-help-content', diff --git a/dmp-frontend/src/app/ui/misc/help-content/help-content.module.ts b/dmp-frontend/src/app/ui/misc/help-content/help-content.module.ts index ae67f9f8b..de7863976 100644 --- a/dmp-frontend/src/app/ui/misc/help-content/help-content.module.ts +++ b/dmp-frontend/src/app/ui/misc/help-content/help-content.module.ts @@ -1,6 +1,6 @@ import { NgModule } from '@angular/core'; -import { CommonUiModule } from '../../../common/ui/common-ui.module'; -import { HelpContentComponent } from './help-content.component'; +import { HelpContentComponent } from '@app/ui/misc/help-content/help-content.component'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/misc/navigation/navigation.component.ts b/dmp-frontend/src/app/ui/misc/navigation/navigation.component.ts index b16e560ce..60daecb04 100644 --- a/dmp-frontend/src/app/ui/misc/navigation/navigation.component.ts +++ b/dmp-frontend/src/app/ui/misc/navigation/navigation.component.ts @@ -1,21 +1,21 @@ -import {mergeMap, distinctUntilChanged, debounceTime, takeUntil } from 'rxjs/operators'; import { Component, OnInit } from '@angular/core'; import { FormControl } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { Router } from '@angular/router'; +import { AppRole } from '@app/core/common/enum/app-role'; +import { SearchBarItem } from '@app/core/model/dashboard/search-bar-item'; +import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { GrantService } from '@app/core/services/grant/grant.service'; +import { ProgressIndicationService } from '@app/core/services/progress-indication/progress-indication-service'; +import { SearchBarService } from '@app/core/services/search-bar/search-bar.service'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { UserDialogComponent } from '@app/ui/misc/navigation/user-dialog/user-dialog.component'; +import { BaseComponent } from '@common/base/base.component'; import { Observable } from 'rxjs'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { AppRole } from '../../../core/common/enum/app-role'; -import { SearchBarItem } from '../../../core/model/dashboard/search-bar-item'; -import { GrantCriteria } from '../../../core/query/grant/grant-criteria'; -import { RequestItem } from '../../../core/query/request-item'; -import { AuthService } from '../../../core/services/auth/auth.service'; -import { ProgressIndicationService } from '../../../core/services/progress-indication/progress-indication-service'; -import { GrantService } from '../../../core/services/grant/grant.service'; -import { SearchBarService } from '../../../core/services/search-bar/search-bar.service'; -import { SingleAutoCompleteConfiguration } from '../../../library/auto-complete/single/single-auto-complete-configuration'; -import { UserDialogComponent } from './user-dialog/user-dialog.component'; +import { debounceTime, distinctUntilChanged, mergeMap, takeUntil } from 'rxjs/operators'; export enum SearchBarType { Dataset = 0, @@ -60,9 +60,9 @@ export class NavigationComponent extends BaseComponent implements OnInit { titleFn: (item) => item['label'] }; - this.filteredOptions = this.searchControl.valueChanges.pipe(debounceTime(500),distinctUntilChanged(),mergeMap(x => { + this.filteredOptions = this.searchControl.valueChanges.pipe(debounceTime(500), distinctUntilChanged(), mergeMap(x => { return this.searchBarService.search(x); - }),); + })); } searchGrant(query: string) { diff --git a/dmp-frontend/src/app/ui/misc/navigation/navigation.module.ts b/dmp-frontend/src/app/ui/misc/navigation/navigation.module.ts index 3cfef3c81..c7e8099af 100644 --- a/dmp-frontend/src/app/ui/misc/navigation/navigation.module.ts +++ b/dmp-frontend/src/app/ui/misc/navigation/navigation.module.ts @@ -1,10 +1,9 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; -import { CommonFormsModule } from '../../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../../common/ui/common-ui.module'; -import { NavigationComponent } from './navigation.component'; -import { UserDialogComponent } from './user-dialog/user-dialog.component'; -import { SearchComponent } from '../search/search.component'; +import { NavigationComponent } from '@app/ui/misc/navigation/navigation.component'; +import { UserDialogComponent } from '@app/ui/misc/navigation/user-dialog/user-dialog.component'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/misc/unauthorized/unauthorized.component.ts b/dmp-frontend/src/app/ui/misc/unauthorized/unauthorized.component.ts index 22233f4ef..7102be364 100644 --- a/dmp-frontend/src/app/ui/misc/unauthorized/unauthorized.component.ts +++ b/dmp-frontend/src/app/ui/misc/unauthorized/unauthorized.component.ts @@ -1,8 +1,8 @@ import { AfterViewInit, Component, Input } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { AuthService } from '../../../core/services/auth/auth.service'; @Component({ selector: 'app-unauthorized-component', diff --git a/dmp-frontend/src/app/ui/misc/unauthorized/unauthorized.module.ts b/dmp-frontend/src/app/ui/misc/unauthorized/unauthorized.module.ts index c25f31acd..3970bc105 100644 --- a/dmp-frontend/src/app/ui/misc/unauthorized/unauthorized.module.ts +++ b/dmp-frontend/src/app/ui/misc/unauthorized/unauthorized.module.ts @@ -1,7 +1,7 @@ import { NgModule } from "@angular/core"; -import { CommonUiModule } from "../../../common/ui/common-ui.module"; -import { UnauthorizedComponent } from "./unauthorized.component"; -import { UnauthorizedRoutingModule } from "./unauthorized.routes"; +import { UnauthorizedComponent } from '@app/ui/misc/unauthorized/unauthorized.component'; +import { UnauthorizedRoutingModule } from '@app/ui/misc/unauthorized/unauthorized.routes'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/navbar/navbar.component.ts b/dmp-frontend/src/app/ui/navbar/navbar.component.ts index fad635899..d9105405a 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.component.ts +++ b/dmp-frontend/src/app/ui/navbar/navbar.component.ts @@ -1,15 +1,14 @@ -import { Component, OnInit, ElementRef } from '@angular/core'; -import { GENERAL_ROUTES, DMP_ROUTES, DATASETS_ROUTES } from '../sidebar/sidebar.component'; -// import { HISTORY_ROUTES } from '../sidebar/sidebar.component'; -import { Location, LocationStrategy, PathLocationStrategy } from '@angular/common'; +import { Location } from '@angular/common'; +import { Component, ElementRef, OnInit } from '@angular/core'; +import { MatDialog } from '@angular/material'; import { Router } from '@angular/router'; -import { AuthService } from '../../core/services/auth/auth.service'; -import { MatDialog } from '@angular/material/dialog'; -import { UserDialogComponent } from '../misc/navigation/user-dialog/user-dialog.component'; -import { AppRole } from '../../core/common/enum/app-role'; -import { ProgressIndicationService } from '../../core/services/progress-indication/progress-indication-service'; -import { BaseComponent } from '../../core/common/base/base.component'; +import { AppRole } from '@app/core/common/enum/app-role'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { ProgressIndicationService } from '@app/core/services/progress-indication/progress-indication-service'; +import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; +import { UserDialogComponent } from '../misc/navigation/user-dialog/user-dialog.component'; +import { DATASETS_ROUTES, DMP_ROUTES, GENERAL_ROUTES } from '../sidebar/sidebar.component'; @Component({ selector: 'app-navbar', diff --git a/dmp-frontend/src/app/ui/navbar/navbar.module.ts b/dmp-frontend/src/app/ui/navbar/navbar.module.ts index 54420be4f..4d89a8027 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.module.ts +++ b/dmp-frontend/src/app/ui/navbar/navbar.module.ts @@ -1,10 +1,10 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; -import { CommonFormsModule } from '../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { NavbarComponent } from './navbar.component'; -import { SearchComponent } from '../misc/search/search.component'; -import { BreadcrumbModule } from '../misc/breadcrumb/breadcrumb.module'; +import { BreadcrumbModule } from '@app/ui/misc/breadcrumb/breadcrumb.module'; +import { SearchComponent } from '@app/ui/misc/search/search.component'; +import { NavbarComponent } from '@app/ui/navbar/navbar.component'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard-model.ts b/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard-model.ts index 84710c8a4..c681b72f5 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard-model.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard-model.ts @@ -1,17 +1,16 @@ -import { FormBuilder, FormGroup, Validators } from "@angular/forms"; -import { BackendErrorValidator } from "../../../common/forms/validation/custom-validator"; -import { ValidationErrorModel } from "../../../common/forms/validation/error-model/validation-error-model"; -import { ValidationContext } from "../../../common/forms/validation/validation-context"; -import { BaseFormModel } from "../../../core/model/base-form-model"; -import { DatasetWizardEditorModel } from "../../dataset/dataset-wizard/dataset-wizard-editor.model"; -import { QuickWizardDatasetDescriptionModel } from "./quick-wizard-dataset-description-model"; - +import { FormBuilder, FormGroup } from "@angular/forms"; +import { BaseFormModel } from '@app/core/model/base-form-model'; +import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; +import { QuickWizardDatasetDescriptionModel } from '@app/ui/quick-wizard/dataset-editor/quick-wizard-dataset-description-model'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; export class DatasetEditorWizardModel extends BaseFormModel { public datasetsList: Array = []; - public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); - public viewOnly: boolean; + public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); + public viewOnly: boolean; fromModel(item: DatasetWizardEditorModel[]): DatasetEditorWizardModel { @@ -20,7 +19,7 @@ export class DatasetEditorWizardModel extends BaseFormModel { buildForm(context: ValidationContext = null): FormGroup { if (context == null) { context = this.createValidationContext(); } - const formGroup = new FormBuilder().group({},context.getValidation('datasetsList').validators); + const formGroup = new FormBuilder().group({}, context.getValidation('datasetsList').validators); const formArray = new Array(); this.datasetsList.forEach(item => { const form: FormGroup = item.buildForm(); @@ -32,7 +31,7 @@ export class DatasetEditorWizardModel extends BaseFormModel { createValidationContext(): ValidationContext { const baseContext: ValidationContext = new ValidationContext(); - baseContext.validation.push({ key: 'datasetsList', validators:[BackendErrorValidator(this.validationErrorModel, 'datasetsList')] }); + baseContext.validation.push({ key: 'datasetsList', validators: [BackendErrorValidator(this.validationErrorModel, 'datasetsList')] }); return baseContext; } diff --git a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts index 72f746bb5..a32b77b64 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts @@ -1,14 +1,14 @@ import { Component, Input, OnInit } from "@angular/core"; import { FormArray, FormGroup } from "@angular/forms"; +import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { DatasetDescriptionFormEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; +import { QuickWizardDatasetDescriptionModel } from '@app/ui/quick-wizard/dataset-editor/quick-wizard-dataset-description-model'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from "@ngx-translate/core"; import { Observable } from "rxjs"; import { takeUntil } from "rxjs/operators"; -import { BaseComponent } from "../../../core/common/base/base.component"; -import { DatasetWizardService } from "../../../core/services/dataset-wizard/dataset-wizard.service"; -import { BreadcrumbItem } from "../../misc/breadcrumb/definition/breadcrumb-item"; -import { IBreadCrumbComponent } from "../../misc/breadcrumb/definition/IBreadCrumbComponent"; -import { DatasetDescriptionFormEditorModel } from "../../misc/dataset-description-form/dataset-description-form.model"; -import { QuickWizardDatasetDescriptionModel } from "./quick-wizard-dataset-description-model"; @Component({ selector: 'app-dataset-editor-wizard-component', diff --git a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts index 8da1d888f..0ec5bf74c 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts @@ -1,12 +1,12 @@ -import { Status } from "../../../core/common/enum/Status"; -import { DmpProfile, DmpProfileDefinition } from "../../../core/model/dmp-profile/dmp-profile"; -import { ValidationErrorModel } from "../../../common/forms/validation/error-model/validation-error-model"; -import { DmpModel } from "../../../core/model/dmp/dmp"; -import { ValidationContext } from "../../../common/forms/validation/validation-context"; -import { FormBuilder, FormGroup, Validators } from "@angular/forms"; -import { BackendErrorValidator } from "../../../common/forms/validation/custom-validator"; -import { ValidJsonValidator } from "../../../library/auto-complete/auto-complete-custom-validator"; -import { DatasetProfileModel } from "../../../core/model/dataset/dataset-profile"; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Status } from '@app/core/common/enum/Status'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { ValidJsonValidator } from '@app/library/auto-complete/auto-complete-custom-validator'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; export class DmpEditorWizardModel { public id: string; diff --git a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.ts index 7f4fbea97..4674857d6 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.ts @@ -1,20 +1,20 @@ -import {of as observableOf, Observable } from 'rxjs'; import { Component, Input, OnInit } from '@angular/core'; import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; import { MatSnackBar } from '@angular/material/snack-bar'; import { ActivatedRoute, Router } from '@angular/router'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { BaseComponent } from '@common/base/base.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; -import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model'; -import { BaseComponent } from "../../../core/common/base/base.component"; -import { DatasetProfileModel } from '../../../core/model/dataset/dataset-profile'; -import { DatasetProfileCriteria } from '../../../core/query/dataset-profile/dataset-profile-criteria'; -import { RequestItem } from '../../../core/query/request-item'; -import { DmpService } from '../../../core/services/dmp/dmp.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../core/services/notification/ui-notification-service'; -import { SingleAutoCompleteConfiguration } from '../../../library/auto-complete/single/single-auto-complete-configuration'; -import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '../../misc/breadcrumb/definition/IBreadCrumbComponent'; +import { Observable, of as observableOf } from 'rxjs'; import { DmpEditorWizardModel } from './dmp-editor-wizard-model'; diff --git a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard-model.ts b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard-model.ts index 8468d48a1..b8f30cc6e 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard-model.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard-model.ts @@ -1,10 +1,10 @@ -import { Status } from "../../../core/common/enum/Status"; -import { GrantListingModel } from "../../../core/model/grant/grant-listing"; -import { ValidationContext } from "../../../common/forms/validation/validation-context"; -import { FormGroup, FormBuilder, Validators } from "@angular/forms"; -import { BackendErrorValidator } from "../../../common/forms/validation/custom-validator"; -import { ValidationErrorModel } from "../../../common/forms/validation/error-model/validation-error-model"; -import { ValidJsonValidator } from "../../../library/auto-complete/auto-complete-custom-validator"; +import { FormBuilder, FormGroup, Validators } from "@angular/forms"; +import { Status } from '@app/core/common/enum/Status'; +import { GrantListingModel } from '@app/core/model/grant/grant-listing'; +import { ValidJsonValidator } from '@app/library/auto-complete/auto-complete-custom-validator'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; export class GrantEditorWizardModel { public id: string; diff --git a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts index 47f1c730a..c1a605c8a 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts @@ -1,20 +1,20 @@ -import { of as observableOf, Observable } from 'rxjs'; import { Component, Input, OnInit } from '@angular/core'; import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { ActivatedRoute, Router } from '@angular/router'; +import { Router } from '@angular/router'; +import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { GrantService } from '@app/core/services/grant/grant.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { GrantEditorWizardModel } from '@app/ui/quick-wizard/grant-editor/grant-editor-wizard-model'; +import { BaseComponent } from '@common/base/base.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; -import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model'; -import { BaseComponent } from "../../../core/common/base/base.component"; -import { GrantCriteria } from '../../../core/query/grant/grant-criteria'; -import { RequestItem } from '../../../core/query/request-item'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../core/services/notification/ui-notification-service'; -import { GrantService } from '../../../core/services/grant/grant.service'; -import { SingleAutoCompleteConfiguration } from '../../../library/auto-complete/single/single-auto-complete-configuration'; -import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '../../misc/breadcrumb/definition/IBreadCrumbComponent'; -import { GrantEditorWizardModel } from './grant-editor-wizard-model'; +import { Observable, of as observableOf } from 'rxjs'; @Component({ selector: 'app-quick-wizard-grant-editor-component', diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.ts b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.ts index 9345b7ea1..2867109dc 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.ts @@ -1,29 +1,29 @@ -import { of as observableOf, Observable } from 'rxjs'; -import { Component, OnInit, ViewChild, HostListener } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { MatSnackBar } from '@angular/material/snack-bar'; import { MatStepper } from '@angular/material/stepper'; -import { ActivatedRoute, Router } from '@angular/router'; +import { Router } from '@angular/router'; +import { DatasetStatus } from '@app/core/common/enum/dataset-status'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { QuickWizardService } from '@app/core/services/quick-wizard/quick-wizard.service'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; +import { DmpFinalizeDialogComponent, DmpFinalizeDialogDataset, DmpFinalizeDialogInput } from '@app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; +import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; +import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; +import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { DatasetEditorWizardComponent } from '@app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component'; +import { GrantEditorWizardModel } from '@app/ui/quick-wizard/grant-editor/grant-editor-wizard-model'; +import { QuickWizardEditorWizardModel } from '@app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; +import { Observable, of as observableOf } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model'; -import { DatasetStatus } from '../../../core/common/enum/dataset-status'; -import { DmpStatus } from '../../../core/common/enum/dmp-status'; -import { DatasetService } from '../../../core/services/dataset/dataset.service'; -import { SnackBarNotificationLevel, UiNotificationService, PopupNotification } from '../../../core/services/notification/ui-notification-service'; -import { QuickWizardService } from '../../../core/services/quick-wizard/quick-wizard.service'; -import { ConfirmationDialogComponent } from '../../../library/confirmation-dialog/confirmation-dialog.component'; -import { DmpFinalizeDialogComponent, DmpFinalizeDialogDataset, DmpFinalizeDialogInput } from '../../dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; -import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '../../misc/breadcrumb/definition/IBreadCrumbComponent'; -import { DatasetEditorWizardComponent } from '../dataset-editor/dataset-editor-wizard.component'; -import { GrantEditorWizardModel } from '../grant-editor/grant-editor-wizard-model'; -import { QuickWizardEditorWizardModel } from './quick-wizard-editor.model'; -import { FunderFormModel } from '../../dmp/editor/grant-tab/funder-form-model'; -import { ProjectFormModel } from '../../dmp/editor/grant-tab/project-form-model'; -import { CheckDeactivateBaseComponent } from '../../../library/deactivate/deactivate.component'; @Component({ selector: 'app-quick-wizard-editor-component', diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model.ts b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model.ts index 617c68ade..c707da664 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model.ts @@ -1,23 +1,22 @@ -import { GrantEditorWizardModel } from "../grant-editor/grant-editor-wizard-model"; -import { DmpEditorWizardModel } from "../dmp-editor/dmp-editor-wizard-model"; -import { DmpModel } from "../../../core/model/dmp/dmp"; -import { GrantListingModel } from "../../../core/model/grant/grant-listing"; -import { DatasetModel } from "../../../core/model/dataset/dataset"; -import { ValidationContext } from "../../../common/forms/validation/validation-context"; -import { FormGroup, FormBuilder, Validators } from "@angular/forms"; -import { BackendErrorValidator } from "../../../common/forms/validation/custom-validator"; -import { ValidationErrorModel } from "../../../common/forms/validation/error-model/validation-error-model"; -import { DatasetEditorWizardModel } from "../dataset-editor/dataset-editor-wizard-model"; -import { DatasetWizardEditorModel } from "../../dataset/dataset-wizard/dataset-wizard-editor.model"; -import { FunderModel } from "../../../core/model/funder/funder"; -import { FunderFormModel } from "../../dmp/editor/grant-tab/funder-form-model"; -import { ProjectFormModel } from "../../dmp/editor/grant-tab/project-form-model"; -import { ProjectModel } from "../../../core/model/project/project"; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { FunderModel } from '@app/core/model/funder/funder'; +import { GrantListingModel } from '@app/core/model/grant/grant-listing'; +import { ProjectModel } from '@app/core/model/project/project'; +import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; +import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; +import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; +import { DatasetEditorWizardModel } from '../dataset-editor/dataset-editor-wizard-model'; +import { DmpEditorWizardModel } from '../dmp-editor/dmp-editor-wizard-model'; +import { GrantEditorWizardModel } from '../grant-editor/grant-editor-wizard-model'; + export class QuickWizardEditorWizardModel { - public grant: GrantEditorWizardModel; - public funder: FunderFormModel; - public project: ProjectFormModel; + public grant: GrantEditorWizardModel; + public funder: FunderFormModel; + public project: ProjectFormModel; public dmp: DmpEditorWizardModel; public datasets: DatasetEditorWizardModel; public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); @@ -25,17 +24,17 @@ export class QuickWizardEditorWizardModel { fromModelGrant(item: GrantListingModel): QuickWizardEditorWizardModel { this.grant.fromModel(item); return this; - } + } - fromModelFunder(item: FunderModel): QuickWizardEditorWizardModel { - this.funder.fromModel(item); - return this; - } + fromModelFunder(item: FunderModel): QuickWizardEditorWizardModel { + this.funder.fromModel(item); + return this; + } - fromModelProject(item: ProjectModel): QuickWizardEditorWizardModel { - this.project.fromModel(item); - return this; - } + fromModelProject(item: ProjectModel): QuickWizardEditorWizardModel { + this.project.fromModel(item); + return this; + } fromModelDmp(item: DmpModel): QuickWizardEditorWizardModel { this.dmp.fromModel(item); @@ -45,14 +44,14 @@ export class QuickWizardEditorWizardModel { fromModelDataset(item: DatasetWizardEditorModel[]): QuickWizardEditorWizardModel { this.datasets.fromModel(item); return this; - } + } buildForm(context: ValidationContext = null): FormGroup { // if (context == null) { context = this.createValidationContext(); } const formGroup = new FormBuilder().group({ - grant: new GrantEditorWizardModel().buildForm(), - funder: new FunderFormModel().buildForm(), - project: new ProjectFormModel().buildForm(), + grant: new GrantEditorWizardModel().buildForm(), + funder: new FunderFormModel().buildForm(), + project: new ProjectFormModel().buildForm(), dmp: new DmpEditorWizardModel().buildForm(), datasets: new DatasetEditorWizardModel().buildForm() diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.module.ts b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.module.ts index d0f5980af..99bdfc6e5 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.module.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.module.ts @@ -1,19 +1,19 @@ import { NgModule } from '@angular/core'; -import { CommonFormsModule } from '../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { ConfirmationDialogModule } from '../../library/confirmation-dialog/confirmation-dialog.module'; -import { UrlListingModule } from '../../library/url-listing/url-listing.module'; -import { QuickWizardRoutingModule } from './quick-wizard.routing'; -import { GrantEditorWizardComponent } from './grant-editor/grant-editor-wizard.component'; -import { DmpEditorWizardComponent } from './dmp-editor/dmp-editor-wizard.component'; -import { QuickWizardEditorComponent } from './quick-wizard-editor/quick-wizard-editor.component'; -import { AutoCompleteModule } from '../../library/auto-complete/auto-complete.module'; -import { DatasetEditorWizardComponent } from './dataset-editor/dataset-editor-wizard.component'; -import { DatasetDescriptionFormModule } from '../misc/dataset-description-form/dataset-description-form.module'; -import { DmpModule } from '../dmp/dmp.module'; -import { FunderEditorWizardComponent } from './funder-editor/funder-editor-wizard.component'; -import { ProjectEditorWizardComponent } from './project-editor/project-editor-wizard.component'; -import { CanDeactivateGuard } from '../../library/deactivate/can-deactivate.guard'; +import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; +import { CanDeactivateGuard } from '@app/library/deactivate/can-deactivate.guard'; +import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; +import { DmpModule } from '@app/ui/dmp/dmp.module'; +import { DatasetDescriptionFormModule } from '@app/ui/misc/dataset-description-form/dataset-description-form.module'; +import { DatasetEditorWizardComponent } from '@app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component'; +import { DmpEditorWizardComponent } from '@app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component'; +import { FunderEditorWizardComponent } from '@app/ui/quick-wizard/funder-editor/funder-editor-wizard.component'; +import { GrantEditorWizardComponent } from '@app/ui/quick-wizard/grant-editor/grant-editor-wizard.component'; +import { ProjectEditorWizardComponent } from '@app/ui/quick-wizard/project-editor/project-editor-wizard.component'; +import { QuickWizardEditorComponent } from '@app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component'; +import { QuickWizardRoutingModule } from '@app/ui/quick-wizard/quick-wizard.routing'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/privacy/privacy.module.ts b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/privacy/privacy.module.ts index 37921fc36..8c303fe91 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/privacy/privacy.module.ts +++ b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/privacy/privacy.module.ts @@ -1,15 +1,15 @@ import { NgModule } from '@angular/core'; -import { PrivacyComponent } from './privacy.component'; -import { PrivacyRoutingModule } from './privacy.routing'; -import { CommonUiModule } from '../../../../common/ui/common-ui.module'; +import { PrivacyComponent } from '@app/ui/sidebar/sidebar-footer/privacy/privacy.component'; +import { PrivacyRoutingModule } from '@app/ui/sidebar/sidebar-footer/privacy/privacy.routing'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ - CommonUiModule, - PrivacyRoutingModule + CommonUiModule, + PrivacyRoutingModule ], declarations: [ - PrivacyComponent + PrivacyComponent ] }) export class PrivacyModule { } diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.ts b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.ts index c03321df9..ac594671b 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.ts +++ b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.ts @@ -1,17 +1,17 @@ import { Component, OnInit } from '@angular/core'; import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; +import { Router } from '@angular/router'; +import { ContactEmailFormModel } from '@app/core/model/contact/contact-email-form-model'; +import { ContactSupportService } from '@app/core/services/contact-support/contact-support.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { ContactDialogComponent } from '@app/ui/contact/contact-dialog/contact-dialog.component'; +import { FaqDialogComponent } from '@app/ui/faq/dialog/faq-dialog.component'; +import { GlossaryDialogComponent } from '@app/ui/glossary/dialog/glossary-dialog.component'; +import { BaseComponent } from '@common/base/base.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; -import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model'; -import { BaseComponent } from '../../../core/common/base/base.component'; -import { ContactEmailFormModel } from '../../../core/model/contact/contact-email-form-model'; -import { ContactSupportService } from '../../../core/services/contact-support/contact-support.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '../../../core/services/notification/ui-notification-service'; -import { GlossaryDialogComponent } from '../../glossary/dialog/glossary-dialog.component'; -import { Router } from '@angular/router'; -import { FaqDialogComponent } from '../../faq/dialog/faq-dialog.component'; -import { ContactDialogComponent } from '../../contact/contact-dialog/contact-dialog.component'; @Component({ selector: 'app-sidebar-footer', diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/terms/terms.module.ts b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/terms/terms.module.ts index d9c62dcc5..86c5c4a3a 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/terms/terms.module.ts +++ b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/terms/terms.module.ts @@ -1,7 +1,7 @@ import { NgModule } from '@angular/core'; -import { TermsComponent } from './terms.component'; -import { TermsRoutingModule } from './terms.routing'; -import { CommonUiModule } from '../../../../common/ui/common-ui.module'; +import { TermsComponent } from '@app/ui/sidebar/sidebar-footer/terms/terms.component'; +import { TermsRoutingModule } from '@app/ui/sidebar/sidebar-footer/terms/terms.routing'; +import { CommonUiModule } from '@common/ui/common-ui.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar.module.ts b/dmp-frontend/src/app/ui/sidebar/sidebar.module.ts index a42c97328..9a05ddb09 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar.module.ts +++ b/dmp-frontend/src/app/ui/sidebar/sidebar.module.ts @@ -1,12 +1,12 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; -import { CommonFormsModule } from '../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; +import { ContactModule } from '../contact/contact.module'; +import { FaqModule } from '../faq/faq.module'; +import { GlossaryModule } from '../glossary/glossary.module'; import { SidebarFooterComponent } from './sidebar-footer/sidebar-footer.component'; import { SidebarComponent } from './sidebar.component'; -import { GlossaryModule } from '../glossary/glossary.module'; -import { FaqModule } from '../faq/faq.module'; -import { ContactModule } from '../contact/contact.module'; @NgModule({ imports: [ diff --git a/dmp-frontend/src/app/ui/user-profile/user-profile.component.ts b/dmp-frontend/src/app/ui/user-profile/user-profile.component.ts index a5e847417..2438df81b 100644 --- a/dmp-frontend/src/app/ui/user-profile/user-profile.component.ts +++ b/dmp-frontend/src/app/ui/user-profile/user-profile.component.ts @@ -1,17 +1,17 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Params, Router } from '@angular/router'; +import { CultureInfo } from '@app/core/model/culture-info'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { UserListingModel } from '@app/core/model/user/user-listing'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { CultureService } from '@app/core/services/culture/culture-service'; +import { UserService } from '@app/core/services/user/user.service'; +import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import * as moment from 'moment-timezone'; import { Observable, of } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import { BaseComponent } from '../../core/common/base/base.component'; -import { CultureInfo } from '../../core/model/culture-info'; -import { DmpModel } from '../../core/model/dmp/dmp'; -import { UserListingModel } from '../../core/model/user/user-listing'; -import { AuthService } from '../../core/services/auth/auth.service'; -import { CultureService } from '../../core/services/culture/culture-service'; -import { UserService } from '../../core/services/user/user.service'; const availableLanguages: any[] = require('../../../assets/resources/language.json'); diff --git a/dmp-frontend/src/app/ui/user-profile/user-profile.module.ts b/dmp-frontend/src/app/ui/user-profile/user-profile.module.ts index be8e300a4..29f166199 100644 --- a/dmp-frontend/src/app/ui/user-profile/user-profile.module.ts +++ b/dmp-frontend/src/app/ui/user-profile/user-profile.module.ts @@ -1,7 +1,7 @@ import { NgModule } from '@angular/core'; -import { CommonFormsModule } from '../../common/forms/common-forms.module'; -import { CommonUiModule } from '../../common/ui/common-ui.module'; -import { FormattingModule } from '../../core/formatting.module'; +import { FormattingModule } from '@app/core/formatting.module'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; import { UserProfileComponent } from './user-profile.component'; import { UserProfileRoutingModule } from './user-profile.routing'; diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index d0c9ba3a8..03a240d41 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -34,6 +34,18 @@ "EDIT": "Edited", "FINALISED": "Finalized" }, + "FORM-VALIDATION-DISPLAY-DIALOG": { + "WARNING": "Warning!", + "THIS-FIELD": "Field", + "HAS-ERROR": "has error", + "REQUIRED": "Required", + "EMAIL": "Invalid e-mail", + "MIN-VALUE": "Minimum value should be {{min}}", + "MAX-VALUE": "Maximum value should be {{max}}", + "ACTIONS": { + "CANCEL": "Close" + } + }, "CONFIRMATION-DIALOG": { "DELETE-ITEM": "Delete this item?", "DELETE-USER": "Remove this collaborator?", @@ -342,7 +354,7 @@ "TITLE": "Grants", "SUBTITLE": "Grant Subtitle", "ACTIONS": { - "NEW":"New Grant" + "NEW": "New Grant" } }, "DMP-LISTING": { @@ -510,7 +522,7 @@ "MAKE-IT-PUBLIC": "Make it public", "VIEW": "View", "NEW": "New Dataset Description", - "CREATE-NEW":"Create new Dataset Description" + "CREATE-NEW": "Create new Dataset Description" }, "TOOLTIP": { "DATASET-STATUS": { @@ -574,8 +586,8 @@ "SELECT": "Select Dataset Description Template" }, "SNACK-BAR": { - "SUCCESSFUL-CREATION" : "Imported Successfully", - "UNSUCCESSFUL" : "Something went wrong" + "SUCCESSFUL-CREATION": "Imported Successfully", + "UNSUCCESSFUL": "Something went wrong" } }, "DMP-PROFILE-EDITOR": { @@ -856,7 +868,7 @@ "DMP-VISIBILITY": { "VISIBILITY": "Visibility", "PUBLIC": "Published", - "FINALIZED": "Finalized" , + "FINALIZED": "Finalized", "DRAFT": "Draft", "ANY": "Any" }, diff --git a/dmp-frontend/src/common/base/base-enum-utils.service.ts b/dmp-frontend/src/common/base/base-enum-utils.service.ts new file mode 100644 index 000000000..0d5654137 --- /dev/null +++ b/dmp-frontend/src/common/base/base-enum-utils.service.ts @@ -0,0 +1,17 @@ +import { BaseService } from '@common/base/base.service'; + +export abstract class BaseEnumUtilsService extends BaseService { + + public getEnumValues(T): Array { + + //getting all numeric values + const numericValues: T[] = Object.keys(T).map(key => T[key]).filter(value => typeof (value) === 'number'); + if (numericValues.length > 0) { return numericValues; } + + //getting all string values + const stringValues: T[] = Object.keys(T).map(key => T[key]).filter(value => typeof (value) === 'string'); + if (stringValues.length > 0) { return stringValues; } + + return []; + } +} diff --git a/dmp-frontend/src/common/base/base-form-editor-model.ts b/dmp-frontend/src/common/base/base-form-editor-model.ts new file mode 100644 index 000000000..4f414abd5 --- /dev/null +++ b/dmp-frontend/src/common/base/base-form-editor-model.ts @@ -0,0 +1,8 @@ +import { FormBuilder } from '@angular/forms'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; + +export abstract class BaseFormEditorModel { + + public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); + protected formBuilder: FormBuilder = new FormBuilder(); +} diff --git a/dmp-frontend/src/common/base/base-form-editor.ts b/dmp-frontend/src/common/base/base-form-editor.ts new file mode 100644 index 000000000..9ef8bbc80 --- /dev/null +++ b/dmp-frontend/src/common/base/base-form-editor.ts @@ -0,0 +1,111 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { FormGroup } from '@angular/forms'; +import { MatDialog } from '@angular/material'; +import { ActivatedRoute, Router } from '@angular/router'; +import { BaseFormEditorModel } from '@common/base/base-form-editor-model'; +import { BasePendingChangesComponent } from '@common/base/base-pending-changes.component'; +import { FormService } from '@common/forms/form-service'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { HttpError, HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@common/modules/notification/ui-notification-service'; +import { Guid } from '@common/types/guid'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +export abstract class BaseFormEditor extends BasePendingChangesComponent { + + isNew = true; + isDeleted = false; + editorModel: EditorModelType; + serverData: FormModel; //To be used only for presentation purposes + formGroup: FormGroup = null; + + abstract deleteItem(id: Guid); + abstract refreshData(): void; + abstract persistForm(onSuccess?: (response) => void): void; + abstract buildForm(): void; + + constructor( + protected dialog: MatDialog, + protected language: TranslateService, + protected formService: FormService, + protected router: Router, + protected route: ActivatedRoute, + protected uiNotificationService: UiNotificationService, + protected httpErrorHandlingService: HttpErrorHandlingService, + ) { super(); } + + public isFormValid() { + return this.formGroup.valid; + } + + public delete() { + const value = this.formGroup.value; + if (value.id) { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + maxWidth: '300px', + data: { + message: this.language.instant('COMMONS.CONFIRMATION-DIALOG.DELETE-ITEM'), + confirmButton: this.language.instant('COMMONS.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'), + cancelButton: this.language.instant('COMMONS.CONFIRMATION-DIALOG.ACTIONS.CANCEL') + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + this.deleteItem(value.id); + } + }); + } + } + + public cancel(): void { + this.router.navigate(['/folders']); + } + + onCallbackSuccess(data?: any): void { + this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); + this.refreshOnNavigateToData(data.id); + } + + onCallbackError(errorResponse: HttpErrorResponse) { + const error: HttpError = this.httpErrorHandlingService.getError(errorResponse); + if (error.statusCode === 400) { + this.editorModel.validationErrorModel.fromJSONObject(errorResponse.error); + this.formService.validateAllFormFields(this.formGroup); + } else { + this.uiNotificationService.snackBarNotification(error.getMessagesString(), SnackBarNotificationLevel.Warning); + } + } + + canDeactivate(): boolean | Observable { + return this.formGroup ? !this.formGroup.dirty : true; + } + + formSubmit(): void { + this.formService.removeAllBackEndErrors(this.formGroup); + this.formService.touchAllFormFields(this.formGroup); + if (!this.isFormValid()) { + return; + } + + this.persistForm(complete => { + this.refreshOnNavigateToData(complete.id); + }); + } + + private refreshOnNavigateToData(id: Guid): void { + if (this.isNew) { + this.formGroup.markAsPristine(); + this.router.navigate(['../' + (id)], { relativeTo: this.route }); + } else { this.internalRefreshData(); } + } + + private internalRefreshData(): void { + setTimeout(() => { + this.formGroup = null; + this.editorModel = null; + }); + this.refreshData(); + } +} diff --git a/dmp-frontend/src/common/base/base-http.service.ts b/dmp-frontend/src/common/base/base-http.service.ts new file mode 100644 index 000000000..7ac3735fe --- /dev/null +++ b/dmp-frontend/src/common/base/base-http.service.ts @@ -0,0 +1,39 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; + +@Injectable() +export class BaseHttpService { + constructor( + protected http: HttpClient + ) { + } + + get(url: string, options?: Object): Observable { + return this.http.get(url, options); + } + + post(url: string, body: any, options?: Object): Observable { + return this.http.post(url, body, options); + } + + put(url: string, body: any, options?: Object): Observable { + return this.http.put(url, body, options); + } + + delete(url: string, options?: Object): Observable { + return this.http.delete(url, options); + } + + patch(url: string, body: any, options?: Object): Observable { + return this.http.patch(url, body, options); + } + + head(url: string, options?: Object): Observable { + return this.http.head(url, options); + } + + options(url: string, options?: Object): Observable { + return this.http.options(url, options); + } +} diff --git a/dmp-frontend/src/common/base/base-pending-changes.component.ts b/dmp-frontend/src/common/base/base-pending-changes.component.ts new file mode 100644 index 000000000..fbf4a98ea --- /dev/null +++ b/dmp-frontend/src/common/base/base-pending-changes.component.ts @@ -0,0 +1,17 @@ +import { HostListener } from '@angular/core'; +import { BaseComponent } from '@common/base/base.component'; +import { Observable } from 'rxjs'; + +export abstract class BasePendingChangesComponent extends BaseComponent { + + protected constructor() { super(); } + + abstract canDeactivate(): boolean | Observable; + + @HostListener('window:beforeunload', ['$event']) + unloadNotification($event: any) { + if (!this.canDeactivate()) { + $event.returnValue = true; + } + } +} diff --git a/dmp-frontend/src/app/core/common/base/base.component.ts b/dmp-frontend/src/common/base/base.component.ts similarity index 100% rename from dmp-frontend/src/app/core/common/base/base.component.ts rename to dmp-frontend/src/common/base/base.component.ts diff --git a/dmp-frontend/src/common/base/base.guard.ts b/dmp-frontend/src/common/base/base.guard.ts new file mode 100644 index 000000000..a4809b6f3 --- /dev/null +++ b/dmp-frontend/src/common/base/base.guard.ts @@ -0,0 +1,14 @@ +import { OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; + +export abstract class BaseGuard implements OnDestroy { + + protected _destroyed: Subject = new Subject(); + + protected constructor() { } + + ngOnDestroy(): void { + this._destroyed.next(true); + this._destroyed.complete(); + } +} diff --git a/dmp-frontend/src/common/base/base.pipe.ts b/dmp-frontend/src/common/base/base.pipe.ts new file mode 100644 index 000000000..a36b43efb --- /dev/null +++ b/dmp-frontend/src/common/base/base.pipe.ts @@ -0,0 +1,14 @@ +import { OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; + +export abstract class BasePipe implements OnDestroy { + + protected _destroyed: Subject = new Subject(); + + protected constructor() { } + + ngOnDestroy(): void { + this._destroyed.next(true); + this._destroyed.complete(); + } +} diff --git a/dmp-frontend/src/app/core/common/base/base.service.ts b/dmp-frontend/src/common/base/base.service.ts similarity index 100% rename from dmp-frontend/src/app/core/common/base/base.service.ts rename to dmp-frontend/src/common/base/base.service.ts diff --git a/dmp-frontend/src/common/base/tenant-configuration-editor.component.ts b/dmp-frontend/src/common/base/tenant-configuration-editor.component.ts new file mode 100644 index 000000000..46c632d1b --- /dev/null +++ b/dmp-frontend/src/common/base/tenant-configuration-editor.component.ts @@ -0,0 +1,20 @@ +import { FormControl } from '@angular/forms'; +import { BaseComponent } from '@common/base/base.component'; + +export abstract class TenantConfigurationBaseComponent extends BaseComponent { + + readonly secretValue: string = '1784E159-C809-4F3F-AC8F-90F98B04B01D'; + shouldShowEditSecret: Map = new Map(); + + protected constructor() { super(); } + + editSecret(formControl: FormControl, formControlName: string) { + this.shouldShowEditSecret.set(formControlName, true); + formControl.setValue(undefined); + } + + cancelEditSecret(formControl: FormControl, formControlName: string) { + this.shouldShowEditSecret.delete(formControlName); + formControl.setValue(this.secretValue); + } +} diff --git a/dmp-frontend/src/app/common/date/moment-utc-date-adapter.ts b/dmp-frontend/src/common/date/moment-utc-date-adapter.ts similarity index 93% rename from dmp-frontend/src/app/common/date/moment-utc-date-adapter.ts rename to dmp-frontend/src/common/date/moment-utc-date-adapter.ts index 659926878..0b3ca383d 100644 --- a/dmp-frontend/src/app/common/date/moment-utc-date-adapter.ts +++ b/dmp-frontend/src/common/date/moment-utc-date-adapter.ts @@ -36,7 +36,8 @@ export class MomentUtcDateAdapter extends MomentDateAdapter { // manually writing on the textbox parse(value: any, parseFormat: string | string[]): Moment | null { const initialParse = super.parse(value, parseFormat); - if (initialParse === null || !initialParse.isValid()) { return initialParse; } + if (initialParse == null) { return null }; + if (!initialParse.isValid()) { return initialParse; } const result = moment.utc({ year: initialParse.year(), month: initialParse.month(), date: initialParse.date() }).locale(this.locale); return result; diff --git a/dmp-frontend/src/app/common/forms/common-forms.module.ts b/dmp-frontend/src/common/forms/common-forms.module.ts similarity index 55% rename from dmp-frontend/src/app/common/forms/common-forms.module.ts rename to dmp-frontend/src/common/forms/common-forms.module.ts index 13f128841..cea6b2aab 100644 --- a/dmp-frontend/src/app/common/forms/common-forms.module.ts +++ b/dmp-frontend/src/common/forms/common-forms.module.ts @@ -1,5 +1,7 @@ import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { PendingChangesGuard } from '@common/forms/pending-form-changes/pending-form-changes-guard.service'; +import { FormService } from './form-service'; @NgModule({ imports: [ @@ -9,6 +11,10 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; exports: [ FormsModule, ReactiveFormsModule, + ], + providers: [ + FormService, + PendingChangesGuard ] }) export class CommonFormsModule { } diff --git a/dmp-frontend/src/common/forms/form-service.ts b/dmp-frontend/src/common/forms/form-service.ts new file mode 100644 index 000000000..3bb75fa85 --- /dev/null +++ b/dmp-frontend/src/common/forms/form-service.ts @@ -0,0 +1,81 @@ +import { Injectable } from '@angular/core'; +import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; + +@Injectable() +export class FormService { + + constructor() { + } + + public validateAllFormFields(formControl: AbstractControl) { + if (formControl instanceof FormControl) { + formControl.updateValueAndValidity({ emitEvent: false }); + } else if (formControl instanceof FormGroup) { + Object.keys(formControl.controls).forEach(item => { + const control = formControl.get(item); + this.validateAllFormFields(control); + }); + } else if (formControl instanceof FormArray) { + formControl.controls.forEach(item => { + this.validateAllFormFields(item); + }); + } + } + + public touchAllFormFields(formControl: AbstractControl) { + if (formControl instanceof FormControl) { + formControl.markAsTouched(); + } else if (formControl instanceof FormGroup) { + Object.keys(formControl.controls).forEach(item => { + const control = formControl.get(item); + this.touchAllFormFields(control); + }); + } else if (formControl instanceof FormArray) { + formControl.controls.forEach(item => { + this.touchAllFormFields(item); + }); + } + } + + public removeAllBackEndErrors(formControl: AbstractControl) { + if (formControl instanceof FormControl) { + this.removeError(formControl, 'backendError'); + } else if (formControl instanceof FormGroup) { + Object.keys(formControl.controls).forEach(item => { + const control = formControl.get(item); + this.removeAllBackEndErrors(control); + }); + } else if (formControl instanceof FormArray) { + formControl.controls.forEach(item => { + this.removeAllBackEndErrors(item); + }); + } + } + + public removeError(control: FormControl, error: string) { + const err = control.errors; + if (err && err[error]) { + delete err[error]; + if (!Object.keys(err).length) { + control.setErrors(null); // Make control Valid again + } else { + control.setErrors(err); // if there are others errors left attach them back to the control + } + } + } + + public getValue(control: AbstractControl) { + return JSON.parse(JSON.stringify(control.value)); //Used to deep copy formGroup. + } + + // TODO + // public reapplyValidators(array: FormArray, validationContext: ValidationContext) { + // if (!Array.isArray(array.controls)) { return; } + // array.controls.forEach((element, index) => { + // const formGroup = element as FormGroup; + // Object.keys(formGroup.controls).forEach(key => { + // formGroup.get(key).setValidators(validationContext.getValidation(key).validators); + // }); + // }); + // } +} diff --git a/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.html b/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.html new file mode 100644 index 000000000..1126efc31 --- /dev/null +++ b/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.html @@ -0,0 +1,11 @@ +
+

{{'GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.WARNING' | translate}}

+
+
    +
  • {{error}}
  • +
+
+
+ +
+
diff --git a/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.scss b/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.scss new file mode 100644 index 000000000..66c7f2cf2 --- /dev/null +++ b/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.scss @@ -0,0 +1,5 @@ +#warningText { + color: red; + text-decoration: underline; + text-decoration-color: red; +} \ No newline at end of file diff --git a/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.ts b/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.ts new file mode 100644 index 000000000..2e2b31be6 --- /dev/null +++ b/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.ts @@ -0,0 +1,78 @@ +import { Component, Inject } from '@angular/core'; +import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { TranslateService } from '@ngx-translate/core'; + +@Component({ + selector: 'app-form-validation-errors-dialog', + templateUrl: './form-validation-errors-dialog.component.html', + styleUrls: ['./form-validation-errors-dialog.component.scss'] +}) +export class FormValidationErrorsDialogComponent { + + formGroup: FormGroup; + errorMessages: string[] = []; + + constructor(public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any, + private language: TranslateService + ) { + this.formGroup = data.formGroup; + this.errorMessages = this.getErrors(this.formGroup); + } + + onClose(): void { + this.dialogRef.close(); + } + + public getErrors(formControl: AbstractControl): string[] { + const errors: string[] = []; + if (formControl instanceof FormControl) { + if (formControl.invalid && formControl['nativeElement']) { errors.push(...this.getErrorMessage(formControl)); } + } else if (formControl instanceof FormGroup) { + if (formControl.errors) { (errors.push(...Object.values(formControl.errors).map(x => x.message) as string[])); } + Object.keys(formControl.controls).forEach(item => { + const control = formControl.get(item); + errors.push(...this.getErrors(control)); + }); + } else if (formControl instanceof FormArray) { + if (formControl.errors) { (errors.push(...Object.values(formControl.errors).map(x => x.message) as string[])); } + formControl.controls.forEach(item => { + errors.push(...this.getErrors(item)); + }); + } + return errors; + } + + getErrorMessage(formControl: FormControl): string[] { + const errors: string[] = []; + Object.keys(formControl.errors).forEach(key => { + 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') + ' "' + this.getPlaceHolder(formControl) + '" ' + 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') + ' "' + this.getPlaceHolder(formControl) + '" ' + 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') + ' "' + this.getPlaceHolder(formControl) + '" ' + 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') + ' "' + this.getPlaceHolder(formControl) + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + formControl.errors[key].message); } + }); + return errors; + } + + getPlaceHolder(formControl: any): string { + // if (formControl.nativeElement.localName === 'input') { + // return formControl.nativeElement.getAttribute('placeholder'); + // } else if (formControl.nativeElement.localName === 'mat-select') { + // return formControl.nativeElement.getAttribute('aria-label'); + // } 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.children).filter((x: any) => x.localName === 'input')[0] as any).getAttribute('placeholder'); + // } + + let result = ''; + try { + result = (Array.from(formControl.nativeElement.parentElement.children).filter((x: any) => Array.from(x.classList).includes('mat-form-field-label-wrapper'))[0] as any).innerText; + result = result.replace(' *', ''); + } catch (error) { } + + return result; + } +} diff --git a/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.module.ts b/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.module.ts new file mode 100644 index 000000000..fad8c4028 --- /dev/null +++ b/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.module.ts @@ -0,0 +1,25 @@ +import { NgModule } from '@angular/core'; +import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component'; +import { FormValidationErrorsDirective } from '@common/forms/form-validation-errors-dialog/form-validation-errors-directive'; +import { CommonUiModule } from '@common/ui/common-ui.module'; + +@NgModule({ + imports: [ + CommonUiModule, + ], + exports: [ + FormValidationErrorsDialogComponent, + FormValidationErrorsDirective + ], + declarations: [ + FormValidationErrorsDialogComponent, + FormValidationErrorsDirective + ], + entryComponents: [ + FormValidationErrorsDialogComponent + ], + providers: [ + FormValidationErrorsDirective + ] +}) +export class FormValidationErrorsDialogModule { } diff --git a/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-directive.ts b/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-directive.ts new file mode 100644 index 000000000..60724499a --- /dev/null +++ b/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-directive.ts @@ -0,0 +1,20 @@ +import { Directive, ElementRef, OnInit } from '@angular/core'; +import { NgControl } from '@angular/forms'; + +@Directive({ + selector: '[formControl], [formControlName]' +}) +export class FormValidationErrorsDirective implements OnInit { + get control() { + return this.controlDir.control; + } + + constructor( + private controlDir: NgControl, + private host: ElementRef) { + } + + ngOnInit() { + (this.controlDir.control as any).nativeElement = this.host.nativeElement; + } +} diff --git a/dmp-frontend/src/common/forms/pending-form-changes/pending-form-changes-guard.service.ts b/dmp-frontend/src/common/forms/pending-form-changes/pending-form-changes-guard.service.ts new file mode 100644 index 000000000..c8a5166d9 --- /dev/null +++ b/dmp-frontend/src/common/forms/pending-form-changes/pending-form-changes-guard.service.ts @@ -0,0 +1,34 @@ +import { Injectable } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { CanDeactivate } from '@angular/router'; +import { BasePendingChangesComponent } from '@common/base/base-pending-changes.component'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { TranslateService } from '@ngx-translate/core'; +import { from, Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +@Injectable() +export class PendingChangesGuard implements CanDeactivate { + + constructor( + private dialog: MatDialog, + private language: TranslateService + ) { + } + + canDeactivate(component: BasePendingChangesComponent): boolean | Observable { + if (component.canDeactivate()) { + return from([true]); + } else { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + maxWidth: '300px', + data: { + message: this.language.instant('COMMONS.PENDING-FORM-CHANGES-DIALOG.MESSAGE'), + cancelButton: this.language.instant('COMMONS.PENDING-FORM-CHANGES-DIALOG.ACTIONS.NO'), + confirmButton: this.language.instant('COMMONS.PENDING-FORM-CHANGES-DIALOG.ACTIONS.YES') + } + }); + return dialogRef.afterClosed().pipe(map(x => x ? true : false)); + } + } +} diff --git a/dmp-frontend/src/common/forms/validation/custom-validator.ts b/dmp-frontend/src/common/forms/validation/custom-validator.ts new file mode 100644 index 000000000..9854d1d4d --- /dev/null +++ b/dmp-frontend/src/common/forms/validation/custom-validator.ts @@ -0,0 +1,100 @@ +import { AbstractControl, ValidatorFn, Validators } from '@angular/forms'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { isNullOrUndefined } from 'util'; + +export function BackendErrorValidator(errorModel: ValidationErrorModel, propertyName: string): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } => { + const error: string = errorModel.getError(propertyName); + return error ? { 'backendError': { message: error } } : null; + }; +} + +export function E164PhoneValidator(): ValidatorFn { + return Validators.pattern('^\\+?[1-9]\\d{1,14}$'); +} + +// Getter is required because the index of each element is not fixed (array does not always follow LIFO) +export function BackendArrayErrorValidator(errorModel: ValidationErrorModel, propertyNameGetter: () => string): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } => { + const error: string = errorModel.getError(propertyNameGetter()); + return error ? { 'backendError': { message: error } } : null; + }; +} + +export function CustomErrorValidator(errorModel: ValidationErrorModel, propertyNames: string[]): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } => { + const error: string = errorModel.getErrors(propertyNames); + return error ? { 'customError': { message: error } } : null; + }; +} + +export function DateValidator(): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } => { + if (control.value) { + const dateString: string[] = control.value.split('-'); + const yearString = dateString.length > 0 ? dateString[0].replace(/_/g, '') : null; + const monthString = dateString.length > 1 ? dateString[1].replace(/_/g, '') : null; + const dayString = dateString.length > 2 ? dateString[2].replace(/_/g, '') : null; + let yearParsed: number = null; + let monthParsed: number = null; + let dayParsed: number = null; + + if (!isNullOrUndefined(yearString) && yearString.length === 4 && Number(yearString) !== NaN) { + yearParsed = Number(yearString); + } + if (!isNullOrUndefined(monthString) && monthString.length > 0 && Number(monthString) !== NaN) { + monthParsed = Number(monthString); + } + if (!isNullOrUndefined(dayString) && dayString.length > 0 && Number(dayString) !== NaN) { + dayParsed = Number(dayString); + } + + if ((dayParsed && (!monthParsed || !yearParsed)) || (monthParsed && !yearParsed) || !yearParsed) { + return { 'invalidDate': true }; + } + + const current_date = new Date(); + yearParsed = yearParsed ? yearParsed : current_date.getFullYear(); + monthParsed = monthParsed ? monthParsed - 1 : current_date.getMonth(); + dayParsed = dayParsed ? dayParsed : 1; + + //due to autocorrection of Date objects + const d = new Date(yearParsed, monthParsed, dayParsed); + if (d.getFullYear() === yearParsed && d.getMonth() === monthParsed && d.getDate() === dayParsed) { + return null; + } + return { 'invalidDate': true }; + } + return null; + }; +} + +export function DateFromToValidator(): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } => { + if (control.get('fromTime').value && control.get('toTime').value) { + const fromDate = new Date(control.get('fromTime').value); + const toDate = new Date(control.get('toTime').value); + if (fromDate <= toDate) { return null; } + return { 'invalidFromToDate': true }; + } + return null; + }; +} + +export function EmailMatchValidator(): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } => { + return control.get('email').value === control.get('emailConfirm').value ? null : { 'emailMismatch': true }; + }; +} + +export function PasswordMatchValidator(passwordControlName: string, repeatPasswordControlName: string): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } => { + const passwordControl = control.get(passwordControlName); + const passwordRepeatControl = control.get(repeatPasswordControlName); + + if (passwordControl && passwordControl.value && passwordRepeatControl && passwordRepeatControl.value && passwordControl.value !== passwordRepeatControl.value) { + return { 'passwordMismatch': true }; + } + return null; + }; +} diff --git a/dmp-frontend/src/app/common/forms/validation/error-model/validation-error-model.ts b/dmp-frontend/src/common/forms/validation/error-model/validation-error-model.ts similarity index 97% rename from dmp-frontend/src/app/common/forms/validation/error-model/validation-error-model.ts rename to dmp-frontend/src/common/forms/validation/error-model/validation-error-model.ts index 21eec2772..86dca530e 100644 --- a/dmp-frontend/src/app/common/forms/validation/error-model/validation-error-model.ts +++ b/dmp-frontend/src/common/forms/validation/error-model/validation-error-model.ts @@ -1,4 +1,4 @@ -import { Serializable } from '../../../types/json/serializable'; +import { Serializable } from '@common/types/json/serializable'; export class ValidationErrorModel implements Serializable { public error: string; diff --git a/dmp-frontend/src/app/common/forms/validation/validation-context.ts b/dmp-frontend/src/common/forms/validation/validation-context.ts similarity index 100% rename from dmp-frontend/src/app/common/forms/validation/validation-context.ts rename to dmp-frontend/src/common/forms/validation/validation-context.ts diff --git a/dmp-frontend/src/app/common/http/base-http-params.ts b/dmp-frontend/src/common/http/base-http-params.ts similarity index 100% rename from dmp-frontend/src/app/common/http/base-http-params.ts rename to dmp-frontend/src/common/http/base-http-params.ts diff --git a/dmp-frontend/src/app/common/http/common-http.module.ts b/dmp-frontend/src/common/http/common-http.module.ts similarity index 100% rename from dmp-frontend/src/app/common/http/common-http.module.ts rename to dmp-frontend/src/common/http/common-http.module.ts diff --git a/dmp-frontend/src/common/http/image/secure-image.pipe.ts b/dmp-frontend/src/common/http/image/secure-image.pipe.ts new file mode 100644 index 000000000..61052fdc7 --- /dev/null +++ b/dmp-frontend/src/common/http/image/secure-image.pipe.ts @@ -0,0 +1,16 @@ +import { HttpClient } from '@angular/common/http'; +import { Pipe, PipeTransform } from '@angular/core'; +import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; +import { BasePipe } from '@common/base/base.pipe'; +import { Observable } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; + +@Pipe({ name: 'secureImage' }) +export class SecureImagePipe extends BasePipe implements PipeTransform { + + constructor(private http: HttpClient, private sanitizer: DomSanitizer) { super(); } + + transform(url): Observable { + return this.http.get(url, { responseType: 'blob' }).pipe(takeUntil(this._destroyed), map(val => this.sanitizer.bypassSecurityTrustUrl(URL.createObjectURL(val)))); + } +} diff --git a/dmp-frontend/src/app/common/http/interceptor-context.ts b/dmp-frontend/src/common/http/interceptor-context.ts similarity index 100% rename from dmp-frontend/src/app/common/http/interceptor-context.ts rename to dmp-frontend/src/common/http/interceptor-context.ts diff --git a/dmp-frontend/src/app/common/http/interceptors/auth-token.interceptor.ts b/dmp-frontend/src/common/http/interceptors/auth-token.interceptor.ts similarity index 91% rename from dmp-frontend/src/app/common/http/interceptors/auth-token.interceptor.ts rename to dmp-frontend/src/common/http/interceptors/auth-token.interceptor.ts index 3f37fd4ba..41b5443b9 100644 --- a/dmp-frontend/src/app/common/http/interceptors/auth-token.interceptor.ts +++ b/dmp-frontend/src/common/http/interceptors/auth-token.interceptor.ts @@ -3,7 +3,7 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { BaseInterceptor } from './base.interceptor'; import { InterceptorType } from './interceptor-type'; -import { AuthService } from '../../../core/services/auth/auth.service'; +import { AuthService } from '../../../app/core/services/auth/auth.service'; @Injectable() export class AuthTokenInterceptor extends BaseInterceptor { diff --git a/dmp-frontend/src/app/common/http/interceptors/base.interceptor.ts b/dmp-frontend/src/common/http/interceptors/base.interceptor.ts similarity index 94% rename from dmp-frontend/src/app/common/http/interceptors/base.interceptor.ts rename to dmp-frontend/src/common/http/interceptors/base.interceptor.ts index 7918c5f0a..13374a21f 100644 --- a/dmp-frontend/src/app/common/http/interceptors/base.interceptor.ts +++ b/dmp-frontend/src/common/http/interceptors/base.interceptor.ts @@ -2,7 +2,7 @@ import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/c import { Observable } from 'rxjs'; import { BaseHttpParams } from '../base-http-params'; import { InterceptorType } from './interceptor-type'; -import { environment } from '../../../../environments/environment'; +import { environment } from '../../../environments/environment'; export abstract class BaseInterceptor implements HttpInterceptor { diff --git a/dmp-frontend/src/app/common/http/interceptors/interceptor-type.ts b/dmp-frontend/src/common/http/interceptors/interceptor-type.ts similarity index 100% rename from dmp-frontend/src/app/common/http/interceptors/interceptor-type.ts rename to dmp-frontend/src/common/http/interceptors/interceptor-type.ts diff --git a/dmp-frontend/src/app/common/http/interceptors/json.interceptor.ts b/dmp-frontend/src/common/http/interceptors/json.interceptor.ts similarity index 100% rename from dmp-frontend/src/app/common/http/interceptors/json.interceptor.ts rename to dmp-frontend/src/common/http/interceptors/json.interceptor.ts diff --git a/dmp-frontend/src/app/common/http/interceptors/locale.interceptor.ts b/dmp-frontend/src/common/http/interceptors/locale.interceptor.ts similarity index 100% rename from dmp-frontend/src/app/common/http/interceptors/locale.interceptor.ts rename to dmp-frontend/src/common/http/interceptors/locale.interceptor.ts diff --git a/dmp-frontend/src/app/common/http/interceptors/progress-indication.interceptor.ts b/dmp-frontend/src/common/http/interceptors/progress-indication.interceptor.ts similarity index 87% rename from dmp-frontend/src/app/common/http/interceptors/progress-indication.interceptor.ts rename to dmp-frontend/src/common/http/interceptors/progress-indication.interceptor.ts index c472b1e12..939d25f41 100644 --- a/dmp-frontend/src/app/common/http/interceptors/progress-indication.interceptor.ts +++ b/dmp-frontend/src/common/http/interceptors/progress-indication.interceptor.ts @@ -2,7 +2,7 @@ import { HttpEvent, HttpHandler, HttpRequest } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { finalize } from 'rxjs/operators'; -import { ProgressIndicationService } from '../../../core/services/progress-indication/progress-indication-service'; +import { ProgressIndicationService } from '../../../app/core/services/progress-indication/progress-indication-service'; import { BaseInterceptor } from './base.interceptor'; import { InterceptorType } from './interceptor-type'; diff --git a/dmp-frontend/src/app/common/http/interceptors/request-timing.interceptor.ts b/dmp-frontend/src/common/http/interceptors/request-timing.interceptor.ts similarity index 92% rename from dmp-frontend/src/app/common/http/interceptors/request-timing.interceptor.ts rename to dmp-frontend/src/common/http/interceptors/request-timing.interceptor.ts index 869674c69..295701614 100644 --- a/dmp-frontend/src/app/common/http/interceptors/request-timing.interceptor.ts +++ b/dmp-frontend/src/common/http/interceptors/request-timing.interceptor.ts @@ -2,7 +2,7 @@ import { HttpEvent, HttpHandler, HttpRequest, HttpResponse } from '@angular/comm import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; -import { LoggingService } from '../../../core/services/logging/logging-service'; +import { LoggingService } from '../../../app/core/services/logging/logging-service'; import { BaseInterceptor } from './base.interceptor'; import { InterceptorType } from './interceptor-type'; diff --git a/dmp-frontend/src/app/common/http/interceptors/response-payload.interceptor.ts b/dmp-frontend/src/common/http/interceptors/response-payload.interceptor.ts similarity index 100% rename from dmp-frontend/src/app/common/http/interceptors/response-payload.interceptor.ts rename to dmp-frontend/src/common/http/interceptors/response-payload.interceptor.ts diff --git a/dmp-frontend/src/app/common/http/interceptors/status-code.interceptor.ts b/dmp-frontend/src/common/http/interceptors/status-code.interceptor.ts similarity index 100% rename from dmp-frontend/src/app/common/http/interceptors/status-code.interceptor.ts rename to dmp-frontend/src/common/http/interceptors/status-code.interceptor.ts diff --git a/dmp-frontend/src/app/common/http/interceptors/unauthorized-response.interceptor.ts b/dmp-frontend/src/common/http/interceptors/unauthorized-response.interceptor.ts similarity index 97% rename from dmp-frontend/src/app/common/http/interceptors/unauthorized-response.interceptor.ts rename to dmp-frontend/src/common/http/interceptors/unauthorized-response.interceptor.ts index 2417f00dd..542df6dac 100644 --- a/dmp-frontend/src/app/common/http/interceptors/unauthorized-response.interceptor.ts +++ b/dmp-frontend/src/common/http/interceptors/unauthorized-response.interceptor.ts @@ -3,7 +3,7 @@ import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { Observable, throwError } from 'rxjs'; import { catchError, mergeMap, tap } from 'rxjs/operators'; -import { AuthService } from '../../../core/services/auth/auth.service'; +import { AuthService } from '../../../app/core/services/auth/auth.service'; import { BaseInterceptor } from './base.interceptor'; import { InterceptorType } from './interceptor-type'; diff --git a/dmp-frontend/src/app/common/material/material.module.ts b/dmp-frontend/src/common/material/material.module.ts similarity index 100% rename from dmp-frontend/src/app/common/material/material.module.ts rename to dmp-frontend/src/common/material/material.module.ts diff --git a/dmp-frontend/src/app/library/confirmation-dialog/confirmation-dialog.component.html b/dmp-frontend/src/common/modules/confirmation-dialog/confirmation-dialog.component.html similarity index 100% rename from dmp-frontend/src/app/library/confirmation-dialog/confirmation-dialog.component.html rename to dmp-frontend/src/common/modules/confirmation-dialog/confirmation-dialog.component.html diff --git a/dmp-frontend/src/common/modules/confirmation-dialog/confirmation-dialog.component.scss b/dmp-frontend/src/common/modules/confirmation-dialog/confirmation-dialog.component.scss new file mode 100644 index 000000000..a0856d4a9 --- /dev/null +++ b/dmp-frontend/src/common/modules/confirmation-dialog/confirmation-dialog.component.scss @@ -0,0 +1,45 @@ +.confirmation-dialog { + .confirmation { + padding-bottom: 20px; + } + + .privacy-policy-names { + font-weight: 700; + padding: 1em; + } + + .close-btn { + margin-left: auto; + cursor: pointer; + } + + .warn-text { + color: #f44336; + } + + .cancel { + background-color: #aaaaaa; + color: #ffffff; + } + + .confirm { + background-color: #2cba6c; + color: #ffffff; + } + + .delete { + background-color: #ba2c2c; + color: #ffffff; + } + + .checkbox-privacy { + padding: 0em 1em; + } + + .required-policy { + padding: 0em 1.2em 1em; + font-size: smaller; + color: #f44336; + } + } + \ No newline at end of file diff --git a/dmp-frontend/src/app/library/confirmation-dialog/confirmation-dialog.component.ts b/dmp-frontend/src/common/modules/confirmation-dialog/confirmation-dialog.component.ts similarity index 100% rename from dmp-frontend/src/app/library/confirmation-dialog/confirmation-dialog.component.ts rename to dmp-frontend/src/common/modules/confirmation-dialog/confirmation-dialog.component.ts diff --git a/dmp-frontend/src/common/modules/confirmation-dialog/confirmation-dialog.module.ts b/dmp-frontend/src/common/modules/confirmation-dialog/confirmation-dialog.module.ts new file mode 100644 index 000000000..124fea2f1 --- /dev/null +++ b/dmp-frontend/src/common/modules/confirmation-dialog/confirmation-dialog.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { CommonUiModule } from '@common/ui/common-ui.module'; + +@NgModule({ + imports: [CommonUiModule, FormsModule], + declarations: [ConfirmationDialogComponent], + exports: [ConfirmationDialogComponent], + entryComponents: [ConfirmationDialogComponent] +}) +export class ConfirmationDialogModule { + constructor() { } +} diff --git a/dmp-frontend/src/common/modules/errors/error-handling/http-error-handling.service.ts b/dmp-frontend/src/common/modules/errors/error-handling/http-error-handling.service.ts new file mode 100644 index 000000000..754a6a8c9 --- /dev/null +++ b/dmp-frontend/src/common/modules/errors/error-handling/http-error-handling.service.ts @@ -0,0 +1,67 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; + +@Injectable() +export class HttpErrorHandlingService { + constructor( + protected language: TranslateService + ) { + } + + getError(errorResponse: HttpErrorResponse): HttpError { + const error: HttpError = new HttpError(); + error.statusCode = errorResponse.status; + error.messages = this.parseMessages(error.statusCode, errorResponse); + + // if (error && error.error && error.error.error) { + // errorMsg = error.error.error; + // // } else if (error && error.message) { + // // errorMsg = error.message; + // // } else if (error) { + // // errorMsg = error; + // } else { + // errorMsg = language.instant('COMMONS.ERRORS.DEFAULT'); + // } + return error; + } + + private parseMessages(httpStatusCode: number, errorPayload: any): string[] { + const result: string[] = []; + switch (httpStatusCode) { + case 400: // Bad Request, Used for validation errors. + if (errorPayload && errorPayload.error && errorPayload.error.error_description) { result.push(errorPayload.error.error_description); } + else if (errorPayload && errorPayload.error && errorPayload.error.error) { result.push(errorPayload.error.error); } + else if (errorPayload && errorPayload.message) { result.push(errorPayload.message); } + break; + case 404: // Not Found + if (errorPayload && errorPayload.error && errorPayload.error.error_description) { result.push(errorPayload.error.error_description); } + else if (errorPayload && errorPayload.error && errorPayload.error.error) { result.push(errorPayload.error.error); } + else if (errorPayload && errorPayload.message) { result.push(errorPayload.message); } + break; + case 500: // Bad Request, Used for validation errors. + if (errorPayload && errorPayload.error && errorPayload.error.error_description) { result.push(errorPayload.error.error_description); } + else if (errorPayload && errorPayload.error && errorPayload.error.error) { result.push(errorPayload.error.error); } + else if (errorPayload && errorPayload.message) { result.push(errorPayload.message); } + break; + default: + if (errorPayload && errorPayload.error && errorPayload.error.error_description) { result.push(errorPayload.error.error_description); } + else if (errorPayload && errorPayload.error && errorPayload.error.error) { result.push(errorPayload.error.error); } + else if (errorPayload && errorPayload.message) { result.push(errorPayload.message); } + break; + } + + if (result.length === 0) { result.push(this.language.instant('COMMONS.ERRORS.DEFAULT')); } + + return result; + } +} + +export class HttpError { + statusCode: number; + messages: string[]; + + getMessagesString(): string { + return this.messages ? this.messages.join(', ') : null; + } +} diff --git a/dmp-frontend/src/common/modules/errors/errors-component/errors.component.html b/dmp-frontend/src/common/modules/errors/errors-component/errors.component.html new file mode 100644 index 000000000..02396e756 --- /dev/null +++ b/dmp-frontend/src/common/modules/errors/errors-component/errors.component.html @@ -0,0 +1,34 @@ +
+
+
+
+

ERROR {{ data?.error}}

+
Not found :(
+ +
Go Home
+
+
+ +
+ +

ERROR {{ routeParams?.status }}


+

{{ routeParams?.message }}


+

Error in {{ routeParams?.url }} page, sorry :(

+

This error has been reported to the Administrator with the ID:
{{ routeParams?.id}}

+ +
Go Back to {{routeParams?.url}}
+
+ +
Go Back to home
+
+
+ +
+

Unknown error, sorry :(

+ +
Go Home
+
+
+
+
+
diff --git a/dmp-frontend/src/common/modules/errors/errors-component/errors.component.scss b/dmp-frontend/src/common/modules/errors/errors-component/errors.component.scss new file mode 100644 index 000000000..b4f6062e5 --- /dev/null +++ b/dmp-frontend/src/common/modules/errors/errors-component/errors.component.scss @@ -0,0 +1,14 @@ +h1, +h3, +h4, +h5 { + margin-bottom: 0; + margin-top: 10px; +} + +.error-container { + margin-top: auto; + margin-bottom: auto; + text-align: center; + overflow-wrap: break-word; +} diff --git a/dmp-frontend/src/common/modules/errors/errors-component/errors.component.ts b/dmp-frontend/src/common/modules/errors/errors-component/errors.component.ts new file mode 100644 index 000000000..7b6fc0155 --- /dev/null +++ b/dmp-frontend/src/common/modules/errors/errors-component/errors.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +@Component({ + selector: 'app-error', + templateUrl: './errors.component.html', + styleUrls: ['./errors.component.scss'] +}) +export class ErrorsComponent implements OnInit { + routeParams; + data; + + constructor( + private activatedRoute: ActivatedRoute, + ) { } + + ngOnInit() { + this.routeParams = this.activatedRoute.snapshot.queryParams; + this.data = this.activatedRoute.snapshot.data; + } +} diff --git a/dmp-frontend/src/common/modules/errors/errors-handler/errors-handler.ts b/dmp-frontend/src/common/modules/errors/errors-handler/errors-handler.ts new file mode 100644 index 000000000..77b954a4f --- /dev/null +++ b/dmp-frontend/src/common/modules/errors/errors-handler/errors-handler.ts @@ -0,0 +1,51 @@ + +import { HttpErrorResponse } from '@angular/common/http'; +import { ErrorHandler, Injectable, Injector } from '@angular/core'; +import { Router } from '@angular/router'; +import { SnackBarNotificationLevel, UiNotificationService } from '@common/modules/notification/ui-notification-service'; +import { TranslateService } from '@ngx-translate/core'; + +@Injectable() +export class ErrorsHandler implements ErrorHandler { + + private _notificationService; + // private _errorService; + private _router; + private _language; + + constructor( + private injector: Injector, + ) { + + } + + handleError(error: Error | HttpErrorResponse) { + this._notificationService = this.injector.get(UiNotificationService); + // this._errorService = this.injector.get(ErrorService); + this._router = this.injector.get(Router); + this._language = this.injector.get(TranslateService); + + if (error instanceof HttpErrorResponse) { + // Server error happened + if (!navigator.onLine) { + // No Internet connection + return this._notificationService.snackBarNotification(this._language.instant('ERROR-HANDLER.GLOBAL.NO-INTERNET'), SnackBarNotificationLevel.Error); + } + // Http Error + // Send the error to the server + // this._errorService.log(error).subscribe(); + // Show notification to the user + return this._notificationService.snackBarNotification(`${error.status} - ${error.message}`, SnackBarNotificationLevel.Error); + } else { + // Client Error Happend + // Send the error to the server and then + // redirect the user to the page with all the info + // this._errorService + // .log(error) + // .subscribe(errorWithContextInfo => { + // this._router.navigate(['/error'], { queryParams: errorWithContextInfo }); + // }); + } + } +} + diff --git a/dmp-frontend/src/common/modules/errors/errors-routing/errors-routing.module.ts b/dmp-frontend/src/common/modules/errors/errors-routing/errors-routing.module.ts new file mode 100644 index 000000000..c95dd35c7 --- /dev/null +++ b/dmp-frontend/src/common/modules/errors/errors-routing/errors-routing.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { ErrorsComponent } from '@common/modules/errors/errors-component/errors.component'; + +const routes: Routes = [ + { path: 'error', component: ErrorsComponent }, + { path: '**', loadChildren: () => import('@common/modules/page-not-found/page-not-found.module').then(m => m.PageNotFoundModule) }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class ErrorRoutingModule { } diff --git a/dmp-frontend/src/common/modules/errors/errors.module.ts b/dmp-frontend/src/common/modules/errors/errors.module.ts new file mode 100644 index 000000000..d630e7a17 --- /dev/null +++ b/dmp-frontend/src/common/modules/errors/errors.module.ts @@ -0,0 +1,34 @@ +import { CommonModule } from '@angular/common'; +import { HTTP_INTERCEPTORS } from '@angular/common/http'; +import { ErrorHandler, NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +// import { ExternalTracingService } from '@app/core/services/http/external-tracing.service'; +import { ErrorsComponent } from '@common/modules/errors/errors-component/errors.component'; +import { ErrorsHandler } from '@common/modules/errors/errors-handler/errors-handler'; +import { ErrorRoutingModule } from '@common/modules/errors/errors-routing/errors-routing.module'; +import { ServerErrorsInterceptor } from '@common/modules/errors/server-errors-interceptor/server-errors.interceptor'; + +@NgModule({ + imports: [ + CommonModule, + RouterModule, + ErrorRoutingModule, + ], + declarations: [ + ErrorsComponent + ], + providers: [ + // ErrorService, + // ExternalTracingService, + { + provide: ErrorHandler, + useClass: ErrorsHandler, + }, + { + provide: HTTP_INTERCEPTORS, + useClass: ServerErrorsInterceptor, + multi: true + }, + ] +}) +export class ErrorsModule { } diff --git a/dmp-frontend/src/common/modules/errors/external-tracing/external-trace-entry.ts b/dmp-frontend/src/common/modules/errors/external-tracing/external-trace-entry.ts new file mode 100644 index 000000000..8af4afb37 --- /dev/null +++ b/dmp-frontend/src/common/modules/errors/external-tracing/external-trace-entry.ts @@ -0,0 +1,20 @@ +export interface ExternalTraceEntry { + eventId: EventId; + level: ExternalTraceLogLevel; + message: string; + data: any; +} + +export interface EventId { + id: number; +} + +export enum ExternalTraceLogLevel { + Trace = 0, + Debug = 1, + Information = 2, + Warning = 3, + Error = 4, + Critical = 5, + None = 6 +} diff --git a/dmp-frontend/src/common/modules/errors/server-errors-interceptor/server-errors.interceptor.ts b/dmp-frontend/src/common/modules/errors/server-errors-interceptor/server-errors.interceptor.ts new file mode 100644 index 000000000..c652d028e --- /dev/null +++ b/dmp-frontend/src/common/modules/errors/server-errors-interceptor/server-errors.interceptor.ts @@ -0,0 +1,13 @@ +import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { retry } from 'rxjs/operators'; + +@Injectable() +export class ServerErrorsInterceptor implements HttpInterceptor { + constructor() { } + intercept(request: HttpRequest, next: HttpHandler): Observable> { + + return next.handle(request); //TODO: possibly we want to retry here using: .pipe(retry(5)); + } +} diff --git a/dmp-frontend/src/common/modules/notification/popup/popup-notification.component.html b/dmp-frontend/src/common/modules/notification/popup/popup-notification.component.html new file mode 100644 index 000000000..a06d796e6 --- /dev/null +++ b/dmp-frontend/src/common/modules/notification/popup/popup-notification.component.html @@ -0,0 +1,5 @@ +

{{notification.title}}

+{{notification.message}} + + + diff --git a/dmp-frontend/src/common/modules/notification/popup/popup-notification.component.ts b/dmp-frontend/src/common/modules/notification/popup/popup-notification.component.ts new file mode 100644 index 000000000..04622b096 --- /dev/null +++ b/dmp-frontend/src/common/modules/notification/popup/popup-notification.component.ts @@ -0,0 +1,16 @@ +import { Component, Inject } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { PopupNotification } from '@common/modules/notification/ui-notification-service'; + +@Component({ + selector: 'app-popup-notification-dialog', + templateUrl: './popup-notification.component.html' +}) +export class PopupNotificationDialogComponent { + + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public notification: PopupNotification + ) { + } +} diff --git a/dmp-frontend/src/common/modules/notification/snack-bar/snack-bar-notification.component.html b/dmp-frontend/src/common/modules/notification/snack-bar/snack-bar-notification.component.html new file mode 100644 index 000000000..75af56131 --- /dev/null +++ b/dmp-frontend/src/common/modules/notification/snack-bar/snack-bar-notification.component.html @@ -0,0 +1 @@ +{{message}} diff --git a/dmp-frontend/src/common/modules/notification/snack-bar/snack-bar-notification.component.ts b/dmp-frontend/src/common/modules/notification/snack-bar/snack-bar-notification.component.ts new file mode 100644 index 000000000..55db60951 --- /dev/null +++ b/dmp-frontend/src/common/modules/notification/snack-bar/snack-bar-notification.component.ts @@ -0,0 +1,15 @@ +import { Component, Inject } from '@angular/core'; +import { MAT_SNACK_BAR_DATA } from '@angular/material/snack-bar'; +import { SnackBarNotification } from '@common/modules/notification/ui-notification-service'; + +@Component({ + selector: 'app-snack-bar-notification', + templateUrl: './snack-bar-notification.component.html' +}) + +export class SnackBarNotificationComponent { + message: string; + constructor(@Inject(MAT_SNACK_BAR_DATA) public data: SnackBarNotification) { + this.message = data.message; + } +} diff --git a/dmp-frontend/src/common/modules/notification/ui-notification-service.ts b/dmp-frontend/src/common/modules/notification/ui-notification-service.ts new file mode 100644 index 000000000..3219daa45 --- /dev/null +++ b/dmp-frontend/src/common/modules/notification/ui-notification-service.ts @@ -0,0 +1,60 @@ +import { Injectable } from '@angular/core'; +import { Observable, Subject } from 'rxjs'; + +@Injectable() +export class UiNotificationService { + + private notificationSubject = new Subject(); + + constructor() { + } + + public snackBarNotification(message: string, level: SnackBarNotificationLevel, duration: number = 5000) { + const notification: SnackBarNotification = new SnackBarNotification(); + notification.level = level; + notification.message = message; + notification.duration = duration; + this.notificationSubject.next(notification); + } + + public popupNotification(title: string, message: string) { + const notification: PopupNotification = new PopupNotification(); + notification.title = title; + notification.message = message; + this.notificationSubject.next(notification); + } + + public getNotificationObservable(): Observable { + return this.notificationSubject.asObservable(); + } +} + +export enum UiNotificationType { + SnackBar = 0, + Popup = 1 +} + +export interface UiNotification { + type: UiNotificationType; + +} + +export enum SnackBarNotificationLevel { + Info = 0, + Warning = 1, + Success = 2, + Error = 3 +} + +export class SnackBarNotification implements UiNotification { + type: UiNotificationType = UiNotificationType.SnackBar; + message: string; + level: SnackBarNotificationLevel; + duration: number; +} + +export class PopupNotification implements UiNotification { + type: UiNotificationType = UiNotificationType.Popup; + message: string; + title: string; +} diff --git a/dmp-frontend/src/common/modules/notification/ui-notification.component.html b/dmp-frontend/src/common/modules/notification/ui-notification.component.html new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/dmp-frontend/src/common/modules/notification/ui-notification.component.html @@ -0,0 +1 @@ + diff --git a/dmp-frontend/src/common/modules/notification/ui-notification.component.scss b/dmp-frontend/src/common/modules/notification/ui-notification.component.scss new file mode 100644 index 000000000..1203c5d5a --- /dev/null +++ b/dmp-frontend/src/common/modules/notification/ui-notification.component.scss @@ -0,0 +1,15 @@ +.snack-bar-notification--success { + background-color: #4CAF50 !important; +} + +.snack-bar-notification--error { + background-color: #B13636 !important; +} + +.snack-bar-notification--warning { + background-color: #B13636 !important; +} + +.snack-bar-notification--info { + background-color: #B13636 !important; +} diff --git a/dmp-frontend/src/common/modules/notification/ui-notification.component.ts b/dmp-frontend/src/common/modules/notification/ui-notification.component.ts new file mode 100644 index 000000000..f4bf6ee0a --- /dev/null +++ b/dmp-frontend/src/common/modules/notification/ui-notification.component.ts @@ -0,0 +1,55 @@ +import { Component, OnInit } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { BaseComponent } from '@common/base/base.component'; +import { PopupNotificationDialogComponent } from '@common/modules/notification/popup/popup-notification.component'; +import { SnackBarNotificationComponent } from '@common/modules/notification/snack-bar/snack-bar-notification.component'; +import { PopupNotification, SnackBarNotification, SnackBarNotificationLevel, UiNotificationService, UiNotificationType } from '@common/modules/notification/ui-notification-service'; +import { takeUntil } from 'rxjs/operators'; + +@Component({ + selector: 'app-ui-notification', + templateUrl: './ui-notification.component.html', + styleUrls: ['./ui-notification.component.scss'] +}) +export class UiNotificationComponent extends BaseComponent implements OnInit { + + constructor( + private snackBar: MatSnackBar, + public dialog: MatDialog, + private uiNotificationService: UiNotificationService + ) { + super(); + } + + ngOnInit() { + this.uiNotificationService.getNotificationObservable().pipe(takeUntil(this._destroyed)).subscribe(notification => { + switch (notification.type) { + case UiNotificationType.SnackBar: + const snackBarNotification: SnackBarNotification = notification as SnackBarNotification; + this.snackBar.openFromComponent(SnackBarNotificationComponent, { + data: snackBarNotification, + duration: snackBarNotification.duration, + panelClass: [this.getSnackBarLevelClass(snackBarNotification.level)] + }); + break; + case UiNotificationType.Popup: + const popupNotification: PopupNotification = notification as PopupNotification; + this.dialog.open(PopupNotificationDialogComponent, { + data: popupNotification + }); + break; + } + }); + } + + private getSnackBarLevelClass(level: SnackBarNotificationLevel): string { + switch (level) { + case SnackBarNotificationLevel.Warning: return 'snack-bar-notification--warning'; + case SnackBarNotificationLevel.Error: return 'snack-bar-notification--error'; + case SnackBarNotificationLevel.Success: return 'snack-bar-notification--success'; + default: return 'snack-bar-notification--info'; + } + + } +} diff --git a/dmp-frontend/src/common/modules/notification/ui-notification.module.ts b/dmp-frontend/src/common/modules/notification/ui-notification.module.ts new file mode 100644 index 000000000..3e57b18bc --- /dev/null +++ b/dmp-frontend/src/common/modules/notification/ui-notification.module.ts @@ -0,0 +1,26 @@ +import { NgModule } from '@angular/core'; +import { PopupNotificationDialogComponent } from '@common/modules/notification/popup/popup-notification.component'; +import { SnackBarNotificationComponent } from '@common/modules/notification/snack-bar/snack-bar-notification.component'; +import { UiNotificationComponent } from '@common/modules/notification/ui-notification.component'; +import { CommonUiModule } from '@common/ui/common-ui.module'; + +@NgModule({ + imports: [ + CommonUiModule + ], + declarations: [ + UiNotificationComponent, + SnackBarNotificationComponent, + PopupNotificationDialogComponent, + ], + exports: [ + UiNotificationComponent + ], + entryComponents: [ + SnackBarNotificationComponent, + PopupNotificationDialogComponent, + ] +}) +export class UiNotificationModule { + constructor() { } +} diff --git a/dmp-frontend/src/common/modules/page-not-found/page-not-found.component.html b/dmp-frontend/src/common/modules/page-not-found/page-not-found.component.html new file mode 100644 index 000000000..5727cb897 --- /dev/null +++ b/dmp-frontend/src/common/modules/page-not-found/page-not-found.component.html @@ -0,0 +1 @@ +

Page not found

diff --git a/dmp-frontend/src/common/modules/page-not-found/page-not-found.component.ts b/dmp-frontend/src/common/modules/page-not-found/page-not-found.component.ts new file mode 100644 index 000000000..ea7c6f5f9 --- /dev/null +++ b/dmp-frontend/src/common/modules/page-not-found/page-not-found.component.ts @@ -0,0 +1,13 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + templateUrl: './page-not-found.component.html' +}) +export class PageNotFoundComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/dmp-frontend/src/common/modules/page-not-found/page-not-found.module.ts b/dmp-frontend/src/common/modules/page-not-found/page-not-found.module.ts new file mode 100644 index 000000000..0a362cb9b --- /dev/null +++ b/dmp-frontend/src/common/modules/page-not-found/page-not-found.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { PageNotFoundComponent } from '@common/modules/page-not-found/page-not-found.component'; + +@NgModule({ + imports: [ + ], + declarations: [ + PageNotFoundComponent + ], + entryComponents: [] +}) +export class PageNotFoundModule { } diff --git a/dmp-frontend/src/app/common/types/guid.ts b/dmp-frontend/src/common/types/guid.ts similarity index 100% rename from dmp-frontend/src/app/common/types/guid.ts rename to dmp-frontend/src/common/types/guid.ts diff --git a/dmp-frontend/src/app/common/types/json/json-serializer.ts b/dmp-frontend/src/common/types/json/json-serializer.ts similarity index 82% rename from dmp-frontend/src/app/common/types/json/json-serializer.ts rename to dmp-frontend/src/common/types/json/json-serializer.ts index 775a9c2de..96d4ef8ed 100644 --- a/dmp-frontend/src/app/common/types/json/json-serializer.ts +++ b/dmp-frontend/src/common/types/json/json-serializer.ts @@ -1,4 +1,4 @@ -import { Serializable } from './serializable'; +import { Serializable } from '@common/types/json/serializable'; export class JsonSerializer> { constructor(private constructorOfT: { new(): T }) { diff --git a/dmp-frontend/src/app/common/types/json/serializable.ts b/dmp-frontend/src/common/types/json/serializable.ts similarity index 100% rename from dmp-frontend/src/app/common/types/json/serializable.ts rename to dmp-frontend/src/common/types/json/serializable.ts diff --git a/dmp-frontend/src/app/common/types/pair.ts b/dmp-frontend/src/common/types/pair.ts similarity index 100% rename from dmp-frontend/src/app/common/types/pair.ts rename to dmp-frontend/src/common/types/pair.ts diff --git a/dmp-frontend/src/app/common/ui/common-ui.module.ts b/dmp-frontend/src/common/ui/common-ui.module.ts similarity index 62% rename from dmp-frontend/src/app/common/ui/common-ui.module.ts rename to dmp-frontend/src/common/ui/common-ui.module.ts index fe8455d39..5c16efc7b 100644 --- a/dmp-frontend/src/app/common/ui/common-ui.module.ts +++ b/dmp-frontend/src/common/ui/common-ui.module.ts @@ -1,21 +1,23 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { SecureImagePipe } from '@common/http/image/secure-image.pipe'; +import { MaterialModule } from '@common/material/material.module'; import { TranslateModule } from '@ngx-translate/core'; -import { MaterialModule } from '../material/material.module'; -import { FormsModule } from '@angular/forms'; @NgModule({ imports: [ CommonModule, MaterialModule, TranslateModule, - FormsModule + ], + declarations: [ + SecureImagePipe ], exports: [ CommonModule, MaterialModule, TranslateModule, - FormsModule + SecureImagePipe ] }) export class CommonUiModule { } diff --git a/dmp-frontend/tsconfig.json b/dmp-frontend/tsconfig.json index bfd2e9604..5d5ba689a 100644 --- a/dmp-frontend/tsconfig.json +++ b/dmp-frontend/tsconfig.json @@ -1,15 +1,30 @@ { + "compileOnSave": false, "compilerOptions": { - "downlevelIteration": true, - "importHelpers": true, - "target": "es2015", + "baseUrl": "./src", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, "module": "esnext", "moduleResolution": "node", - "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "lib": ["es2017", "dom"], - "noImplicitAny": false, - "suppressImplicitAnyIndexErrors": true + "importHelpers": true, + "target": "es2015", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2018", + "dom" + ], + "paths": { + "@app/*": [ + "./app/*" + ], + "@common/*": [ + "./common/*" + ] + } } -} +} \ No newline at end of file From 7c2a3b298db23d32502aebf6d63a6060980e2410 Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Wed, 11 Dec 2019 16:51:18 +0200 Subject: [PATCH 009/106] minor fix --- .../app/ui/dataset/dataset-wizard/dataset-wizard.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts index dd9bed9a2..7b28adb42 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts @@ -89,8 +89,8 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr initialItems: (extraData) => this.searchDmp(''), displayFn: (item) => this.getDatasetDisplay(item), titleFn: (item) => item['label'], - iconFn: (item) => this.publicMode ? '' : (item['status'] ? 'lock' : 'lock_open'), - linkFn: (item) => this.publicMode ? '/explore-plans/overview/' + item['id'] : '/plans/overview/' + item['id'] + // iconFn: (item) => this.publicMode ? '' : (item['status'] ? 'lock' : 'lock_open'), + // linkFn: (item) => this.publicMode ? '/explore-plans/overview/' + item['id'] : '/plans/overview/' + item['id'] }; const params = this.route.snapshot.params; From e85c0cc68f7be22938edfe989d36861157ddede7 Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Thu, 12 Dec 2019 11:26:19 +0200 Subject: [PATCH 010/106] minor fixes --- .../eudat/logic/proxy/fetching/RemoteFetcher.java | 7 ++++--- .../src/app/ui/dashboard/dashboard.component.ts | 2 +- .../src/app/ui/dashboard/drafts/drafts.component.ts | 1 + .../ui/dataset/listing/dataset-listing.component.ts | 3 ++- .../editor/general-tab/general-tab.component.html | 4 ++-- .../dmp/editor/general-tab/general-tab.component.ts | 13 +++++++++---- .../src/app/ui/dmp/listing/dmp-listing.component.ts | 3 ++- 7 files changed, 21 insertions(+), 12 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java index f3a416982..ed92795dd 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java @@ -120,11 +120,12 @@ public class RemoteFetcher { private List> getAll(List urlConfigs, FetchStrategy fetchStrategy, ExternalUrlCriteria externalUrlCriteria) throws NoURLFound, HugeResultSet { - if (urlConfigs == null || urlConfigs.isEmpty()) - throw new NoURLFound("No Repository urls found in configuration"); + List> results = new LinkedList<>(); + + if (urlConfigs == null || urlConfigs.isEmpty()) return results; +// throw new NoURLFound("No Repository urls found in configuration"); urlConfigs.sort(Comparator.comparing(UrlConfiguration::getOrdinal)); - List> results = new LinkedList<>(); for (UrlConfiguration urlConfig : urlConfigs) { ifFunderQueryExist(urlConfig, externalUrlCriteria); if (urlConfig.getType() == null || urlConfig.getType().equals("External")) { diff --git a/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts b/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts index 7eafd961e..8649de976 100644 --- a/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts @@ -156,7 +156,7 @@ export class DashboardComponent extends BaseComponent implements OnInit, IBreadC getPublicDatasets() { const dmpCriteria = new ExploreDatasetCriteriaModel(); const fields: Array = new Array(); - fields.push('asc'); + fields.push('-modified'); const dataTableRequest: DataTableRequest = new DataTableRequest(0, 4, { fields: fields }); dataTableRequest.criteria = dmpCriteria; return this.datasetService.getPublicPaged(dataTableRequest).pipe(takeUntil(this._destroyed)).subscribe(result => { this.datasetListingItems = result.data; }); diff --git a/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts b/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts index b2fc93e2d..1d18f127a 100644 --- a/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts @@ -27,6 +27,7 @@ export class DraftsComponent implements OnInit { ngOnInit() { const fields: Array = []; + fields.push('-modified'); const dmpDataTableRequest: DataTableRequest = new DataTableRequest(0, 2, { fields: fields }); dmpDataTableRequest.criteria = new DatasetCriteria(); dmpDataTableRequest.criteria.status = DmpStatus.Draft; diff --git a/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts b/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts index c843dfe12..8a06012ab 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts +++ b/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts @@ -94,7 +94,8 @@ export class DatasetListingComponent extends BaseComponent implements OnInit, IB if (resetPages) this._paginator.pageIndex = 0; const startIndex = this._paginator.pageIndex * this._paginator.pageSize; let fields: Array = new Array(); - if (this.sort && this.sort.active) { fields = this.sort.direction === 'asc' ? ['+' + this.sort.active] : ['-' + this.sort.active]; } + fields.push('-modified'); + //if (this.sort && this.sort.active) { fields = this.sort.direction === 'asc' ? ['+' + this.sort.active] : ['-' + this.sort.active]; } const request = new DataTableRequest(startIndex, this._paginator.pageSize, { fields: fields }); let value = this.criteria.formGroup.value; request.criteria = { diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html index 9131651d7..2683c7562 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html @@ -31,7 +31,7 @@ {{formGroup.get('profiles').getError('backendError').message}} {{'GENERAL.VALIDATION.REQUIRED' | translate}} - @@ -56,7 +56,7 @@ {{formGroup.get('researchers').getError('backendError').message}} {{'GENERAL.VALIDATION.REQUIRED' | translate}} - diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts index 99f8a01b9..1990eb528 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts @@ -142,25 +142,30 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { return this._service.searchDMPProfiles(request); } - addResearcher() { + 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; - this.formGroup.get('researchers').value.push({ + const newItem = { label: null, name: fullName, id: "dmp:" + fullName, status: 0, tag: "Internal", - }); + }; + const researchersArray = this.formGroup.get('researchers').value || []; + researchersArray.push(newItem); + this.formGroup.get('researchers').setValue(researchersArray); } }); } - availableProfiles() { + availableProfiles(event: MouseEvent) { + event.stopPropagation(); const dialogRef = this.dialog.open(AvailableProfilesComponent, { data: { profiles: this.formGroup.get('profiles') diff --git a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts index b4bcedc2b..4e05f29a7 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts @@ -108,7 +108,8 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread if (resetPages) this._paginator.pageIndex = 0; const startIndex = this._paginator.pageIndex * this._paginator.pageSize; let fields: Array = new Array(); - if (this.sort && this.sort.active) { fields = this.sort.direction === 'asc' ? ['+' + this.sort.active] : ['-' + this.sort.active]; } + // if (this.sort && this.sort.active) { fields = this.sort.direction === 'asc' ? ['+' + this.sort.active] : ['-' + this.sort.active]; } + fields.push('-modified'); const request = new DataTableRequest(startIndex, this._paginator.pageSize, { fields: fields }); let value = this.criteria.formGroup.value; request.criteria = { From d1d0cbd93132b1c7322a40c97f4b5bdc937d11fc Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Thu, 12 Dec 2019 12:04:29 +0200 Subject: [PATCH 011/106] autocomplete fix --- .../multiple/multiple-auto-complete.component.html | 6 +++--- .../single/single-auto-complete.component.html | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html index add09a812..6bcc888aa 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html @@ -1,5 +1,5 @@
- + @@ -12,7 +12,7 @@ - + keyboard_arrow_down @@ -54,4 +54,4 @@ -
\ No newline at end of file + diff --git a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.html b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.html index 2fd06b044..dd7f7a9a9 100644 --- a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.html +++ b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.html @@ -1,5 +1,5 @@
- + keyboard_arrow_down From 01d6782ec70f61c9cbcb85d56b96345d0da8cf74 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 12 Dec 2019 12:27:47 +0200 Subject: [PATCH 012/106] Refactors how reference is created on Funder, Grant and Projcect now using their unique id as a part of it instead of label. --- .../java/eu/eudat/data/entities/Funder.java | 4 +-- .../java/eu/eudat/data/entities/Grant.java | 4 +-- .../java/eu/eudat/data/entities/Project.java | 4 +-- .../dmp/DataManagementPlanEditorModel.java | 9 ++++--- .../DataManagementPlanNewVersionModel.java | 27 ++++++++++--------- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/entities/Funder.java b/dmp-backend/data/src/main/java/eu/eudat/data/entities/Funder.java index c1a3bb087..d57e91136 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/entities/Funder.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/entities/Funder.java @@ -66,8 +66,8 @@ public class Funder implements DataEntity { } @Id - @GeneratedValue - @GenericGenerator(name = "uuid2", strategy = "uuid2") + //@GeneratedValue + //@GenericGenerator(name = "uuid2", strategy = "uuid2") @Column(name = "\"ID\"", updatable = false, nullable = false, columnDefinition = "BINARY(16)") private UUID id; diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/entities/Grant.java b/dmp-backend/data/src/main/java/eu/eudat/data/entities/Grant.java index a7dbfc926..9809f0953 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/entities/Grant.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/entities/Grant.java @@ -81,8 +81,8 @@ public class Grant implements DataEntity { } @Id - @GeneratedValue - @GenericGenerator(name = "uuid2", strategy = "uuid2") + //@GeneratedValue + //@GenericGenerator(name = "uuid2", strategy = "uuid2") @Column(name = "\"ID\"", updatable = false, nullable = false, columnDefinition = "BINARY(16)") private UUID id; diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/entities/Project.java b/dmp-backend/data/src/main/java/eu/eudat/data/entities/Project.java index 44a5c8804..04c9d662c 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/entities/Project.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/entities/Project.java @@ -67,8 +67,8 @@ public class Project implements DataEntity { } @Id - @GeneratedValue - @GenericGenerator(name = "uuid2", strategy = "uuid2") + //@GeneratedValue + //@GenericGenerator(name = "uuid2", strategy = "uuid2") @Column(name = "\"ID\"", updatable = false, nullable = false, columnDefinition = "BINARY(16)") private UUID id; diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/DataManagementPlanEditorModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/DataManagementPlanEditorModel.java index 8a9d283e9..a59d9d437 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/DataManagementPlanEditorModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/DataManagementPlanEditorModel.java @@ -278,10 +278,11 @@ public class DataManagementPlanEditorModel implements DataModel Date: Thu, 12 Dec 2019 12:42:00 +0200 Subject: [PATCH 013/106] autocomplete style changes --- .../multiple/multiple-auto-complete.component.html | 2 +- .../multiple/multiple-auto-complete.component.scss | 5 ++++- .../auto-complete/single/single-auto-complete.component.html | 2 +- .../auto-complete/single/single-auto-complete.component.scss | 3 +++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html index 6bcc888aa..ff3b11105 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html @@ -13,7 +13,7 @@ - keyboard_arrow_down + arrow_drop_down diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss index cdaa669c8..139b132c6 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss @@ -6,11 +6,14 @@ display: none; } - + .align-arrow-right { position: absolute; right: 0; vertical-align: middle; + cursor: pointer; + align-self: center; + color: rgba(0, 0, 0, 0.54); } } diff --git a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.html b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.html index dd7f7a9a9..5ca49de77 100644 --- a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.html +++ b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.html @@ -1,6 +1,6 @@
- keyboard_arrow_down + arrow_drop_down diff --git a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss index 401a5e99e..7216861d0 100644 --- a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss +++ b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss @@ -29,6 +29,9 @@ position: absolute; right: 0; vertical-align: middle; + cursor: pointer; + align-self: center; + color: rgba(0, 0, 0, 0.54); } } From 7d6790b22503167bede6fbcf2b4962efca38d91c Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 12 Dec 2019 13:04:00 +0200 Subject: [PATCH 014/106] Fixes bug missing Project id on default creating Project entity on DMP. --- .../java/eu/eudat/logic/managers/DataManagementPlanManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index 49d0816f2..678b10a26 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -724,6 +724,7 @@ public class DataManagementPlanManager { if (projectEntity != null) project.setId(projectEntity.getId()); else { project.setType(Project.ProjectType.EXTERNAL.getValue()); + if (project.getId() == null) project.setId(UUID.randomUUID()); projectDao.createOrUpdate(project); } } From 9dbf57be0390a7dfa893b473575d607e7f0b9e02 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 12 Dec 2019 14:02:52 +0200 Subject: [PATCH 015/106] Fixes bug at DMP Wizard on creating new Grant, Funder and Project. --- .../controllers/QuickWizardController.java | 20 ++++++++++-------- .../logic/managers/QuickWizardManager.java | 2 ++ .../eu/eudat/models/data/funder/Funder.java | 18 ++++++++++------ .../eu/eudat/models/data/grant/Grant.java | 17 +++++++++------ .../eu/eudat/models/data/project/Project.java | 18 ++++++++++------ .../quickwizard/FunderQuickWizardModel.java | 5 ++++- .../quickwizard/GrantQuickWizardModel.java | 21 +++++++++++-------- .../quickwizard/ProjectQuickWizardModel.java | 5 ++++- 8 files changed, 68 insertions(+), 38 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/QuickWizardController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/QuickWizardController.java index adedfcb4f..727d4f0bf 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/QuickWizardController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/QuickWizardController.java @@ -3,11 +3,13 @@ package eu.eudat.controllers; import eu.eudat.data.entities.Funder; import eu.eudat.data.entities.Project; -import eu.eudat.logic.managers.*; +import eu.eudat.logic.managers.DatasetManager; +import eu.eudat.logic.managers.QuickWizardManager; import eu.eudat.logic.services.ApiContext; import eu.eudat.models.data.datasetwizard.DatasetWizardModel; import eu.eudat.models.data.dmp.DataManagementPlan; import eu.eudat.models.data.helpers.responses.ResponseItem; +import eu.eudat.models.data.quickwizard.DatasetCreateWizardModel; import eu.eudat.models.data.quickwizard.DatasetDescriptionQuickWizardModel; import eu.eudat.models.data.quickwizard.QuickWizardModel; import eu.eudat.models.data.security.Principal; @@ -16,7 +18,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import eu.eudat.models.data.quickwizard.DatasetCreateWizardModel; import javax.transaction.Transactional; import javax.validation.Valid; @@ -47,7 +48,6 @@ public class QuickWizardController extends BaseController { if (quickWizard.getFunder() == null) { throw new Exception("Funder is a mandatory entity"); } else if (quickWizard.getFunder().getExistFunder() == null && quickWizard.getFunder().getLabel() == null) { - // funderEntity = null; throw new Exception("Funder is a mandatory entity"); } else if (quickWizard.getFunder().getExistFunder() == null && quickWizard.getFunder().getLabel() != null) { funderEntity = this.quickWizardManager.createOrUpdate(quickWizard.getFunder().toDataFunder(), principal); @@ -57,7 +57,11 @@ public class QuickWizardController extends BaseController { eu.eudat.data.entities.Grant grantEntity; //Create Grant - if (quickWizard.getGrant().getExistGrant() == null) { + if (quickWizard.getGrant() == null) { + throw new Exception("Grant is a mandatory entity"); + } else if (quickWizard.getGrant().getExistGrant() == null && quickWizard.getGrant().getLabel() == null) { + throw new Exception("Grant is a mandatory entity"); + } else if (quickWizard.getGrant().getExistGrant() == null) { grantEntity = this.quickWizardManager.createOrUpdate(quickWizard.getGrant().toDataGrant(), principal); } else { grantEntity = quickWizard.getGrant().getExistGrant().toDataModel(); @@ -68,17 +72,15 @@ public class QuickWizardController extends BaseController { if (quickWizard.getProject().getExistProject() == null && quickWizard.getProject().getLabel() == null) { projectEntity = null; - } else if (quickWizard.getProject().getExistProject() == null && quickWizard.getProject().getLabel() != null){ + } else if (quickWizard.getProject().getExistProject() == null && quickWizard.getProject().getLabel() != null) { projectEntity = this.quickWizardManager.createOrUpdate(quickWizard.getProject().toDataProject(), principal); } else { projectEntity = quickWizard.getProject().getExistProject().toDataModel(); } //Create Dmp - eu.eudat.data.entities.DMP dmpEntity = this.quickWizardManager.createOrUpdate( - quickWizard.getDmp().toDataDmp(grantEntity, projectEntity, principal), - funderEntity, - principal); + DataManagementPlan dataManagementPlan = quickWizard.getDmp().toDataDmp(grantEntity, projectEntity, principal); + eu.eudat.data.entities.DMP dmpEntity = this.quickWizardManager.createOrUpdate(dataManagementPlan, funderEntity, principal); //Create Datasets quickWizard.getDmp().setId(dmpEntity.getId()); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/QuickWizardManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/QuickWizardManager.java index b0a424c3f..d75c07603 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/QuickWizardManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/QuickWizardManager.java @@ -13,6 +13,7 @@ import org.springframework.stereotype.Component; import java.io.IOException; import java.text.ParseException; +import java.util.UUID; @Component public class QuickWizardManager { @@ -109,6 +110,7 @@ public class QuickWizardManager { eu.eudat.data.entities.Project projectEntity = databaseRepository.getProjectDao().getWithCritetia(criteria).getSingleOrDefault(); if (projectEntity != null) project.setId(projectEntity.getId()); else { + if (project.getId() == null) project.setId(UUID.randomUUID()); project.setType(Project.ProjectType.EXTERNAL.getValue()); databaseRepository.getProjectDao().createOrUpdate(project); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/funder/Funder.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/funder/Funder.java index 22fe5d6d6..1fdfcd5c5 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/funder/Funder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/funder/Funder.java @@ -90,22 +90,28 @@ public class Funder implements DataModel this.status = entity.getStatus(); this.created = entity.getCreated(); this.modified = entity.getModified(); - String source = entity.getReference().substring(0, entity.getReference().indexOf(":")); - if (source.equals("dmp")) { - this.source = "Internal"; - } else { - this.source = source; + if (entity.getReference() != null) { + String source = entity.getReference().substring(0, entity.getReference().indexOf(":")); + if (source.equals("dmp")) { + this.source = "Internal"; + } else { + this.source = source; + } } + return this; } @Override public eu.eudat.data.entities.Funder toDataModel() { eu.eudat.data.entities.Funder entity = new eu.eudat.data.entities.Funder(); - entity.setId(this.id); + entity.setId(UUID.randomUUID()); entity.setLabel(this.label); entity.setType(this.type); if (this.source != null && this.source.equals("Internal")) this.source = "dmp"; + if (this.source == null && this.reference != null && this.reference.startsWith("dmp:")) { + entity.setReference(this.reference); + } if (this.reference != null && !this.reference.trim().isEmpty() && this.source != null && !this.source.trim().isEmpty()) { if (this.source.equals(this.reference.substring(0, this.source.length()))) { diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/grant/Grant.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/grant/Grant.java index 56884fe73..7d42a3964 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/grant/Grant.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/grant/Grant.java @@ -177,11 +177,13 @@ public class Grant implements DataModel { this.files = entity.getContent() != null ? Arrays.asList(new ContentFile(entity.getContent().getLabel(), UUID.fromString(entity.getContent().getUri().split(":")[1]), "final", entity.getContent().getExtension())) : Arrays.asList(new ContentFile("default.png", null, null, null)); if (entity.getFunder() != null) this.funderId = entity.getFunder().getId(); - String source = entity.getReference().substring(0, entity.getReference().indexOf(":")); - if (source.equals("dmp")) { - this.source = "Internal"; - } else { - this.source = source; + if (entity.getReference() != null) { + String source = entity.getReference().substring(0, entity.getReference().indexOf(":")); + if (source.equals("dmp")) { + this.source = "Internal"; + } else { + this.source = source; + } } return this; @@ -190,11 +192,14 @@ public class Grant implements DataModel { @Override public eu.eudat.data.entities.Grant toDataModel() { eu.eudat.data.entities.Grant entity = new eu.eudat.data.entities.Grant(); - entity.setId(this.id); + entity.setId(UUID.randomUUID()); entity.setAbbreviation(this.abbreviation); entity.setLabel(this.label); entity.setType(this.type); if (this.source != null && this.source.equals("Internal")) this.source = "dmp"; + if (this.source == null && this.reference != null && this.reference.startsWith("dmp:")) { + entity.setReference(this.reference); + } if (this.reference != null && !this.reference.trim().isEmpty() && this.source != null && !this.source.trim().isEmpty()) { if (this.source.equals(this.reference.substring(0, this.source.length()))) { diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/project/Project.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/project/Project.java index 8752e0bd6..45be84962 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/project/Project.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/project/Project.java @@ -165,23 +165,29 @@ public class Project implements DataModel Date: Thu, 12 Dec 2019 16:12:46 +0200 Subject: [PATCH 016/106] autocomplete fixes --- .../multiple/multiple-auto-complete.component.scss | 2 +- .../auto-complete/single/single-auto-complete.component.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss index 139b132c6..a539b8f19 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss @@ -19,6 +19,6 @@ } .two-line-mat-option { - height: 3.5em; + // height: 3.5em; line-height: 1.2em; } diff --git a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss index 7216861d0..096e3640c 100644 --- a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss +++ b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss @@ -40,7 +40,7 @@ } .two-line-mat-option { - height: 3.5em; + // height: 3.5em; line-height: 1.2em; } From 3327131ad8612bc9f546d5313ff2c2d08b66bb19 Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Thu, 12 Dec 2019 16:54:26 +0200 Subject: [PATCH 017/106] autocomplete style fix --- .../multiple/multiple-auto-complete.component.scss | 1 - .../single/single-auto-complete.component.scss | 1 - .../listing/criteria/dataset-criteria.component.html | 6 ------ .../app/ui/dmp/listing/criteria/dmp-criteria.component.html | 4 ---- .../filters/explore-dataset-filters.component.html | 4 ---- .../dmp-explore-filters/explore-dmp-filters.component.html | 3 --- 6 files changed, 19 deletions(-) diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss index a539b8f19..a2ff47c86 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss @@ -19,6 +19,5 @@ } .two-line-mat-option { - // height: 3.5em; line-height: 1.2em; } diff --git a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss index 096e3640c..d87344f60 100644 --- a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss +++ b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.scss @@ -40,7 +40,6 @@ } .two-line-mat-option { - // height: 3.5em; line-height: 1.2em; } diff --git a/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.html b/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.html index 878a4b1d6..674efe80e 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.html +++ b/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.html @@ -31,7 +31,6 @@ placeholder="{{'CRITERIA.DATA-SETS.SELECT-DATASET-TEMPLATES' | translate }}" [configuration]="datasetTemplateAutoCompleteConfiguration"> - arrow_drop_down
@@ -44,7 +43,6 @@ placeholder="{{'CRITERIA.DATA-SETS.SELECT-DMP' | translate }}" [configuration]="dmpAutoCompleteConfiguration"> - arrow_drop_down
@@ -57,7 +55,6 @@ placeholder="{{'CRITERIA.DATA-SETS.SELECT-GRANTS' | translate }}" [configuration]="grantAutoCompleteConfiguration"> - arrow_drop_down @@ -70,7 +67,6 @@ placeholder="{{'CRITERIA.DATA-SETS.SELECT-COLLABORATORS' | translate }}" [configuration]="collaboratorsAutoCompleteConfiguration"> - arrow_drop_down @@ -94,7 +90,6 @@ placeholder="{{'CRITERIA.DATA-SETS.SELECT-ORGANIZATIONS' | translate}}" [configuration]="organisationAutoCompleteConfiguration"> - arrow_drop_down @@ -107,7 +102,6 @@ placeholder="{{'CRITERIA.DATA-SETS.SELECT-TAGS' | translate}}" [configuration]="tagsAutoCompleteConfiguration"> - arrow_drop_down diff --git a/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.html b/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.html index f0f777463..b1af0d9aa 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.html +++ b/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.html @@ -32,7 +32,6 @@ placeholder="{{ 'CRITERIA.DMP.SELECT-DATASET-TEMPLATES' | translate }}" [configuration]="datasetTemplateAutoCompleteConfiguration"> - arrow_drop_down @@ -45,7 +44,6 @@ placeholder="{{ 'CRITERIA.DMP.SELECT-GRANTS' | translate }}" [configuration]="grantAutoCompleteConfiguration"> - arrow_drop_down @@ -58,7 +56,6 @@ placeholder="{{'CRITERIA.DMP.SELECT-COLLABORATORS' | translate}}" [configuration]="collaboratorsAutoCompleteConfiguration"> - arrow_drop_down @@ -82,7 +79,6 @@ placeholder="{{'DMP-RELATED-ORGANIZATION.SELECT-ORGANIZATIONS' | translate}}" [configuration]="organisationAutoCompleteConfiguration"> - arrow_drop_down diff --git a/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.html b/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.html index 3684f2955..01769decb 100644 --- a/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.html +++ b/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.html @@ -23,7 +23,6 @@ - arrow_drop_down @@ -32,7 +31,6 @@ - arrow_drop_down @@ -41,7 +39,6 @@ - arrow_drop_down @@ -59,7 +56,6 @@ - arrow_drop_down diff --git a/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component.html b/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component.html index 9ae8fe5d3..d7a2e6ce6 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component.html +++ b/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component.html @@ -27,7 +27,6 @@ - arrow_drop_down @@ -36,7 +35,6 @@ - arrow_drop_down @@ -60,7 +58,6 @@ - arrow_drop_down From a80a935ff3b9491dc1da12e1b3bbc2e78a73f901 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 12 Dec 2019 18:29:56 +0200 Subject: [PATCH 018/106] Fixes bug on not fetching internal saved Grants. --- .../java/eu/eudat/data/dao/entities/GrantDaoImpl.java | 2 +- .../main/java/eu/eudat/logic/managers/GrantManager.java | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/GrantDaoImpl.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/GrantDaoImpl.java index bb91b39ad..04e14d3b8 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/GrantDaoImpl.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/GrantDaoImpl.java @@ -53,7 +53,7 @@ public class GrantDaoImpl extends DatabaseAccess implements GrantDao { if (criteria.getFunderId() != null && !criteria.getFunderId().trim().isEmpty()) query.where((builder, root) -> builder.equal(root.get("funder").get("id"), UUID.fromString(criteria.getFunderId()))); if (criteria.getFunderReference() != null && !criteria.getFunderReference().isEmpty()) - query.where((builder, root) -> builder.equal(root.join("funder", JoinType.LEFT).get("reference"), criteria.getFunderReference())); + query.where((builder, root) -> builder.or(builder.like(root.join("funder", JoinType.LEFT).get("reference"), "%" + criteria.getFunderReference()))); query.where((builder, root) -> builder.notEqual(root.get("status"), Grant.Status.DELETED.getValue())); return query; } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/GrantManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/GrantManager.java index 03213aa87..e3c0c7360 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/GrantManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/GrantManager.java @@ -109,21 +109,24 @@ public class GrantManager { public List getCriteriaWithExternal(GrantCriteriaRequest grantCriteria, Principal principal) throws HugeResultSet, NoURLFound { eu.eudat.data.entities.UserInfo userInfo = new eu.eudat.data.entities.UserInfo(); userInfo.setId(principal.getId()); - if (grantCriteria.getCriteria().getFunderReference() != null && !grantCriteria.getCriteria().getFunderReference().trim().isEmpty()) { + /*if (grantCriteria.getCriteria().getFunderReference() != null && !grantCriteria.getCriteria().getFunderReference().trim().isEmpty()) { FunderCriteria funderCriteria = new FunderCriteria(); funderCriteria.setReference(grantCriteria.getCriteria().getFunderReference()); Funder funder = apiContext.getOperationsContext().getDatabaseRepository().getFunderDao().getWithCritetia(funderCriteria).getSingleOrDefault(); if (funder != null) { grantCriteria.getCriteria().setFunderId(funder.getId().toString()); } + }*/ + ExternalUrlCriteria externalUrlCriteria = new ExternalUrlCriteria(grantCriteria.getCriteria().getLike()); + if (grantCriteria.getCriteria().getFunderReference() != null) { + externalUrlCriteria.setFunderId(grantCriteria.getCriteria().getFunderReference()); + grantCriteria.getCriteria().setFunderReference(null); } grantCriteria.getCriteria().setReference("dmp:"); QueryableList items = apiContext.getOperationsContext().getDatabaseRepository().getGrantDao().getWithCriteria(grantCriteria.getCriteria()); QueryableList authItems = apiContext.getOperationsContext().getDatabaseRepository().getGrantDao().getAuthenticated(items, userInfo); List grants = authItems.select(item -> new Grant().fromDataModel(item)); - ExternalUrlCriteria externalUrlCriteria = new ExternalUrlCriteria(grantCriteria.getCriteria().getLike()); - if (grantCriteria.getCriteria().getFunderReference() != null) externalUrlCriteria.setFunderId(grantCriteria.getCriteria().getFunderReference()); List> remoteRepos = remoteFetcher.getGrants(externalUrlCriteria); GrantsExternalSourcesModel grantsExternalSourcesModel = new GrantsExternalSourcesModel().fromExternalItem(remoteRepos); From d4db0e204e962098bd5e0f21fe9fc0c65ae54a6a Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Fri, 13 Dec 2019 11:53:43 +0200 Subject: [PATCH 019/106] fixed validation issues on dmp wizard --- .../editor/dmp-profile-editor.component.ts | 41 +------ .../contact-content.component.ts | 20 +--- .../ui/grant/editor/grant-editor.component.ts | 42 ++----- .../dmp-editor/dmp-editor-wizard.component.ts | 40 +------ .../funder-editor-wizard.component.html | 11 +- .../funder-editor-wizard.component.ts | 58 ++-------- .../grant-editor-wizard.component.html | 2 +- .../grant-editor-wizard.component.ts | 106 +++++------------- .../quick-wizard-editor.component.html | 8 +- .../quick-wizard-editor.component.ts | 40 +------ .../sidebar-footer.component.html | 18 +-- .../sidebar-footer.component.ts | 24 +--- 12 files changed, 91 insertions(+), 319 deletions(-) diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.ts b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.ts index 51fe8a1c7..b7cf3cdd0 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.ts @@ -1,6 +1,6 @@ import { AfterViewInit, Component } from '@angular/core'; -import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; +import { FormArray, FormGroup } 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'; @@ -13,6 +13,7 @@ import { DmpProfileEditorModel, DmpProfileFieldEditorModel } from '@app/ui/admin import { DmpProfileExternalAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model'; import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { BaseComponent } from '@common/base/base.component'; +import { FormService } from '@common/forms/form-service'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; import { environment } from 'environments/environment'; @@ -42,7 +43,8 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie private router: Router, private language: TranslateService, private enumUtils: EnumUtils, - private uiNotificationService: UiNotificationService + private uiNotificationService: UiNotificationService, + private formService: FormService ) { super(); } @@ -86,7 +88,7 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie } formSubmit(): void { - this.touchAllFormFields(this.formGroup); + this.formService.touchAllFormFields(this.formGroup); if (!this.isFormValid()) { return; } this.onSubmit(); } @@ -111,7 +113,7 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie onCallbackError(errorResponse: any) { this.setErrorModel(errorResponse.error); - this.validateAllFormFields(this.formGroup); + this.formService.validateAllFormFields(this.formGroup); } public setErrorModel(validationErrorModel: ValidationErrorModel) { @@ -124,37 +126,6 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie this.router.navigate(['/dmp-profiles']); } - - public touchAllFormFields(formControl: AbstractControl) { - if (formControl instanceof FormControl) { - formControl.markAsTouched(); - } else if (formControl instanceof FormGroup) { - Object.keys(formControl.controls).forEach(item => { - const control = formControl.get(item); - this.touchAllFormFields(control); - }); - } else if (formControl instanceof FormArray) { - formControl.controls.forEach(item => { - this.touchAllFormFields(item); - }); - } - } - - public validateAllFormFields(formControl: AbstractControl) { - if (formControl instanceof FormControl) { - formControl.updateValueAndValidity({ emitEvent: false }); - } else if (formControl instanceof FormGroup) { - Object.keys(formControl.controls).forEach(item => { - const control = formControl.get(item); - this.validateAllFormFields(control); - }); - } else if (formControl instanceof FormArray) { - formControl.controls.forEach(item => { - this.validateAllFormFields(item); - }); - } - } - addField() { (this.formGroup.get('definition').get('fields')).push(new DmpProfileFieldEditorModel().buildForm()); } diff --git a/dmp-frontend/src/app/ui/contact/contact-content/contact-content.component.ts b/dmp-frontend/src/app/ui/contact/contact-content/contact-content.component.ts index b1275e92a..207cc3848 100644 --- a/dmp-frontend/src/app/ui/contact/contact-content/contact-content.component.ts +++ b/dmp-frontend/src/app/ui/contact/contact-content/contact-content.component.ts @@ -8,6 +8,7 @@ import { BaseComponent } from '@common/base/base.component'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; +import { FormService } from '@common/forms/form-service'; @Component({ selector: 'app-contact-content', @@ -26,6 +27,7 @@ export class ContactContentComponent extends BaseComponent implements OnInit { private _location: Location, private uiNotificationService: UiNotificationService, private language: TranslateService, + private formService: FormService ) { super(); } @@ -59,7 +61,7 @@ export class ContactContentComponent extends BaseComponent implements OnInit { onCallbackError(errorResponse: any) { this.setErrorModel(errorResponse.error); - this.validateAllFormFields(this.formGroup); + this.formService.validateAllFormFields(this.formGroup); this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-EMAIL-SEND'), SnackBarNotificationLevel.Error); } @@ -68,20 +70,4 @@ export class ContactContentComponent extends BaseComponent implements OnInit { (this.contactEmailFormModel.validationErrorModel)[item] = (validationErrorModel)[item]; }); } - - public validateAllFormFields(formControl: AbstractControl) { - if (formControl instanceof FormControl) { - formControl.updateValueAndValidity({ emitEvent: false }); - } else if (formControl instanceof FormGroup) { - Object.keys(formControl.controls).forEach(item => { - const control = formControl.get(item); - this.validateAllFormFields(control); - }); - } else if (formControl instanceof FormArray) { - formControl.controls.forEach(item => { - this.validateAllFormFields(item); - }); - } - } - } diff --git a/dmp-frontend/src/app/ui/grant/editor/grant-editor.component.ts b/dmp-frontend/src/app/ui/grant/editor/grant-editor.component.ts index 6310ae2da..428cf5a1d 100644 --- a/dmp-frontend/src/app/ui/grant/editor/grant-editor.component.ts +++ b/dmp-frontend/src/app/ui/grant/editor/grant-editor.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from '@angular/core'; -import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; +import { FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { MatSnackBar } from '@angular/material/snack-bar'; import { ActivatedRoute, Params, Router } from '@angular/router'; @@ -9,12 +9,13 @@ import { GrantListingModel } from '@app/core/model/grant/grant-listing'; import { GrantFileUploadService } from '@app/core/services/grant/grant-file-upload.service'; import { GrantService } from '@app/core/services/grant/grant.service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; -import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { GrantEditorModel } from '@app/ui/grant/editor/grant-editor.model'; import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; import { BaseComponent } from '@common/base/base.component'; +import { FormService } from '@common/forms/form-service'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { TranslateService } from '@ngx-translate/core'; import { environment } from 'environments/environment'; import { Observable, of as observableOf } from 'rxjs'; @@ -44,7 +45,8 @@ export class GrantEditorComponent extends BaseComponent implements OnInit, IBrea public language: TranslateService, private dialog: MatDialog, private grantFileUploadService: GrantFileUploadService, - private uiNotificationService: UiNotificationService + private uiNotificationService: UiNotificationService, + private formService: FormService ) { super(); } @@ -100,7 +102,7 @@ export class GrantEditorComponent extends BaseComponent implements OnInit, IBrea } formSubmit(): void { - this.touchAllFormFields(this.formGroup); + this.formService.touchAllFormFields(this.formGroup); if (!this.isFormValid()) { return; } this.onSubmit(); } @@ -125,7 +127,7 @@ export class GrantEditorComponent extends BaseComponent implements OnInit, IBrea onCallbackError(errorResponse: any) { this.setErrorModel(errorResponse.error.payload); - this.validateAllFormFields(this.formGroup); + this.formService.validateAllFormFields(this.formGroup); } public setErrorModel(validationErrorModel: ValidationErrorModel) { @@ -161,36 +163,6 @@ export class GrantEditorComponent extends BaseComponent implements OnInit, IBrea }); } - public touchAllFormFields(formControl: AbstractControl) { - if (formControl instanceof FormControl) { - formControl.markAsTouched(); - } else if (formControl instanceof FormGroup) { - Object.keys(formControl.controls).forEach(item => { - const control = formControl.get(item); - this.touchAllFormFields(control); - }); - } else if (formControl instanceof FormArray) { - formControl.controls.forEach(item => { - this.touchAllFormFields(item); - }); - } - } - - public validateAllFormFields(formControl: AbstractControl) { - if (formControl instanceof FormControl) { - formControl.updateValueAndValidity({ emitEvent: false }); - } else if (formControl instanceof FormGroup) { - Object.keys(formControl.controls).forEach(item => { - const control = formControl.get(item); - this.validateAllFormFields(control); - }); - } else if (formControl instanceof FormArray) { - formControl.controls.forEach(item => { - this.validateAllFormFields(item); - }); - } - } - public enableForm() { if (!this.isExternalGrant()) { this.editMode = true; diff --git a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.ts index 4674857d6..99d898a15 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; +import { FormArray, FormGroup } from '@angular/forms'; import { MatSnackBar } from '@angular/material/snack-bar'; import { ActivatedRoute, Router } from '@angular/router'; import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; @@ -12,6 +12,7 @@ import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/sing import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; import { BaseComponent } from '@common/base/base.component'; +import { FormService } from '@common/forms/form-service'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; import { Observable, of as observableOf } from 'rxjs'; @@ -44,7 +45,8 @@ export class DmpEditorWizardComponent extends BaseComponent implements OnInit, I public router: Router, private route: ActivatedRoute, private _service: DmpService, - public language: TranslateService + public language: TranslateService, + private formService: FormService ) { super(); } @@ -74,7 +76,7 @@ export class DmpEditorWizardComponent extends BaseComponent implements OnInit, I } formSubmit(): void { - this.touchAllFormFields(this.formGroup); + this.formService.touchAllFormFields(this.formGroup); if (!this.isFormValid()) { return; } this.onSubmit(); } @@ -83,21 +85,6 @@ export class DmpEditorWizardComponent extends BaseComponent implements OnInit, I return this.formGroup.valid; } - public touchAllFormFields(formControl: AbstractControl) { - if (formControl instanceof FormControl) { - formControl.markAsTouched(); - } else if (formControl instanceof FormGroup) { - Object.keys(formControl.controls).forEach(item => { - const control = formControl.get(item); - this.touchAllFormFields(control); - }); - } else if (formControl instanceof FormArray) { - formControl.controls.forEach(item => { - this.touchAllFormFields(item); - }); - } - } - onSubmit(): void { // this.grantService.createGrant(this.formGroup.value) // .pipe(takeUntil(this._destroyed)) @@ -115,7 +102,7 @@ export class DmpEditorWizardComponent extends BaseComponent implements OnInit, I onCallbackError(errorResponse: any) { this.setErrorModel(errorResponse.error.payload); - this.validateAllFormFields(this.formGroup); + this.formService.validateAllFormFields(this.formGroup); } public setErrorModel(validationErrorModel: ValidationErrorModel) { @@ -124,21 +111,6 @@ export class DmpEditorWizardComponent extends BaseComponent implements OnInit, I }); } - public validateAllFormFields(formControl: AbstractControl) { - if (formControl instanceof FormControl) { - formControl.updateValueAndValidity({ emitEvent: false }); - } else if (formControl instanceof FormGroup) { - Object.keys(formControl.controls).forEach(item => { - const control = formControl.get(item); - this.validateAllFormFields(control); - }); - } else if (formControl instanceof FormArray) { - formControl.controls.forEach(item => { - this.validateAllFormFields(item); - }); - } - } - filterProfiles(value: string): Observable { this.filteredProfiles = undefined; diff --git a/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.html b/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.html index b4606ff50..80acc2f60 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.html +++ b/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.html @@ -6,20 +6,19 @@

{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.ABOUT-FUNDER' | translate}}

- + {{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}}

{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.ABOUT-NEW-FUNDER' | translate}}

- - - {{funderFormGroup.get('label').getError('backendError').message}} - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{funderFormGroup.get('label').getError('backendError').message}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}}
diff --git a/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.ts index 45334e50a..9fb39f429 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.ts @@ -1,11 +1,12 @@ -import { Component, OnInit, Input } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { SingleAutoCompleteConfiguration } from '../../../library/auto-complete/single/single-auto-complete-configuration'; -import { FunderService } from '../../../core/services/funder/funder.service'; -import { RequestItem } from '../../../core/query/request-item'; -import { FunderCriteria } from '../../../core/query/funder/funder-criteria'; -import { FunderFormModel } from '../../dmp/editor/grant-tab/funder-form-model'; +import { FunderModel } from '@app/core/model/funder/funder'; import { TranslateService } from '@ngx-translate/core'; +import { FunderCriteria } from '../../../core/query/funder/funder-criteria'; +import { RequestItem } from '../../../core/query/request-item'; +import { FunderService } from '../../../core/services/funder/funder.service'; +import { SingleAutoCompleteConfiguration } from '../../../library/auto-complete/single/single-auto-complete-configuration'; +import { FunderFormModel } from '../../dmp/editor/grant-tab/funder-form-model'; @Component({ selector: 'app-quick-wizard-funder-editor-component', @@ -18,7 +19,6 @@ export class FunderEditorWizardComponent implements OnInit { funder: FunderFormModel; funderLabelCleared = true; @Input() funderFormGroup: FormGroup; - @Input() grantformGroup: FormGroup; funderAutoCompleteConfiguration: SingleAutoCompleteConfiguration; constructor( @@ -55,51 +55,13 @@ export class FunderEditorWizardComponent implements OnInit { create() { this.isNew = !this.isNew; if (this.isNew) { - this.funderFormGroup.get('existFunder').disable(); this.funderFormGroup.get('existFunder').reset(); + this.funderFormGroup.get('existFunder').disable(); this.funderFormGroup.get('label').enable(); } else { - this.funderFormGroup.get('existFunder').enable(); - this.funderFormGroup.get('label').disable(); this.funderFormGroup.get('label').reset(); + this.funderFormGroup.get('label').disable(); + this.funderFormGroup.get('existFunder').enable(); } } - - onFunderSelected() { - if (this.grantformGroup.get('existGrant').disabled) { - this.grantformGroup.get('existGrant').enable(); - this.grantformGroup.get('label').disable(); - this.grantformGroup.get('description').disable(); - } else { - this.grantformGroup.get('existGrant').disable(); - this.grantformGroup.get('label').enable(); - this.grantformGroup.get('description').enable(); - } - } - - onFunderRemoved() { - if (this.grantformGroup.get('existGrant').enabled) { - this.grantformGroup.get('existGrant').disable(); - this.grantformGroup.get('existGrant').reset(); - this.grantformGroup.get('label').enable(); - this.grantformGroup.get('description').enable(); - } else { - this.grantformGroup.get('existGrant').enable(); - this.grantformGroup.get('label').disable(); - this.grantformGroup.get('label').reset(); - this.grantformGroup.get('description').disable(); - this.grantformGroup.get('description').reset(); - } - } - - controlModified(event: any) { - if (event && this.funderLabelCleared) { - this.funderLabelCleared = false; - this.onFunderSelected(); - } else if (!event) { - this.funderLabelCleared = true; - this.onFunderRemoved(); - } - } - } diff --git a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.html b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.html index 2b4d9e1b0..f55f3f3c1 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.html +++ b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.html @@ -10,7 +10,7 @@

{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.ABOUT-GRANT' | translate}}

- + {{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}} diff --git a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts index c1a605c8a..de9f7f666 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts @@ -12,9 +12,11 @@ import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-it import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; import { GrantEditorWizardModel } from '@app/ui/quick-wizard/grant-editor/grant-editor-wizard-model'; import { BaseComponent } from '@common/base/base.component'; +import { FormService } from '@common/forms/form-service'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; import { Observable, of as observableOf } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-quick-wizard-grant-editor-component', @@ -36,7 +38,8 @@ export class GrantEditorWizardComponent extends BaseComponent implements OnInit, public snackBar: MatSnackBar, public router: Router, public language: TranslateService, - private grantService: GrantService + private grantService: GrantService, + private formService: FormService ) { super(); } @@ -59,12 +62,7 @@ export class GrantEditorWizardComponent extends BaseComponent implements OnInit, subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') }; - if (!this.grantformGroup) { - this.grant = new GrantEditorWizardModel(); - this.grantformGroup = this.grant.buildForm(); - } - - if (this.funderFormGroup && this.funderFormGroup.get('funder')) { + if (this.funderFormGroup && this.funderFormGroup.valid) { this.grantformGroup.get('existGrant').enable(); this.grantformGroup.get('label').disable(); this.grantformGroup.get('description').disable(); @@ -72,55 +70,29 @@ export class GrantEditorWizardComponent extends BaseComponent implements OnInit, this.grantformGroup.get('existGrant').disable(); } - // this.route.params - // .pipe(takeUntil(this._destroyed)) - // .subscribe((params: Params) => { - // const itemId = params['id']; + this.funderFormGroup.statusChanges.pipe(takeUntil(this._destroyed)).subscribe(x => { + if (x == 'INVALID') { + this.grantformGroup.get('existGrant').reset(); + this.grantformGroup.get('label').reset(); + this.grantformGroup.get('description').reset(); + this.grantformGroup.get('existGrant').disable(); + this.grantformGroup.get('label').disable(); + this.grantformGroup.get('description').disable(); + } else if (x == 'VALID') { + if (!this.isNew) { + this.grantformGroup.get('label').reset(); + this.grantformGroup.get('description').reset(); + this.grantformGroup.get('label').disable(); + this.grantformGroup.get('description').disable(); + this.grantformGroup.get('existGrant').enable(); - // if (itemId != null) { - // this.isNew = false; - // this.grantService.getSingle(itemId).map(data => data as GrantListingModel) - // .pipe(takeUntil(this._destroyed)) - // .subscribe(data => { - // this.grant = new GrantEditorModel().fromModel(data); - // this.formGroup = this.grant.buildForm(null, this.grant.type === GrantType.External || !this.editMode); - // this.breadCrumbs = Observable.of([ - // { parentComponentName: 'GrantListingComponent', label: 'Grants', url: '/grants' }, - // ]); - // }); - // } else { - // this.breadCrumbs = Observable.of([ - // { parentComponentName: 'QuickWizardComponent', label: 'Grants', url: '/grants' }, - // ]); - // this.grant = new GrantEditorWizardModel(); - // setTimeout(() => { - // this.formGroup = this.grant.buildForm(); - // }); - // } - // }); - } - - public isFormValid() { - return this.grantformGroup.valid; + } + } + }) } isFunderFormInvalid() { - return !this.funderFormGroup.get('existFunder').value && !this.funderFormGroup.get('label').valid; - } - - public touchAllFormFields(formControl: AbstractControl) { - if (formControl instanceof FormControl) { - formControl.markAsTouched(); - } else if (formControl instanceof FormGroup) { - Object.keys(formControl.controls).forEach(item => { - const control = formControl.get(item); - this.touchAllFormFields(control); - }); - } else if (formControl instanceof FormArray) { - formControl.controls.forEach(item => { - this.touchAllFormFields(item); - }); - } + return !this.funderFormGroup.valid; } onCallbackSuccess(): void { @@ -130,7 +102,7 @@ export class GrantEditorWizardComponent extends BaseComponent implements OnInit, onCallbackError(errorResponse: any) { this.setErrorModel(errorResponse.error.payload); - this.validateAllFormFields(this.grantformGroup); + this.formService.validateAllFormFields(this.grantformGroup); } public setErrorModel(validationErrorModel: ValidationErrorModel) { @@ -139,21 +111,6 @@ export class GrantEditorWizardComponent extends BaseComponent implements OnInit, }); } - public validateAllFormFields(formControl: AbstractControl) { - if (formControl instanceof FormControl) { - formControl.updateValueAndValidity({ emitEvent: false }); - } else if (formControl instanceof FormGroup) { - Object.keys(formControl.controls).forEach(item => { - const control = formControl.get(item); - this.validateAllFormFields(control); - }); - } else if (formControl instanceof FormArray) { - formControl.controls.forEach(item => { - this.validateAllFormFields(item); - }); - } - } - searchGrant(query: string) { const grantRequestItem: RequestItem = new RequestItem(); grantRequestItem.criteria = new GrantCriteria(); @@ -167,21 +124,16 @@ export class GrantEditorWizardComponent extends BaseComponent implements OnInit, create() { this.isNew = !this.isNew; if (this.isNew) { - this.grantformGroup.get('existGrant').disable(); this.grantformGroup.get('existGrant').reset(); + this.grantformGroup.get('existGrant').disable(); this.grantformGroup.get('label').enable(); this.grantformGroup.get('description').enable(); } else { - this.grantformGroup.get('existGrant').enable(); - this.grantformGroup.get('label').disable(); this.grantformGroup.get('label').reset(); - this.grantformGroup.get('description').disable(); + this.grantformGroup.get('label').disable(); this.grantformGroup.get('description').reset(); + this.grantformGroup.get('description').disable(); + this.grantformGroup.get('existGrant').enable(); } } - - onGrantSelected() { - this.grantformGroup.get('label').disable(); - this.grantformGroup.get('description').disable(); - } } diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.html b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.html index 8b3a7c7c9..a240ffbc1 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.html +++ b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.html @@ -6,11 +6,11 @@

{{ 'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.POST-SELECTION-INFO' | translate }}

- + {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.TITLE' | translate}} - +
@@ -19,7 +19,7 @@
- + {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.SECOND-STEP.TITLE' | translate}} @@ -36,7 +36,7 @@
- + {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.THIRD-STEP.TITLE' | translate}} diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.ts b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.ts index 2867109dc..35800d86f 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.ts @@ -10,7 +10,6 @@ import { DmpStatus } from '@app/core/common/enum/dmp-status'; import { DatasetService } from '@app/core/services/dataset/dataset.service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { QuickWizardService } from '@app/core/services/quick-wizard/quick-wizard.service'; -import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; import { DmpFinalizeDialogComponent, DmpFinalizeDialogDataset, DmpFinalizeDialogInput } from '@app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; @@ -20,7 +19,9 @@ import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadC import { DatasetEditorWizardComponent } from '@app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component'; import { GrantEditorWizardModel } from '@app/ui/quick-wizard/grant-editor/grant-editor-wizard-model'; import { QuickWizardEditorWizardModel } from '@app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model'; +import { FormService } from '@common/forms/form-service'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { TranslateService } from '@ngx-translate/core'; import { Observable, of as observableOf } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @@ -48,7 +49,8 @@ export class QuickWizardEditorComponent extends CheckDeactivateBaseComponent imp public datasetService: DatasetService, public quickWizardService: QuickWizardService, private uiNotificationService: UiNotificationService, - private dialog: MatDialog + private dialog: MatDialog, + private formService: FormService ) { super(); } @@ -82,7 +84,7 @@ export class QuickWizardEditorComponent extends CheckDeactivateBaseComponent imp } formSubmit(): void { - this.touchAllFormFields(this.formGroup); + this.formService.touchAllFormFields(this.formGroup); if (this.formGroup.get('datasets') && this.formGroup.get('datasets').get('datasetsList') && (this.formGroup.get('datasets').get('datasetsList') as FormArray).length > 0) { for (let control of (this.formGroup.get('datasets').get('datasetsList') as FormArray).controls) { control.get('status').setValue(DatasetStatus.Draft); @@ -137,21 +139,6 @@ export class QuickWizardEditorComponent extends CheckDeactivateBaseComponent imp return this.formGroup.get('grant').valid && this.formGroup.get('funder').valid; } - public touchAllFormFields(formControl: AbstractControl) { - if (formControl instanceof FormControl) { - formControl.markAsTouched(); - } else if (formControl instanceof FormGroup) { - Object.keys(formControl.controls).forEach(item => { - const control = formControl.get(item); - this.touchAllFormFields(control); - }); - } else if (formControl instanceof FormArray) { - formControl.controls.forEach(item => { - this.touchAllFormFields(item); - }); - } - } - onSubmitSaveAndFinalize() { this.quickWizardService.createQuickWizard(this.formGroup.getRawValue()) .pipe(takeUntil(this._destroyed)) @@ -192,7 +179,7 @@ export class QuickWizardEditorComponent extends CheckDeactivateBaseComponent imp onCallbackError(errorResponse: any) { this.setErrorModel(errorResponse.error.payload); - this.validateAllFormFields(this.formGroup); + this.formService.validateAllFormFields(this.formGroup); } public setErrorModel(validationErrorModel: ValidationErrorModel) { @@ -201,21 +188,6 @@ export class QuickWizardEditorComponent extends CheckDeactivateBaseComponent imp }); } - public validateAllFormFields(formControl: AbstractControl) { - if (formControl instanceof FormControl) { - formControl.updateValueAndValidity({ emitEvent: false }); - } else if (formControl instanceof FormGroup) { - Object.keys(formControl.controls).forEach(item => { - const control = formControl.get(item); - this.validateAllFormFields(control); - }); - } else if (formControl instanceof FormArray) { - formControl.controls.forEach(item => { - this.validateAllFormFields(item); - }); - } - } - getGrantLabel(): string { if (this.formGroup.get('grant').get('existGrant').value) { return this.formGroup.get('grant').get('existGrant').value['label']; diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.html b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.html index d9e66567b..ba92feae2 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.html +++ b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.html @@ -8,32 +8,32 @@ Help
-->
-
+

{{'FOOTER.GLOSSARY' | translate}}

-
+

{{'FOOTER.FAQ' | translate}}

-
+
+
+

{{'FOOTER.CONTACT-SUPPORT' | translate}}

-
-
-
+ -
+ + {{'FOOTER.PRIVACY-POLICY' | translate}} -
+
-->
diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.ts b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.ts index ac594671b..fcab57335 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.ts +++ b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; +import { FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { Router } from '@angular/router'; import { ContactEmailFormModel } from '@app/core/model/contact/contact-email-form-model'; @@ -9,6 +9,7 @@ import { ContactDialogComponent } from '@app/ui/contact/contact-dialog/contact-d import { FaqDialogComponent } from '@app/ui/faq/dialog/faq-dialog.component'; import { GlossaryDialogComponent } from '@app/ui/glossary/dialog/glossary-dialog.component'; import { BaseComponent } from '@common/base/base.component'; +import { FormService } from '@common/forms/form-service'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; @@ -28,7 +29,8 @@ export class SidebarFooterComponent extends BaseComponent implements OnInit { private language: TranslateService, public router: Router, private contactSupportService: ContactSupportService, - private uiNotificationService: UiNotificationService + private uiNotificationService: UiNotificationService, + private formService: FormService ) { super(); } @@ -99,7 +101,7 @@ export class SidebarFooterComponent extends BaseComponent implements OnInit { onCallbackError(errorResponse: any) { this.setErrorModel(errorResponse.error); - this.validateAllFormFields(this.formGroup); + this.formService.validateAllFormFields(this.formGroup); this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-EMAIL-SEND'), SnackBarNotificationLevel.Error); } @@ -108,20 +110,4 @@ export class SidebarFooterComponent extends BaseComponent implements OnInit { (this.contactEmailFormModel.validationErrorModel)[item] = (validationErrorModel)[item]; }); } - - public validateAllFormFields(formControl: AbstractControl) { - if (formControl instanceof FormControl) { - formControl.updateValueAndValidity({ emitEvent: false }); - } else if (formControl instanceof FormGroup) { - Object.keys(formControl.controls).forEach(item => { - const control = formControl.get(item); - this.validateAllFormFields(control); - }); - } else if (formControl instanceof FormArray) { - formControl.controls.forEach(item => { - this.validateAllFormFields(item); - }); - } - } - } From 52334aec6a7410ea3d4263d3f4d3af31ddb82dc5 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Fri, 13 Dec 2019 13:05:58 +0200 Subject: [PATCH 020/106] Fixes bug on not creating new "External Datasets" and "Data Repositories". (Issue #212) --- .../datarepository/DataRepositoryModel.java | 29 +++++++++---------- .../models/data/dataset/DataRepository.java | 16 +++++----- .../model/data-repository/data-repository.ts | 2 +- .../dataset-wizard-editor.model.ts | 10 +++---- ...-external-references-editor.component.html | 2 +- ...et-external-references-editor.component.ts | 2 +- ...ta-repository-dialog-editor.component.html | 4 +-- 7 files changed, 32 insertions(+), 33 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/datarepository/DataRepositoryModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/datarepository/DataRepositoryModel.java index 200bf2d78..339b6f660 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/datarepository/DataRepositoryModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/datarepository/DataRepositoryModel.java @@ -1,6 +1,5 @@ package eu.eudat.models.data.datarepository; -import com.fasterxml.jackson.annotation.JsonProperty; import eu.eudat.data.entities.DataRepository; import eu.eudat.data.entities.UserInfo; import eu.eudat.models.DataModel; @@ -8,13 +7,9 @@ import eu.eudat.models.DataModel; import java.util.Date; import java.util.UUID; -/** - * Created by ikalyvas on 9/3/2018. - */ public class DataRepositoryModel implements DataModel { private UUID id; - @JsonProperty("name") - private String label; + private String name; private String pid; private String abbreviation; private String uri; @@ -30,11 +25,11 @@ public class DataRepositoryModel implements DataModel, LabelGenerator { private String pid; - private String label; + private String name; private String uri; private String info; private String reference; @@ -21,11 +21,11 @@ public class DataRepository implements DataModel
- {{i+1}}) {{suggestion.get('label').value}} + {{i+1}}) {{suggestion.get('name').value}}
diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts index 57a63660e..48d596ead 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts @@ -139,7 +139,7 @@ export class DatasetExternalReferencesEditorComponent extends BaseComponent impl .pipe(takeUntil(this._destroyed)) .subscribe(result => { if (!result) { return; } - const dataRepositoryModel = new ExternalDataRepositoryEditorModel(result.id, result.label, result.pid, result.uri, result.reference); + const dataRepositoryModel = new ExternalDataRepositoryEditorModel(result.id, result.name, result.pid, result.uri, result.reference); (this.formGroup.get('dataRepositories')).push(dataRepositoryModel.buildForm()); }); } diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.html b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.html index 900f5f4aa..2367cc238 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.html +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.html @@ -9,8 +9,8 @@
- - {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} From e96c927f9451bb33114629514d49a5fa189a68e2 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Fri, 13 Dec 2019 13:08:32 +0200 Subject: [PATCH 021/106] Increases page size when fetching from external Urls. (Issue #208) --- .../java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java index ed92795dd..9c6c90d44 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java @@ -179,7 +179,7 @@ public class RemoteFetcher { if (externalUrlCriteria.getPageSize() != null) { completedPath = completedPath.replace("{pageSize}", externalUrlCriteria.getPageSize()); } else { - completedPath = completedPath.replace("{pageSize}", "10"); + completedPath = completedPath.replace("{pageSize}", "60"); } return completedPath; } @@ -244,7 +244,7 @@ public class RemoteFetcher { results = new Results(jsonContext.read(jsonDataPath.getPath() + "[" + jsonDataPath.getFieldsUrlConfiguration().getName() + "," + jsonDataPath.getFieldsUrlConfiguration().getDescription() + "," + jsonDataPath.getFieldsUrlConfiguration().getUri() + "," + jsonDataPath.getFieldsUrlConfiguration().getId() + "]"), - jsonContext.read(jsonPaginationPath)); + new HashMap<>(1, 1)); } results.results = results.results.stream().map(e -> e.entrySet().stream().collect(Collectors.toMap(x -> this.transformKey(jsonDataPath,x.getKey()), Map.Entry::getValue))) .collect(Collectors.toList()); From 55b6da619f6cd152b6e258138337a70f619f9a2b Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Fri, 13 Dec 2019 13:15:12 +0200 Subject: [PATCH 022/106] bug fixes --- dmp-frontend/src/app/app-routing.module.ts | 4 +- dmp-frontend/src/app/app.module.ts | 4 +- dmp-frontend/src/app/core/model/dmp/dmp.ts | 3 +- .../dataset-wizard-editor.model.ts | 24 +++--- .../dataset-wizard.component.html | 6 +- .../dataset-wizard.component.ts | 86 ++++++++++++------- ...data-repository-dialog-editor.component.ts | 6 +- ...xternal-dataset-dialog-editor.component.ts | 6 +- ...ternal-registry-dialog-editor.component.ts | 6 +- ...xternal-service-dialog-editor.component.ts | 6 +- .../src/app/ui/dataset/dataset.module.ts | 6 +- .../app/ui/dmp/clone/dmp-clone.component.ts | 2 + .../app/ui/dmp/editor/dmp-editor.component.ts | 6 +- .../src/app/ui/dmp/editor/dmp-editor.model.ts | 4 +- .../ui/dmp/wizard/dmp-wizard-editor.model.ts | 3 +- .../reload-helper/reload-helper.component.ts | 9 ++ .../dmp-editor/dmp-editor-wizard-model.ts | 3 +- 17 files changed, 123 insertions(+), 61 deletions(-) create mode 100644 dmp-frontend/src/app/ui/misc/reload-helper/reload-helper.component.ts diff --git a/dmp-frontend/src/app/app-routing.module.ts b/dmp-frontend/src/app/app-routing.module.ts index 9ba283c4d..9b56a04b2 100644 --- a/dmp-frontend/src/app/app-routing.module.ts +++ b/dmp-frontend/src/app/app-routing.module.ts @@ -1,5 +1,6 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; +import { ReloadHelperComponent } from '@app/ui/misc/reload-helper/reload-helper.component'; import { B2AccessLoginComponent } from './ui/auth/login/b2access/b2access-login.component'; const appRoutes: Routes = [ @@ -183,7 +184,8 @@ const appRoutes: Routes = [ component: B2AccessLoginComponent, data: { }, - } + }, + { path: 'reload', component: ReloadHelperComponent } ]; @NgModule({ diff --git a/dmp-frontend/src/app/app.module.ts b/dmp-frontend/src/app/app.module.ts index 47ea72a8b..5f0014ec1 100644 --- a/dmp-frontend/src/app/app.module.ts +++ b/dmp-frontend/src/app/app.module.ts @@ -16,6 +16,7 @@ import { DatasetCreateWizardModule } from '@app/ui/dataset-create-wizard/dataset import { BreadcrumbModule } from '@app/ui/misc/breadcrumb/breadcrumb.module'; import { HelpContentModule } from '@app/ui/misc/help-content/help-content.module'; import { NavigationModule } from '@app/ui/misc/navigation/navigation.module'; +import { ReloadHelperComponent } from '@app/ui/misc/reload-helper/reload-helper.component'; import { NavbarModule } from '@app/ui/navbar/navbar.module'; import { SidebarModule } from '@app/ui/sidebar/sidebar.module'; import { MomentUtcDateAdapter } from '@common/date/moment-utc-date-adapter'; @@ -94,7 +95,8 @@ const cookieConfig: NgcCookieConsentConfig = { NgcCookieConsentModule.forRoot(cookieConfig) ], declarations: [ - AppComponent + AppComponent, + ReloadHelperComponent ], providers: [ { diff --git a/dmp-frontend/src/app/core/model/dmp/dmp.ts b/dmp-frontend/src/app/core/model/dmp/dmp.ts index fd91ba248..aff7f3867 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp.ts @@ -9,6 +9,7 @@ import { UserInfoListingModel } from "../user/user-info-listing"; import { DatasetModel } from "../dataset/dataset"; import { ProjectModel } from "../project/project"; import { FunderModel } from "../funder/funder"; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; export interface DmpModel { id: string; @@ -16,7 +17,7 @@ export interface DmpModel { groupId: String; profile: String; version: number; - status: Status; + status: DmpStatus; lockable: boolean; description: String; grant: GrantListingModel; diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard-editor.model.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard-editor.model.ts index 052d4e68f..3a9cb0598 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard-editor.model.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard-editor.model.ts @@ -203,10 +203,10 @@ export class ExternalServiceEditorModel { buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { return new FormBuilder().group({ id: [this.id], - abbreviation: [this.abbreviation], - label: [this.label], + abbreviation: [this.abbreviation, Validators.required], + label: [this.label, Validators.required], reference: [this.reference], - uri: [this.uri], + uri: [this.uri, Validators.required], definition: [this.definition] }); } @@ -246,10 +246,10 @@ export class ExternalRegistryEditorModel { buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { return new FormBuilder().group({ id: [this.id], - abbreviation: [this.abbreviation], - label: [this.label], + abbreviation: [this.abbreviation, Validators.required], + label: [this.label, Validators.required], reference: [this.reference], - uri: [this.uri], + uri: [this.uri, Validators.required], definition: [this.definition], source: [this.source] }); @@ -291,10 +291,10 @@ export class ExternalDatasetEditorModel { buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { return new FormBuilder().group({ id: [this.id], - abbreviation: [this.abbreviation], - name: [this.name], + abbreviation: [this.abbreviation, Validators.required], + name: [this.name, Validators.required], reference: [this.reference], - type: [this.type, Validators.required], + type: [this.type], info: [this.info], source: [this.source] }); @@ -335,9 +335,9 @@ export class ExternalDataRepositoryEditorModel { buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { return new FormBuilder().group({ id: [this.id], - label: [this.label], - abbreviation: [this.abbreviation], - uri: [this.uri], + label: [this.label, [Validators.required]], + abbreviation: [this.abbreviation, [Validators.required]], + uri: [this.uri, [Validators.required]], info: [this.info], reference: [this.reference], source: [this.source] diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.html b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.html index 601b3f209..40a84d5cd 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.html +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.html @@ -50,7 +50,7 @@
-
+
@@ -112,8 +112,8 @@ - - + +
diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts index 7b28adb42..5ed78291d 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts @@ -18,7 +18,6 @@ import { ExternalSourcesConfigurationService } from '@app/core/services/external import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; -import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { DatasetCopyDialogueComponent } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; @@ -26,7 +25,10 @@ import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadC import { DatasetDescriptionFormEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; import { LinkToScroll } from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents'; import { BaseComponent } from '@common/base/base.component'; +import { FormService } from '@common/forms/form-service'; +import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { TranslateService } from '@ngx-translate/core'; import * as FileSaver from 'file-saver'; import { Observable, of as observableOf } from 'rxjs'; @@ -70,7 +72,8 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr public dmpService: DmpService, public dialog: MatDialog, public externalSourcesConfigurationService: ExternalSourcesConfigurationService, - private uiNotificationService: UiNotificationService + private uiNotificationService: UiNotificationService, + private formService: FormService ) { super(); } @@ -89,8 +92,8 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr initialItems: (extraData) => this.searchDmp(''), displayFn: (item) => this.getDatasetDisplay(item), titleFn: (item) => item['label'], - // iconFn: (item) => this.publicMode ? '' : (item['status'] ? 'lock' : 'lock_open'), - // linkFn: (item) => this.publicMode ? '/explore-plans/overview/' + item['id'] : '/plans/overview/' + item['id'] + // iconFn: (item) => this.publicMode ? '' : (item['status'] ? 'lock' : 'lock_open'), + // linkFn: (item) => this.publicMode ? '/explore-plans/overview/' + item['id'] : '/plans/overview/' + item['id'] }; const params = this.route.snapshot.params; @@ -384,10 +387,10 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr }); } - formSubmit(): void { - if (!this.isFormValid()) { return; } - this.onSubmit(); - } + // formSubmit(): void { + // if (!this.isFormValid()) { return; } + // this.onSubmit(); + // } public isFormValid() { return this.formGroup.valid; @@ -403,36 +406,53 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr return isValid; } - onSubmit(): void { - this.datasetWizardService.createDataset(this.formGroup.value) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => { - this.datasetWizardService.getSingle(complete.id) - .pipe(takeUntil(this._destroyed)) - .subscribe( - result => { - this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(result); - } - ); - this.onCallbackSuccess(); - }, - error => this.onCallbackError(error) - ); - } + // onSubmit(): void { + // this.datasetWizardService.createDataset(this.formGroup.value) + // .pipe(takeUntil(this._destroyed)) + // .subscribe( + // complete => { + // this.datasetWizardService.getSingle(complete.id) + // .pipe(takeUntil(this._destroyed)) + // .subscribe( + // result => { + // this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(result); + // } + // ); + // this.onCallbackSuccess(); + // }, + // error => this.onCallbackError(error) + // ); + // } submit() { this.datasetWizardService.createDataset(this.formGroup.getRawValue()) .pipe(takeUntil(this._destroyed)) - .subscribe(data => { - this.router.navigate(['datasets'], { queryParams: { dmpId: this.formGroup.get('dmp').value.id } }); - }); + .subscribe( + data => { + this.onCallbackSuccess(this.datasetWizardModel.id); + }, + error => this.onCallbackError(error)); } save() { + this.formService.touchAllFormFields(this.formGroup); + if (!this.isSemiFormValid(this.formGroup)) { + this.showValidationErrorsDialog(); + return; + } this.submit(); } + private showValidationErrorsDialog(projectOnly?: boolean) { + const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { + disableClose: true, + data: { + formGroup: this.formGroup, + projectOnly: projectOnly + }, + }); + } + hasReversableStatus(): boolean { if (this.formGroup.get('dmp').value) { return (this.formGroup.get('dmp').value.status == DmpStatus.Draft && this.formGroup.get('status').value == DatasetStatus.Finalized); @@ -461,6 +481,11 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr } saveFinalize() { + this.formService.touchAllFormFields(this.formGroup); + if (!this.isFormValid()) { + this.showValidationErrorsDialog(); + return; + } const dialogRef = this.dialog.open(ConfirmationDialogComponent, { restoreFocus: false, data: { @@ -479,8 +504,9 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr }); } - onCallbackSuccess(): void { + onCallbackSuccess(id?: String): void { this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); + id ? this.router.navigate(['/reload']).then(() => { this.router.navigate(['/datasets', 'edit', id]); }) : this.router.navigate(['/datasets']); } onCallbackError(error: any) { @@ -614,7 +640,7 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr this.datasetWizardService.delete(id) .pipe(takeUntil(this._destroyed)) .subscribe( - complete => { this.onCallbackSuccess(); this.router.navigateByUrl('/datasets') }, + complete => this.onCallbackSuccess(), error => this.onCallbackError(error) ); } diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts index f162b0c9c..62bfc8c6b 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts @@ -4,6 +4,7 @@ import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { ExternalDataRepositoryService } from '@app/core/services/external-sources/data-repository/extternal-data-repository.service'; import { ExternalDataRepositoryEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; import { BaseComponent } from '@common/base/base.component'; +import { FormService } from '@common/forms/form-service'; import { takeUntil } from 'rxjs/operators'; @Component({ @@ -16,7 +17,8 @@ export class DatasetExternalDataRepositoryDialogEditorComponent extends BaseComp constructor( private externalDataRepositoryService: ExternalDataRepositoryService, public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any + @Inject(MAT_DIALOG_DATA) public data: any, + private formService: FormService ) { super(); } ngOnInit(): void { @@ -25,6 +27,8 @@ export class DatasetExternalDataRepositoryDialogEditorComponent extends BaseComp } send(value: any) { + this.formService.touchAllFormFields(this.formGroup); + if (!this.formGroup.valid) { return; } this.externalDataRepositoryService.create(this.formGroup.value) .pipe(takeUntil(this._destroyed)) .subscribe( diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts index 27fd2d062..74cdd6d34 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts @@ -5,6 +5,7 @@ import { ExternalDatasetService } from '@app/core/services/external-sources/data import { ExternalDatasetEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; +import { FormService } from '@common/forms/form-service'; @Component({ templateUrl: 'dataset-external-dataset-dialog-editor.component.html', @@ -16,7 +17,8 @@ export class DatasetExternalDatasetDialogEditorComponent extends BaseComponent i constructor( private externalDatasetService: ExternalDatasetService, public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any + @Inject(MAT_DIALOG_DATA) public data: any, + private formService: FormService ) { super(); } ngOnInit(): void { @@ -25,6 +27,8 @@ export class DatasetExternalDatasetDialogEditorComponent extends BaseComponent i } send(value: any) { + this.formService.touchAllFormFields(this.formGroup); + if (!this.formGroup.valid) { return; } this.externalDatasetService.create(this.formGroup.value) .pipe(takeUntil(this._destroyed)) .subscribe( diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts index bad2db7e6..353233c75 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts @@ -4,6 +4,7 @@ import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { ExternalRegistryService } from '@app/core/services/external-sources/registry/external-registry.service'; import { ExternalRegistryEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; import { BaseComponent } from '@common/base/base.component'; +import { FormService } from '@common/forms/form-service'; import { takeUntil } from 'rxjs/operators'; @Component({ @@ -16,7 +17,8 @@ export class DatasetExternalRegistryDialogEditorComponent extends BaseComponent constructor( private externalRegistryService: ExternalRegistryService, public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any + @Inject(MAT_DIALOG_DATA) public data: any, + private formService: FormService ) { super(); } ngOnInit(): void { @@ -25,6 +27,8 @@ export class DatasetExternalRegistryDialogEditorComponent extends BaseComponent } send(value: any) { + this.formService.touchAllFormFields(this.formGroup); + if (!this.formGroup.valid) { return; } this.externalRegistryService.create(this.formGroup.value) .pipe(takeUntil(this._destroyed)) .subscribe( diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.ts index a2b4a9dfe..10d7d0718 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.ts @@ -5,6 +5,7 @@ import { ExternalServiceService } from '@app/core/services/external-sources/serv import { ExternalServiceEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; +import { FormService } from '@common/forms/form-service'; @Component({ templateUrl: 'dataset-external-service-dialog-editor.component.html', @@ -16,7 +17,8 @@ export class DatasetExternalServiceDialogEditorComponent extends BaseComponent i constructor( private externalServiceService: ExternalServiceService, public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any + @Inject(MAT_DIALOG_DATA) public data: any, + private formService: FormService ) { super(); } ngOnInit(): void { @@ -25,6 +27,8 @@ export class DatasetExternalServiceDialogEditorComponent extends BaseComponent i } send() { + this.formService.touchAllFormFields(this.formGroup); + if (!this.formGroup.valid) { return; } this.externalServiceService.create(this.formGroup.value) .pipe(takeUntil(this._destroyed)) .subscribe( diff --git a/dmp-frontend/src/app/ui/dataset/dataset.module.ts b/dmp-frontend/src/app/ui/dataset/dataset.module.ts index 0a041cd64..5a7900993 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset.module.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset.module.ts @@ -1,6 +1,5 @@ import { NgModule } from '@angular/core'; import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; -import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; import { ExportMethodDialogModule } from '@app/library/export-method-dialog/export-method-dialog.module'; import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; import { DatasetCopyDialogueComponent } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; @@ -20,6 +19,8 @@ import { DatasetDescriptionFormModule } from '@app/ui/misc/dataset-description-f import { TableOfContentsModule } from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.module'; import { ExternalSourcesModule } from '@app/ui/misc/external-sources/external-sources.module'; import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { FormValidationErrorsDialogModule } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.module'; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; import { CommonUiModule } from '@common/ui/common-ui.module'; import { AngularStickyThingsModule } from '@w11k/angular-sticky-things'; @@ -35,7 +36,8 @@ import { AngularStickyThingsModule } from '@w11k/angular-sticky-things'; DatasetDescriptionFormModule, TableOfContentsModule, AngularStickyThingsModule, - DatasetRoutingModule + DatasetRoutingModule, + FormValidationErrorsDialogModule ], declarations: [ DatasetListingComponent, diff --git a/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts b/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts index 35279871e..9a46888aa 100644 --- a/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts +++ b/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts @@ -16,6 +16,7 @@ import { ValidationErrorModel } from '@common/forms/validation/error-model/valid import { TranslateService } from '@ngx-translate/core'; import { Observable, of as observableOf } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; @Component({ @@ -58,6 +59,7 @@ export class DmpCloneComponent extends BaseComponent implements OnInit { this.dmp.project = new ProjectFormModel(); this.dmp.funder = new FunderFormModel(); this.dmp.fromModel(data); + this.dmp.status = DmpStatus.Draft; this.formGroup = this.dmp.buildForm(); this.parentDmpLabel = this.formGroup.get('label').value; diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts index 8cac4012b..950ea4fa9 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts @@ -109,7 +109,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC this.dmp.fromModel(data); this.formGroup = this.dmp.buildForm(); //this.registerFormEventsForDmpProfile(this.dmp.definition); - if (!this.editMode || this.dmp.status === Status.Inactive) { + if (!this.editMode || this.dmp.status === DmpStatus.Finalized) { this.isFinalized = true; this.formGroup.disable(); } @@ -146,7 +146,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC this.dmp.fromModel(data); this.formGroup = this.dmp.buildForm(); //this.registerFormEventsForDmpProfile(this.dmp.definition); - if (!this.editMode || this.dmp.status === Status.Inactive) { this.formGroup.disable(); } + if (!this.editMode || this.dmp.status === DmpStatus.Finalized) { this.formGroup.disable(); } // if (!this.isAuthenticated) { const breadcrumbs = []; breadcrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC-DMPS').toUpperCase(), url: '/plans' }); @@ -271,7 +271,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC onCallbackSuccess(id?: String): void { this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); - id != null ? this.router.navigate(['/plans', 'edit', id]) : this.router.navigate(['/plans']); + id != null ? this.router.navigate(['/reload']).then(() => { this.router.navigate(['/plans', 'edit', id]); }) : this.router.navigate(['/reload']).then(() => { this.router.navigate(['/plans']); }); } onCallbackError(error: any) { diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.model.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.model.ts index 3becc2b75..372ca7250 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.model.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.model.ts @@ -1,7 +1,7 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms"; import { DmpProfileFieldDataType } from '@app/core/common/enum/dmp-profile-field-type'; import { DmpProfileType } from '@app/core/common/enum/dmp-profile-type'; -import { Status } from '@app/core/common/enum/Status'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; import { DatasetModel } from '@app/core/model/dataset/dataset'; import { DmpProfile, DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; import { DmpProfileField } from '@app/core/model/dmp-profile/dmp-profile-field'; @@ -29,7 +29,7 @@ export class DmpEditorModel { public version: number; public lockable: boolean; public creator: UserModel; - public status: Status = Status.Active; + public status: DmpStatus = DmpStatus.Draft; public description: String; public grant: GrantTabModel; public project: ProjectFormModel; diff --git a/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard-editor.model.ts b/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard-editor.model.ts index 7b24cb3d6..4582e91e8 100644 --- a/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard-editor.model.ts +++ b/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard-editor.model.ts @@ -14,6 +14,7 @@ import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-mode import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { ValidationContext } from '@common/forms/validation/validation-context'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; export class DmpWizardEditorModel { public id: string; @@ -23,7 +24,7 @@ export class DmpWizardEditorModel { public version: number; public lockable: boolean; public creator: UserModel; - public status: Status = Status.Active; + public status: DmpStatus = DmpStatus.Draft; public description: String; public grant: GrantTabModel; public funder: FunderFormModel; diff --git a/dmp-frontend/src/app/ui/misc/reload-helper/reload-helper.component.ts b/dmp-frontend/src/app/ui/misc/reload-helper/reload-helper.component.ts new file mode 100644 index 000000000..7709bfdcc --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/reload-helper/reload-helper.component.ts @@ -0,0 +1,9 @@ +import { Component } from "@angular/core"; + +@Component({ + template: "", +}) +export class ReloadHelperComponent { + + constructor() { } +} diff --git a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts index 0ec5bf74c..fa213f870 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts @@ -7,11 +7,12 @@ import { ValidJsonValidator } from '@app/library/auto-complete/auto-complete-cus import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { ValidationContext } from '@common/forms/validation/validation-context'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; export class DmpEditorWizardModel { public id: string; public label: string; - public status: Status = Status.Active; + public status: DmpStatus = DmpStatus.Draft; public description: String; public datasetProfile: DatasetProfileModel; public definition: DmpProfileDefinition; From da031838d61afb3d0b57f434c787a6496c09746c Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Fri, 13 Dec 2019 13:36:25 +0200 Subject: [PATCH 023/106] Adds filter on Datataset's editor DMP selector to only fetch DMPs with "Draft" status. (Issue #213) --- .../app/ui/dataset/dataset-wizard/dataset-wizard.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts index 7b28adb42..80f916a1e 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts @@ -346,6 +346,7 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr const dmpDataTableRequest: DataTableRequest = new DataTableRequest(0, null, { fields: fields }); dmpDataTableRequest.criteria = new DmpCriteria(); dmpDataTableRequest.criteria.like = query; + dmpDataTableRequest.criteria.status = DmpStatus.Draft; return this.dmpService.getPaged(dmpDataTableRequest, "autocomplete").pipe(map(x => x.data)); } From 3bab68265b7cd887ff86066b688efa1c78acccdd Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Fri, 13 Dec 2019 17:05:19 +0200 Subject: [PATCH 024/106] added grant id to displayfn --- .../multiple/multiple-auto-complete.component.ts | 2 +- .../single/single-auto-complete.component.ts | 2 +- .../ui/dmp/editor/grant-tab/grant-tab.component.ts | 12 ++++++++++-- .../grant-editor/grant-editor-wizard.component.ts | 13 +++++++++++-- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts index a81bf3b2f..53a023340 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts @@ -241,8 +241,8 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp onContainerClick(event: MouseEvent) { event.stopPropagation(); - this._onInputFocus(); if (this.disabled) { return; } + this._onInputFocus(); if (!this.autocomplete.isOpen) { this.autocompleteTrigger.openPanel(); } diff --git a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.ts b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.ts index 3d0f8788d..86000d024 100644 --- a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.ts +++ b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.ts @@ -262,8 +262,8 @@ export class SingleAutoCompleteComponent extends _CustomComponentMixinBase imple onContainerClick(event: MouseEvent) { event.stopPropagation(); - this._onInputFocus(); if (this.disabled) { return; } + this._onInputFocus(); if (!this.autocomplete.isOpen) { this.autocompleteTrigger.openPanel(); } diff --git a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts index b39fe23fe..b8e6797a6 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts @@ -45,6 +45,14 @@ export class GrantTabComponent extends BaseComponent implements OnInit { super(); } + getGrantIdText(item) { + if (item.reference != null && typeof item.reference == 'string') { + const parts = (item.reference as String).split('::'); + return parts.length > 1 ? ' (' + parts[parts.length - 1] + ')' : ''; + } + return ''; + } + ngOnInit() { const grantRequestItem: RequestItem = new RequestItem(); @@ -61,8 +69,8 @@ export class GrantTabComponent extends BaseComponent implements OnInit { this.grantAutoCompleteConfiguration = { filterFn: this.searchGrant.bind(this), initialItems: () => this.searchGrant(''), - displayFn: (item) => item['label'], - titleFn: (item) => item['label'], + displayFn: (item) => item['label'] + this.getGrantIdText(item), + titleFn: (item) => item['label'] + this.getGrantIdText(item), subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') }; diff --git a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts index de9f7f666..55b6f6fcc 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts @@ -17,6 +17,7 @@ import { ValidationErrorModel } from '@common/forms/validation/error-model/valid import { TranslateService } from '@ngx-translate/core'; import { Observable, of as observableOf } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; +import { strict } from 'assert'; @Component({ selector: 'app-quick-wizard-grant-editor-component', @@ -44,6 +45,14 @@ export class GrantEditorWizardComponent extends BaseComponent implements OnInit, super(); } + getGrantIdText(item) { + if (item.reference != null && typeof item.reference == 'string') { + const parts = (item.reference as String).split('::'); + return parts.length > 1 ? ' (' + parts[parts.length - 1] + ')' : ''; + } + return ''; + } + ngOnInit() { this.breadCrumbs = observableOf([{ parentComponentName: 'QuickCreate', @@ -57,8 +66,8 @@ export class GrantEditorWizardComponent extends BaseComponent implements OnInit, this.grantAutoCompleteConfiguration = { filterFn: this.searchGrant.bind(this), initialItems: (extraData) => this.searchGrant(''), - displayFn: (item) => item['label'], - titleFn: (item) => item['label'], + displayFn: (item) => item['label'] + this.getGrantIdText(item), + titleFn: (item) => item['label'] + this.getGrantIdText(item), subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') }; From 43134fa959fde3d3f33a716a143437d07b33ecea Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Fri, 13 Dec 2019 17:10:21 +0200 Subject: [PATCH 025/106] Fixes bug not saving properly new External References on Dataset Description. --- .../eudat/controllers/DataRepositories.java | 6 ++--- .../eudat/controllers/ExternalDatasets.java | 5 ++-- .../java/eu/eudat/controllers/Registries.java | 6 ++--- .../java/eu/eudat/controllers/Services.java | 5 ++-- .../datarepository/DataRepositoryModel.java | 1 + .../models/data/dataset/DataRepository.java | 26 +++++++++++++++++++ .../datasetwizard/DatasetWizardModel.java | 12 ++++----- .../ExternalDatasetListingModel.java | 3 +++ .../externaldataset/ExternalDatasetModel.java | 14 +++++----- .../models/data/registries/RegistryModel.java | 9 +++++++ .../dataset-wizard-editor.model.ts | 8 +++--- ...et-external-references-editor.component.ts | 8 +++--- 12 files changed, 72 insertions(+), 31 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DataRepositories.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DataRepositories.java index cd9589615..f6bfed9d3 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DataRepositories.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DataRepositories.java @@ -43,10 +43,10 @@ public class DataRepositories extends BaseController { @Transactional @RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json") public @ResponseBody - ResponseEntity> create(@RequestBody eu.eudat.models.data.datarepository.DataRepositoryModel dataRepositoryModel, Principal principal) throws Exception { + ResponseEntity> create(@RequestBody eu.eudat.models.data.datarepository.DataRepositoryModel dataRepositoryModel, Principal principal) throws Exception { DataRepository dataRepository = this.dataRepositoryManager.create(dataRepositoryModel, principal); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(dataRepository).status(ApiMessageCode.SUCCESS_MESSAGE)); + DataRepositoryModel dataRepositoryModel1 = new DataRepositoryModel().fromDataModel(dataRepository); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(dataRepositoryModel1).status(ApiMessageCode.SUCCESS_MESSAGE)); } - } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/ExternalDatasets.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/ExternalDatasets.java index 532cacdac..642ff7f60 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/ExternalDatasets.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/ExternalDatasets.java @@ -62,8 +62,9 @@ public class ExternalDatasets extends BaseController { @Transactional @RequestMapping(method = RequestMethod.POST, value = {"/externaldatasets"}, consumes = "application/json", produces = "application/json") public @ResponseBody - ResponseEntity> create(@RequestBody eu.eudat.models.data.externaldataset.ExternalDatasetModel externalDatasetModel, Principal principal) throws Exception { + ResponseEntity> create(@RequestBody eu.eudat.models.data.externaldataset.ExternalDatasetModel externalDatasetModel, Principal principal) throws Exception { ExternalDataset externalDataset = this.externalDatasetManager.create(externalDatasetModel, principal); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(externalDataset).status(ApiMessageCode.SUCCESS_MESSAGE)); + ExternalDatasetListingModel externalDatasetListingModel = new ExternalDatasetListingModel().fromDataModel(externalDataset); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(externalDatasetListingModel).status(ApiMessageCode.SUCCESS_MESSAGE)); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/Registries.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/Registries.java index 6289d4f0f..c0a5a58b9 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/Registries.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/Registries.java @@ -42,10 +42,10 @@ public class Registries extends BaseController { @Transactional @RequestMapping(method = RequestMethod.POST, value = {"/registries"}, consumes = "application/json", produces = "application/json") public @ResponseBody - ResponseEntity> create(@RequestBody RegistryModel registryModel, Principal principal) throws Exception { + ResponseEntity> create(@RequestBody RegistryModel registryModel, Principal principal) throws Exception { Registry registry = this.registryManager.create(registryModel, principal); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(registry).status(ApiMessageCode.SUCCESS_MESSAGE)); + RegistryModel registryModel1 = new RegistryModel().fromDataModel(registry); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(registryModel1).status(ApiMessageCode.SUCCESS_MESSAGE)); } - } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/Services.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/Services.java index 02bfd279e..d24928ca1 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/Services.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/Services.java @@ -43,9 +43,10 @@ public class Services extends BaseController { @Transactional @RequestMapping(method = RequestMethod.POST, value = {"/services"}, consumes = "application/json", produces = "application/json") public @ResponseBody - ResponseEntity> create(@RequestBody ServiceModel serviceModel, Principal principal) throws Exception { + ResponseEntity> create(@RequestBody ServiceModel serviceModel, Principal principal) throws Exception { Service service = serviceManager.create(serviceModel, principal); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(service).status(ApiMessageCode.SUCCESS_MESSAGE)); + ServiceModel serviceModel1 = new ServiceModel().fromDataModel(service); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(serviceModel1).status(ApiMessageCode.SUCCESS_MESSAGE)); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/datarepository/DataRepositoryModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/datarepository/DataRepositoryModel.java index 339b6f660..fc8b32c26 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/datarepository/DataRepositoryModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/datarepository/DataRepositoryModel.java @@ -87,6 +87,7 @@ public class DataRepositoryModel implements DataModel, LabelGenerator { + private String id; private String pid; private String name; private String uri; private String info; private String reference; + private String abbreviation; private String tag; private String source; + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public String getPid() { return pid; } @@ -49,6 +59,13 @@ public class DataRepository implements DataModel new Registry().fromDataModel(item)).collect(Collectors.toList()); this.dataRepositories = entity.getDatasetDataRepositories().stream().map(item -> { DataRepository dataRepository = new DataRepository().fromDataModel(item.getDataRepository()); - if(item.getData()!=null) { + if (item.getData() != null) { Map> data = (Map>) JSONValue.parse(item.getData()); Map values = data.get("data"); dataRepository.setInfo(values.get("info")); @@ -171,7 +171,7 @@ public class DatasetWizardModel implements DataModel { ExternalDatasetListingModel externalDatasetListingModel = new ExternalDatasetListingModel().fromDataModel(item.getExternalDataset()); - if(item.getData()!= null) { + if (item.getData() != null) { Map> data = (Map>) JSONValue.parse(item.getData()); Map values = data.get("data"); externalDatasetListingModel.setInfo(values.get("info")); @@ -214,10 +214,10 @@ public class DatasetWizardModel implements DataModel> data = new HashMap<>(); - Map values = new HashMap<>(); - values.put("info",dataRepositoryModel.getInfo()); - data.put("data",values); + Map> data = new HashMap<>(); + Map values = new HashMap<>(); + values.put("info", dataRepositoryModel.getInfo()); + data.put("data", values); datasetDataRepository.setData(JSONValue.toJSONString(data)); entity.getDatasetDataRepositories().add(datasetDataRepository); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/externaldataset/ExternalDatasetListingModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/externaldataset/ExternalDatasetListingModel.java index 2ffc2c525..f874fa74e 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/externaldataset/ExternalDatasetListingModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/externaldataset/ExternalDatasetListingModel.java @@ -140,6 +140,9 @@ public class ExternalDatasetListingModel implements DataModel { public UUID id; - public String label; + public String name; public String abbreviation; public Date created; public Date modified; @@ -22,11 +22,11 @@ public class ExternalDatasetModel implements DataModel { private String uri; private Date created; private Date modified; + private String reference; private String tag; // Api fetching the data private String source; // Actual harvested source @@ -70,6 +71,13 @@ public class RegistryModel implements DataModel { this.modified = modified; } + public String getReference() { + return reference; + } + public void setReference(String reference) { + this.reference = reference; + } + public String getTag() { return tag; } @@ -106,6 +114,7 @@ public class RegistryModel implements DataModel { } else { this.source = source1; } + this.reference = entity.getReference(); return this; } diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard-editor.model.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard-editor.model.ts index 24dc41eb6..341e5e2bb 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard-editor.model.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard-editor.model.ts @@ -203,7 +203,7 @@ export class ExternalServiceEditorModel { buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { return new FormBuilder().group({ id: [this.id], - abbreviation: [this.abbreviation, Validators.required], + abbreviation: [this.abbreviation], label: [this.label, Validators.required], reference: [this.reference], uri: [this.uri, Validators.required], @@ -246,7 +246,7 @@ export class ExternalRegistryEditorModel { buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { return new FormBuilder().group({ id: [this.id], - abbreviation: [this.abbreviation, Validators.required], + abbreviation: [this.abbreviation], label: [this.label, Validators.required], reference: [this.reference], uri: [this.uri, Validators.required], @@ -291,7 +291,7 @@ export class ExternalDatasetEditorModel { buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { return new FormBuilder().group({ id: [this.id], - abbreviation: [this.abbreviation, Validators.required], + abbreviation: [this.abbreviation], name: [this.name, Validators.required], reference: [this.reference], type: [this.type], @@ -336,7 +336,7 @@ export class ExternalDataRepositoryEditorModel { return new FormBuilder().group({ id: [this.id], name: [this.name, [Validators.required]], - abbreviation: [this.abbreviation, [Validators.required]], + abbreviation: [this.abbreviation], uri: [this.uri, [Validators.required]], info: [this.info], reference: [this.reference], diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts index 48d596ead..52f638ae8 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts @@ -139,7 +139,7 @@ export class DatasetExternalReferencesEditorComponent extends BaseComponent impl .pipe(takeUntil(this._destroyed)) .subscribe(result => { if (!result) { return; } - const dataRepositoryModel = new ExternalDataRepositoryEditorModel(result.id, result.name, result.pid, result.uri, result.reference); + const dataRepositoryModel = new ExternalDataRepositoryEditorModel(result.id, result.name, result.abbreviation, result.uri, result.pid, result.source); (this.formGroup.get('dataRepositories')).push(dataRepositoryModel.buildForm()); }); } @@ -154,7 +154,7 @@ export class DatasetExternalReferencesEditorComponent extends BaseComponent impl .pipe(takeUntil(this._destroyed)) .subscribe(result => { if (!result) { return; } - const registryModel = new ExternalRegistryEditorModel(result.abbreviation, result.definition, result.id, result.label, result.reference, result.uri); + const registryModel = new ExternalRegistryEditorModel(result.abbreviation, result.definition, result.id, result.label, result.reference, result.uri, result.source); (this.formGroup.get('registries')).push(registryModel.buildForm()); }); } @@ -169,7 +169,7 @@ export class DatasetExternalReferencesEditorComponent extends BaseComponent impl .pipe(takeUntil(this._destroyed)) .subscribe(result => { if (!result) { return; } - const externalDatasetModel = new ExternalDatasetEditorModel(result.id, result.abbreviation, result.label, result.reference); + const externalDatasetModel = new ExternalDatasetEditorModel(result.id, result.abbreviation, result.name, result.reference, result.source); (this.formGroup.get('externalDatasets')).push(externalDatasetModel.buildForm()); }); } @@ -184,7 +184,7 @@ export class DatasetExternalReferencesEditorComponent extends BaseComponent impl .pipe(takeUntil(this._destroyed)) .subscribe(result => { if (!result) { return; } - const serviceModel = new ExternalServiceEditorModel(result.abbreviation, result.definition, result.id, result.label, result.reference, result.uri); + const serviceModel = new ExternalServiceEditorModel(result.abbreviation, result.definition, result.id, result.label, result.reference, result.uri, result.source); (this.formGroup.get('services')).push(serviceModel.buildForm()); }); } From 72310d8ff142cdf7cd2dac0456eeb87da01c377b Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Fri, 13 Dec 2019 17:40:57 +0200 Subject: [PATCH 026/106] minor fix --- .../dataset-external-references-editor.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts index 52f638ae8..52d127d83 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component.ts @@ -184,7 +184,7 @@ export class DatasetExternalReferencesEditorComponent extends BaseComponent impl .pipe(takeUntil(this._destroyed)) .subscribe(result => { if (!result) { return; } - const serviceModel = new ExternalServiceEditorModel(result.abbreviation, result.definition, result.id, result.label, result.reference, result.uri, result.source); + const serviceModel = new ExternalServiceEditorModel(result.abbreviation, result.definition, result.id, result.label, result.reference, result.uri); (this.formGroup.get('services')).push(serviceModel.buildForm()); }); } From 816ed4dd65fbae0d8f6848828619bd7bb88a2170 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Mon, 16 Dec 2019 12:18:49 +0200 Subject: [PATCH 027/106] Fixes bug not filter out deleted items of DMP and Dataset. Refactors redirect when selecting Grant from Search bar. (Issue #215) --- .../logic/managers/DashBoardManager.java | 3 +++ dmp-frontend/src/app/ui/dmp/dmp.routing.ts | 14 +++++------ .../ui/dmp/listing/dmp-listing.component.ts | 25 ++++++++++++------- .../app/ui/misc/search/search.component.ts | 2 +- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java index d351e492b..ccb9a6060 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java @@ -144,6 +144,7 @@ public class DashBoardManager { CompletableFuture> dmps = dataManagementPlanRepository.getAuthenticated(dataManagementPlanRepository.asQueryable(), principal.getId(), roles) .withHint("dmpRecentActivity") .where((builder, root) -> builder.like(builder.upper(root.get("label")), "%" + like.toUpperCase() + "%")) + .where((builder, root) -> builder.notEqual(root.get("status"), DMP.DMPStatus.DELETED.getValue())) .orderBy((builder, root) -> builder.desc(root.get("modified"))) .selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.DMP.getValue())) .whenComplete((dmpItems, throwable) -> searchBarItems.addAll(dmpItems)); @@ -151,6 +152,8 @@ public class DashBoardManager { CompletableFuture> datasets = datasetRepository.getAuthenticated(datasetRepository.asQueryable(), user) .withHint("datasetRecentActivity") .where((builder, root) -> builder.like(builder.upper(root.get("label")), "%" + like.toUpperCase() + "%")) + .where((builder, root) -> builder.notEqual(root.get("status"), Dataset.Status.DELETED.getValue())) + .where((builder, root) -> builder.notEqual(root.get("status"), Dataset.Status.CANCELED.getValue())) .orderBy((builder, root) -> builder.desc(root.get("modified"))) .selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.DATASET.getValue())) .whenComplete((dataSetItems, throwable) -> searchBarItems.addAll(dataSetItems)); diff --git a/dmp-frontend/src/app/ui/dmp/dmp.routing.ts b/dmp-frontend/src/app/ui/dmp/dmp.routing.ts index dc84fb904..3b3fcb74a 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp.routing.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp.routing.ts @@ -23,13 +23,13 @@ const routes: Routes = [ }, }, // Uncomment to get dmp plans for grant with grantId - // { - // path: 'grant/:grantId', - // component: DmpListingComponent, - // data: { - // breadcrumb: true - // }, - // }, + { + path: 'grant/:grantId', + component: DmpListingComponent, + data: { + breadcrumb: true + }, + }, { path: 'edit/:id', component: DmpEditorComponent, diff --git a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts index 4e05f29a7..060eb213e 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts @@ -18,6 +18,7 @@ import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import { Observable, of as observableOf } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; +import { GrantService } from "@app/core/services/grant/grant.service"; @Component({ selector: 'app-dmp-listing-component', @@ -45,6 +46,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread private dialog: MatDialog, public enumUtils: EnumUtils, private language: TranslateService, + private grantService: GrantService ) { super(); } @@ -56,15 +58,20 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread let grantLabel; if (params['grantId']) { this.grantId = params['grantId']; - this.showGrant = false; - const grant: GrantListingModel = { - id: this.grantId - } - this.criteria.setCriteria({ like: null, grants: [grant], groupIds: null, allVersions: false }); - this.refresh(); - grantLabel = this.route.snapshot.queryParams.grantLabel; - // this.breadCrumbs = Observable.of([{ parentComponentName: 'GrantEditorComponent', label: grantLabel, url: '/grants/edit/' + this.grantId }]); - this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages)); + this.showGrant = true; + this.grantService.getSingle(this.grantId) + .subscribe((grant: GrantListingModel) => { + // const grant: GrantListingModel = { + // id: this.grantId + // } + this.criteria.setCriteria({ like: null, grants: [grant], groupIds: null, allVersions: false }); + + this.refresh(); + grantLabel = this.route.snapshot.queryParams.grantLabel; + // this.breadCrumbs = Observable.of([{ parentComponentName: 'GrantEditorComponent', label: grantLabel, url: '/grants/edit/' + this.grantId }]); + this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages)); + }) + } else { this.itemId = params['groupId']; this.showGrant = true; diff --git a/dmp-frontend/src/app/ui/misc/search/search.component.ts b/dmp-frontend/src/app/ui/misc/search/search.component.ts index f12184af2..7fcba3f4f 100644 --- a/dmp-frontend/src/app/ui/misc/search/search.component.ts +++ b/dmp-frontend/src/app/ui/misc/search/search.component.ts @@ -41,7 +41,7 @@ export class SearchComponent implements OnInit { this.searchControl.patchValue(null); const selectedSearchBarItem = event.option.value; if (selectedSearchBarItem.type === SearchBarType.Dataset) { this.router.navigate(['datasets/edit/' + selectedSearchBarItem.id]); } - if (selectedSearchBarItem.type === SearchBarType.Grant) { this.router.navigate(['grants/edit/' + selectedSearchBarItem.id]); } + if (selectedSearchBarItem.type === SearchBarType.Grant) { this.router.navigate(['plans/grant/' + selectedSearchBarItem.id]); } if (selectedSearchBarItem.type === SearchBarType.Dmp) { this.router.navigate(['plans/edit/' + selectedSearchBarItem.id]); } } From 6cedc40339cd0f4c07ae743823a34b332a8a8e02 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Tue, 17 Dec 2019 13:08:01 +0200 Subject: [PATCH 028/106] Refactors Dataset "Field" from String to Object. --- .../utilities/documents/word/WordBuilder.java | 33 ++++++++++--------- .../documents/xml/ExportXmlBuilder.java | 25 +++++++++----- .../user/components/datasetprofile/Field.java | 31 ++++++++++++----- .../form-field/form-field.component.html | 8 ++--- .../form-field/form-field.component.ts | 20 +++++------ 5 files changed, 71 insertions(+), 46 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java index f8733633a..261ca04d4 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java @@ -25,7 +25,6 @@ import java.math.BigInteger; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; public class WordBuilder { @@ -132,13 +131,13 @@ public class WordBuilder { return document; } - public void createPages(List datasetProfilePages, XWPFDocument mainDocumentPart, Boolean createListing, VisibilityRuleService visibilityRuleService) { + private void createPages(List datasetProfilePages, XWPFDocument mainDocumentPart, Boolean createListing, VisibilityRuleService visibilityRuleService) { datasetProfilePages.forEach(item -> { createSections(item.getSections(), mainDocumentPart, ParagraphStyle.HEADER4, 0, createListing, visibilityRuleService); }); } - public void createSections(List
sections, XWPFDocument mainDocumentPart, ParagraphStyle style, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService) { + private void createSections(List
sections, XWPFDocument mainDocumentPart, ParagraphStyle style, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService) { if (createListing) this.addListing(mainDocumentPart, indent, false, true); sections.forEach(section -> { if (visibilityRuleService.isElementVisible(section.getId())) { @@ -153,7 +152,7 @@ public class WordBuilder { }); } - public void createCompositeFields(List
compositeFields, XWPFDocument mainDocumentPart, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService) { + private void createCompositeFields(List
compositeFields, XWPFDocument mainDocumentPart, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService) { if (createListing) this.addListing(mainDocumentPart, indent, true, true); compositeFields.forEach(compositeField -> { if (visibilityRuleService.isElementVisible(compositeField.getId()) && hasVisibleFields(compositeField, visibilityRuleService)) { @@ -177,7 +176,7 @@ public class WordBuilder { }); } - public void createFields(List fields, XWPFDocument mainDocumentPart, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService) { + private void createFields(List fields, XWPFDocument mainDocumentPart, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService) { if (createListing) this.addListing(mainDocumentPart, indent, false, false); fields.forEach(field -> { if (visibilityRuleService.isElementVisible(field.getId())) { @@ -202,7 +201,7 @@ public class WordBuilder { return paragraph; } - public void addListing(XWPFDocument document, int indent, Boolean question, Boolean hasIndication) { + private void addListing(XWPFDocument document, int indent, Boolean question, Boolean hasIndication) { CTLvl cTLvl = this.cTAbstractNum.addNewLvl(); String textLevel = ""; @@ -222,7 +221,7 @@ public class WordBuilder { } } - public String formatter(Field field) throws IOException { + private String formatter(Field field) throws IOException { switch (field.getViewStyle().getRenderStyle()) { case "combobox": { String comboboxType = ((ComboBoxData) field.getData()).getType(); @@ -232,7 +231,7 @@ public class WordBuilder { Map map = new HashMap<>(); if (!field.getValue().equals("")) { try { - JSONArray jsonarray = new JSONArray(field.getValue()); + JSONArray jsonarray = new JSONArray(field.getValue().toString()); for (int i = 0; i < jsonarray.length(); i++) { JSONObject jsonobject = jsonarray.getJSONObject(i); String id = jsonobject.getString("id"); @@ -241,37 +240,39 @@ public class WordBuilder { map.put(id, label); } } - } catch (Exception e){ - Map exMap = mapper.readValue(field.getValue(), new TypeReference>() { + } catch (Exception e) { + Map exMap = mapper.readValue(field.getValue().toString(), new TypeReference>() { }); return exMap.get("label"); } } StringBuilder sb = new StringBuilder(); + int index = 0; for (Map.Entry entry : map.entrySet()) { - sb.append("\n"); sb.append(entry.getValue()); + if (index != map.size() - 1) sb.append(", "); + index++; } return sb.toString(); } else if (comboboxType.equals("wordlist")) { - return field.getValue(); + return field.getValue().toString(); } } case "booleanDecision": if (field.getValue() != null && field.getValue().equals("true")) return "Yes"; else return "No"; case "radiobox": - return field.getValue(); + return field.getValue().toString(); case "checkBox": CheckBoxData data = (CheckBoxData) field.getData(); if (field.getValue() == null || field.getValue().equals("false")) return null; return data.getLabel(); case "freetext": - return field.getValue(); + return field.getValue().toString(); case "textarea": - return field.getValue(); + return field.getValue().toString(); case "datepicker": - return field.getValue(); + return field.getValue().toString(); } return null; } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/ExportXmlBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/ExportXmlBuilder.java index 3c0f7024f..6f1948853 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/ExportXmlBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/ExportXmlBuilder.java @@ -7,6 +7,8 @@ import eu.eudat.models.data.user.components.datasetprofile.FieldSet; import eu.eudat.models.data.user.components.datasetprofile.Section; import eu.eudat.models.data.user.composite.DatasetProfilePage; import eu.eudat.models.data.user.composite.PagedDatasetProfile; +import org.json.JSONArray; +import org.json.JSONException; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -17,9 +19,6 @@ import java.io.IOException; import java.util.List; import java.util.UUID; -/** - * Created by ikalyvas on 3/5/2018. - */ public class ExportXmlBuilder { public File build(PagedDatasetProfile pagedDatasetProfile, UUID datasetProfileId, VisibilityRuleService visibilityRuleService) throws IOException { @@ -49,7 +48,7 @@ public class ExportXmlBuilder { return pages; } - public Element createSections(List
sections, VisibilityRuleService visibilityRuleService, Document element) { + private Element createSections(List
sections, VisibilityRuleService visibilityRuleService, Document element) { Element elementSections = element.createElement("sections"); sections.forEach(section -> { Element elementSection = element.createElement("section"); @@ -62,7 +61,7 @@ public class ExportXmlBuilder { return elementSections; } - public Element createCompositeFields(List
compositeFields, VisibilityRuleService visibilityRuleService, Document element) { + private Element createCompositeFields(List
compositeFields, VisibilityRuleService visibilityRuleService, Document element) { Element elementComposites = element.createElement("composite-fields"); compositeFields.forEach(compositeField -> { if (visibilityRuleService.isElementVisible(compositeField.getId()) && hasVisibleFields(compositeField, visibilityRuleService)) { @@ -86,15 +85,25 @@ public class ExportXmlBuilder { return elementComposites; } - public Element createFields(List fields, VisibilityRuleService visibilityRuleService, Document element) { + private Element createFields(List fields, VisibilityRuleService visibilityRuleService, Document element) { Element elementFields = element.createElement("fields"); fields.forEach(field -> { if (visibilityRuleService.isElementVisible(field.getId())) { Element elementField = element.createElement("field"); elementField.setAttribute("id", field.getId()); - if (field.getValue() != null && !field.getValue().isEmpty()) { + if (field.getValue() != null) { Element valueField = element.createElement("value"); - valueField.setTextContent(field.getValue()); + try { + JSONArray jsonArray = new JSONArray(field.getValue().toString()); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < jsonArray.length(); i++) { + sb.append(jsonArray.getJSONObject(i).get("label").toString()); + if (i != jsonArray.length() - 1) sb.append(", "); + } + valueField.setTextContent(sb.toString()); + } catch (JSONException ex) { + valueField.setTextContent(field.getValue().toString()); + } elementField.appendChild(valueField); } elementFields.appendChild(elementField); diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/user/components/datasetprofile/Field.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/user/components/datasetprofile/Field.java index ea4301ef6..98680bf0a 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/user/components/datasetprofile/Field.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/user/components/datasetprofile/Field.java @@ -9,6 +9,9 @@ import eu.eudat.models.data.user.composite.PropertiesModelBuilder; import eu.eudat.logic.utilities.interfaces.ViewStyleDefinition; import eu.eudat.logic.utilities.builders.ModelBuilder; +import org.json.JSONArray; +import org.json.JSONException; + import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -17,7 +20,7 @@ import java.util.stream.Collectors; public class Field implements Comparable, PropertiesModelBuilder, ViewStyleDefinition, PropertiesGenerator { private String id; private Integer ordinal; - private String value; + private Object value; private ViewStyle viewStyle; private String datatype; private String numbering; @@ -58,11 +61,11 @@ public class Field implements Comparable, PropertiesModelBuilder, ViewStyleDefin this.ordinal = ordinal; } - public String getValue() { + public Object getValue() { return value; } - public void setValue(String value) { + public void setValue(Object value) { this.value = value; } @@ -146,7 +149,7 @@ public class Field implements Comparable, PropertiesModelBuilder, ViewStyleDefin this.rdaProperty = rdaProperty; } - public Field cloneForMultiplicity(String key, Map properties) { + Field cloneForMultiplicity(String key, Map properties) { Field newField = new Field(); newField.id = key; newField.ordinal = this.ordinal; @@ -189,13 +192,21 @@ public class Field implements Comparable, PropertiesModelBuilder, ViewStyleDefin @Override public void fromJsonObject(Map properties) { - this.value = (String) properties.get(this.id); - this.multiplicityItems = new LinkedList(); + try { + JSONArray jsonArray = new JSONArray(properties.get(this.id).toString()); + List stringList = new LinkedList<>(); + for (int i = 0; i < jsonArray.length(); i++) { + stringList.add(jsonArray.getJSONObject(i).toString()); + } + this.value = stringList; + } catch (JSONException e) { + this.value = (String) properties.get(this.id); + } + this.multiplicityItems = new LinkedList<>(); List compositeKeys = properties.keySet().stream().filter(keys -> keys.startsWith("multiple_" + this.getId())).collect(Collectors.toList()); for (String key : compositeKeys) { this.multiplicityItems.add(this.cloneForMultiplicity(key, properties)); } - } @Override @@ -210,7 +221,11 @@ public class Field implements Comparable, PropertiesModelBuilder, ViewStyleDefin @Override public void toMap(Map fieldValues) { - fieldValues.put(this.id, this.value); + if (this.value != null) { + fieldValues.put(this.id, this.value.toString()); + } else { + fieldValues.put(this.id, ""); + } } @Override diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.html b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.html index b39bd663d..6f5d30659 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.html +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.html @@ -19,7 +19,7 @@
+ [configuration]="multipleAutoCompleteConfiguration">
@@ -47,7 +47,7 @@
+ [configuration]="multipleAutoCompleteConfiguration">
@@ -62,7 +62,7 @@
+ [configuration]="multipleAutoCompleteConfiguration">
@@ -77,7 +77,7 @@
+ [configuration]="multipleAutoCompleteConfiguration">
diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts index 154573b1d..396ed2825 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts @@ -100,16 +100,16 @@ export class FormFieldComponent extends BaseComponent implements OnInit { }); } - _optionRemove(event) { - const array = JSON.parse(this.form.get('value').value); - if (array) { - const index = array.map(x => x.id).indexOf(event.id); - if (index >= 0) { - array.splice(index, 1); - } - this.form.get('value').patchValue(JSON.stringify(array)); - } - } + // _optionRemove(event) { + // const array = JSON.parse(this.form.get('value').value); + // if (array) { + // const index = array.map(x => x.id).indexOf(event.id); + // if (index >= 0) { + // array.splice(index, 1); + // } + // this.form.get('value').patchValue(JSON.stringify(array)); + // } + // } _transformValue(item: any) { if (!item) return []; From c272644c612b4bce635cfb8fa5e0a55a734f0b70 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Tue, 17 Dec 2019 14:15:12 +0200 Subject: [PATCH 029/106] Fixes bug on Grant Tab's validation when creating a new DMP. --- .../src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts index b8e6797a6..9920011fd 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts @@ -200,6 +200,7 @@ export class GrantTabComponent extends BaseComponent implements OnInit { if ((funder.label !== "" && funder.label != null && funder.label !== undefined) || (funder.existFunder !== null && funder.existFunder !== undefined && funder.existFunder.id !== undefined)) { this.grantformGroup.enable(); + this.setGrantValidators(); } else { this.grantformGroup.reset(); From 4efdf42b943393bc97a5f7d6c3b4875348ea798a Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Tue, 17 Dec 2019 16:19:30 +0200 Subject: [PATCH 030/106] Fixes search bar redirect url when a DMP is selected. (Issue #215) --- dmp-frontend/src/app/ui/misc/search/search.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmp-frontend/src/app/ui/misc/search/search.component.ts b/dmp-frontend/src/app/ui/misc/search/search.component.ts index 7fcba3f4f..0fdad5a9a 100644 --- a/dmp-frontend/src/app/ui/misc/search/search.component.ts +++ b/dmp-frontend/src/app/ui/misc/search/search.component.ts @@ -42,7 +42,7 @@ export class SearchComponent implements OnInit { const selectedSearchBarItem = event.option.value; if (selectedSearchBarItem.type === SearchBarType.Dataset) { this.router.navigate(['datasets/edit/' + selectedSearchBarItem.id]); } if (selectedSearchBarItem.type === SearchBarType.Grant) { this.router.navigate(['plans/grant/' + selectedSearchBarItem.id]); } - if (selectedSearchBarItem.type === SearchBarType.Dmp) { this.router.navigate(['plans/edit/' + selectedSearchBarItem.id]); } + if (selectedSearchBarItem.type === SearchBarType.Dmp) { this.router.navigate(['plans/overview/' + selectedSearchBarItem.id]); } } transformType(type) { From 4e3a3b573af8fb98214a3221abc462ad5eaaef22 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Tue, 17 Dec 2019 18:17:21 +0200 Subject: [PATCH 031/106] Fixes bug on fetching Datasets. --- .../eudat/models/data/user/components/datasetprofile/Field.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/user/components/datasetprofile/Field.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/user/components/datasetprofile/Field.java index 98680bf0a..4950261c4 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/user/components/datasetprofile/Field.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/user/components/datasetprofile/Field.java @@ -199,7 +199,7 @@ public class Field implements Comparable, PropertiesModelBuilder, ViewStyleDefin stringList.add(jsonArray.getJSONObject(i).toString()); } this.value = stringList; - } catch (JSONException e) { + } catch (JSONException | NullPointerException e) { this.value = (String) properties.get(this.id); } this.multiplicityItems = new LinkedList<>(); From e50bef555f1106cad4c4b54ae0e2beffbe7a0ff6 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Wed, 18 Dec 2019 10:55:08 +0200 Subject: [PATCH 032/106] Adds missing properties "Funder" and "Project" from DMP xml export. --- .../managers/DataManagementPlanManager.java | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index 678b10a26..fcb0a973c 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -567,7 +567,7 @@ public class DataManagementPlanManager { } - public void assignUser(DMP dmp, UserInfo userInfo) { + private void assignUser(DMP dmp, UserInfo userInfo) { UserDMP userDMP = new UserDMP(); userDMP.setDmp(dmp); userDMP.setUser(userInfo); @@ -835,7 +835,7 @@ public class DataManagementPlanManager { } } - public FileEnvelope getXmlDocument(String id, Principal principal) throws InstantiationException, IllegalAccessException, IOException { + private FileEnvelope getXmlDocument(String id, Principal principal) throws InstantiationException, IllegalAccessException, IOException { ExportXmlBuilder xmlBuilder = new ExportXmlBuilder(); VisibilityRuleService visibilityRuleService = utilitiesService.getVisibilityRuleService(); eu.eudat.data.entities.DMP dmp = databaseRepository.getDmpDao().find(UUID.fromString(id)); @@ -870,14 +870,34 @@ public class DataManagementPlanManager { } dmpElement.appendChild(dmpProfileElement); + // Funder. + Element funder = xmlDoc.createElement("funder"); + Element funderLabel = xmlDoc.createElement("label"); + Element funderId = xmlDoc.createElement("id"); + funderLabel.setTextContent(dmp.getGrant().getFunder().getLabel()); + funderId.setTextContent(dmp.getGrant().getFunder().getId().toString()); + funder.appendChild(funderLabel); + funder.appendChild(funderId); + dmpElement.appendChild(funder); + // Grant. Element grant = xmlDoc.createElement("grant"); - Element label = xmlDoc.createElement("label"); - label.setTextContent(dmp.getGrant().getLabel()); - grant.appendChild(label); + Element grantLabel = xmlDoc.createElement("label"); Element grantId = xmlDoc.createElement("id"); + grantLabel.setTextContent(dmp.getGrant().getLabel()); grantId.setTextContent(dmp.getGrant().getId().toString()); + grant.appendChild(grantLabel); grant.appendChild(grantId); dmpElement.appendChild(grant); + // Project. + Element project = xmlDoc.createElement("project"); + Element projectLabel = xmlDoc.createElement("label"); + Element projectId = xmlDoc.createElement("id"); + projectLabel.setTextContent(dmp.getProject().getLabel()); + projectId.setTextContent(dmp.getProject().getId().toString()); + project.appendChild(projectLabel); + project.appendChild(projectId); + dmpElement.appendChild(project); + Element organisationsElement = xmlDoc.createElement("organisations"); for (Organisation organisation : dmp.getOrganisations()) { Element organisationElement = xmlDoc.createElement("organisation"); From 9aed05d574ab337939c47b3cf45d516ae261c3e8 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Wed, 18 Dec 2019 12:38:04 +0200 Subject: [PATCH 033/106] Adds backend validation so that only creator can edit one DMP. --- .../logic/managers/DataManagementPlanManager.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index fcb0a973c..7bdb35e7e 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -69,9 +69,7 @@ import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import java.io.*; import java.math.BigInteger; -import java.net.URL; import java.nio.file.Files; -import java.nio.file.Paths; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -106,7 +104,6 @@ public class DataManagementPlanManager { CompletableFuture itemsFuture; if (fieldsGroup.equals("listing")) { - itemsFuture = pagedItems.withHint(HintedModelFactory.getHint(DataManagementPlanListingModel.class)) .selectAsync(item -> { item.setDataset( @@ -127,7 +124,7 @@ public class DataManagementPlanManager { } CompletableFuture countFuture = authItems.countAsync().whenComplete((count, throwable) -> - dataTable.setTotalCount(count) + dataTable.setTotalCount(count) ); CompletableFuture.allOf(itemsFuture, countFuture).join(); return dataTable; @@ -479,10 +476,13 @@ public class DataManagementPlanManager { if (dataManagementPlan.getId() != null) { DMP dmp1 = apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().find(dataManagementPlan.getId()); + if (!isUserOwnerOfDmp(dmp1, principal)) { + throw new Exception("User not being the creator is not authorized to edit this DMP."); + } List datasetList = new ArrayList<>(dmp1.getDataset()); for (Dataset dataset : datasetList) { if (dataManagementPlan.getProfiles().stream().filter(associatedProfile -> dataset.getProfile().getId().equals(associatedProfile.getId())).findAny().orElse(null) == null) - throw new Exception("Dataset Template for Dataest Description is missing from the DMP."); + throw new Exception("Dataset Template for Dataset Description is missing from the DMP."); } if (dataManagementPlan.getStatus() == (int) DMP.DMPStatus.FINALISED.getValue() && dmp1.getStatus().equals(DMP.DMPStatus.FINALISED.getValue())) throw new Exception("DMP is finalized, therefore cannot be edited."); From d70e8d46c5cb517acf66ba8ebd04c42ae65aa43d Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Wed, 18 Dec 2019 16:28:48 +0200 Subject: [PATCH 034/106] Adds restrictions on DMP overview when user not creator. --- .../app/ui/dmp/overview/dmp-overview.component.html | 12 ++++++------ .../app/ui/dmp/overview/dmp-overview.component.ts | 10 ++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html index ebb4aef52..2c36bd6d8 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html @@ -11,7 +11,7 @@ more_horiz - -
- - - - diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts index 8c6a92406..e627ff5a4 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts @@ -20,6 +20,7 @@ import { TranslateService } from '@ngx-translate/core'; import * as FileSaver from 'file-saver'; import { Observable, of as observableOf } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; +import { Role } from "@app/core/common/enum/role"; @Component({ selector: 'app-dmp-overview', @@ -34,6 +35,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { isPublicView = true; hasPublishButton: boolean = true; breadCrumbs: Observable = observableOf(); + isUserOwner: boolean; constructor( private route: ActivatedRoute, @@ -62,6 +64,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { .pipe(takeUntil(this._destroyed)) .subscribe(data => { this.dmp = data; + this.setIsUserOwner(); const breadCrumbs = []; breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DMPS'), url: "/plans" }); breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/overview/' + this.dmp.id }); @@ -85,6 +88,13 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { }); } + setIsUserOwner() { + if (this.dmp) { + const principal: Principal = this.authentication.current(); + this.isUserOwner = principal.id === this.dmp.users.find(x => x.role === Role.Owner).id; + } + } + editClicked(dmp: DmpOverviewModel) { this.router.navigate(['/plans/edit/' + dmp.id]); } From c8600b315e320b32c2e992774ed9bb2cdeb9ba15 Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Wed, 18 Dec 2019 17:37:00 +0200 Subject: [PATCH 035/106] autocomplete fix --- .../multiple-auto-complete.component.ts | 14 +++++++------- .../form-field/form-field.component.ts | 17 ++++++----------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts index 53a023340..245f1d2be 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts @@ -135,16 +135,16 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp getSelectedItems(value: any) { if (value != null && Array.isArray(value) && this.configuration) { - const newSelections = value.filter(x => !this._selectedItems.has(JSON.stringify(x))); + const newSelections = value.filter(x => !this._selectedItems.has(this.stringify(x))); if (newSelections.length > 0 && this.configuration.getSelectedItems != null) { this.configuration.getSelectedItems(newSelections).pipe(takeUntil(this._destroyed)).subscribe(x => { x.forEach(element => { - this._selectedItems.set(JSON.stringify(this.configuration.valueAssign != null ? this.configuration.valueAssign(element) : element), element); + this._selectedItems.set(this.stringify(this.configuration.valueAssign != null ? this.configuration.valueAssign(element) : element), element); }); }); } else { newSelections.forEach(element => { - this._selectedItems.set(JSON.stringify(this.configuration.valueAssign != null ? this.configuration.valueAssign(element) : element), element); + this._selectedItems.set(this.stringify(this.configuration.valueAssign != null ? this.configuration.valueAssign(element) : element), element); }); } } @@ -166,7 +166,7 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp } stringify(value: any): string { - return JSON.stringify(value); + return typeof (value) == 'string' ? value : JSON.stringify(value); } isNullOrEmpty(query: string): boolean { @@ -182,7 +182,7 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp const newValue = this._valueToAssign(item); //Update selected items - this._selectedItems.set(JSON.stringify(newValue), item); + this._selectedItems.set(this.stringify(newValue), item); const newValueArray = (Array.isArray(this.value) ? this.value : []); newValueArray.push(newValue); @@ -319,11 +319,11 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp _removeSelectedItem(item: any, event: MouseEvent): void { if (event != null) { event.stopPropagation(); } const valueToDelete = this._valueToAssign(item); - this.value = this.value.filter(x => JSON.stringify(x) !== JSON.stringify(valueToDelete)); //TODO, maybe we need to implement equality here differently. + this.value = this.value.filter(x => this.stringify(x) !== this.stringify(valueToDelete)); //TODO, maybe we need to implement equality here differently. this.optionRemoved.emit(item); //Update chips - this._selectedItems.delete(JSON.stringify(valueToDelete)); + this._selectedItems.delete(this.stringify(valueToDelete)); this.autocompleteInput.nativeElement.focus(); this.pushChanges(this.value); diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts index 396ed2825..62019e028 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts @@ -72,9 +72,9 @@ export class FormFieldComponent extends BaseComponent implements OnInit { this.multipleAutoCompleteConfiguration = { filterFn: this.searchFromAutocomplete.bind(this), initialItems: () => this.searchFromAutocomplete(''), - displayFn: (item) => item['label'], - titleFn: (item) => item['label'], - valueAssign: this._transformValue, + displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'], + titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'], + valueAssign: (item) => typeof (item) == 'string' ? item : JSON.stringify(item), subtitleFn: (item) => item['source'] ? this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-SUBTITLE') + item['source'] : this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-NO-SOURCE') } } @@ -111,11 +111,6 @@ export class FormFieldComponent extends BaseComponent implements OnInit { // } // } - _transformValue(item: any) { - if (!item) return []; - return item && typeof item === 'string' ? JSON.parse(item) : JSON.stringify(item); - } - searchFromAutocomplete(query: string) { const autocompleteRequestItem: RequestItem = new RequestItem(); autocompleteRequestItem.criteria = new DatasetExternalAutocompleteCriteria(); @@ -164,9 +159,9 @@ export class FormFieldComponent extends BaseComponent implements OnInit { this.multipleAutoCompleteConfiguration = { filterFn: myfunc.bind(this), initialItems: (extraData) => myfunc(''), - displayFn: (item) => item[title], - titleFn: (item) => item[title], - valueAssign: this._transformValue, + displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'], + titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'], + valueAssign: (item) => typeof (item) == 'string' ? item : JSON.stringify(item), subtitleFn: (item) => item[subtitle] } } From 61a7f0b80983c6432d80cb7da4fa3a42435000d4 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 19 Dec 2019 12:10:16 +0200 Subject: [PATCH 036/106] Adds Collaborators panel on DMP Overview. --- .../dmp/overview/dmp-overview.component.html | 13 ++++++++++++- .../dmp/overview/dmp-overview.component.scss | 19 +++++++++++++++++++ .../ui/dmp/overview/dmp-overview.component.ts | 18 ++++++++++++------ dmp-frontend/src/assets/i18n/en.json | 4 +++- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html index 2c36bd6d8..22ab7474a 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html @@ -81,7 +81,7 @@
settings -

{{ roleDisplay(dmp.users) }}

+

{{ roleDisplayFromList(dmp.users) }}

@@ -110,6 +110,11 @@

{{ dmp.researchers.length }}

{{ 'DMP-EDITOR.FIELDS.RESEARCHERS' | translate }}

+
+ person +

{{ dmp.users.length }}

+

{{ 'DMP-EDITOR.FIELDS.COLLABORATORS' | translate }}

+
@@ -157,6 +162,12 @@
{{ researcher.name }}
+
+
{{'DMP-OVERVIEW.COLLABORATORS' | translate}}
+
+
{{ user.name }}
+
+
diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.scss b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.scss index 8e5b8b8e1..c06a7179f 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.scss +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.scss @@ -66,6 +66,25 @@ text-transform: uppercase; } +.collaborators { + display: flex; + flex-direction: column; + border: 2px solid #f2f2f2; + margin-right: 2em; + margin-top: 2em; + padding: 0.5em; + } + + .collaborators-title { + width: 135px; + color: #089dbb; + background-color: white; + padding: 0px 10px; + margin-top: -16px; + cursor: default; + text-transform: uppercase; + } + .container-header { display: flex; align-items: baseline; diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts index e627ff5a4..20da2f5be 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts @@ -12,7 +12,7 @@ import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; import { AuthService } from '@app/core/services/auth/auth.service'; import { DmpService } from '@app/core/services/dmp/dmp.service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; -import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { DmpFinalizeDialogComponent, DmpFinalizeDialogInput, DmpFinalizeDialogOutput } from '@app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { BaseComponent } from '@common/base/base.component'; @@ -219,7 +219,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { return filename; } - roleDisplay(value: UserInfoListingModel[]) { + roleDisplayFromList(value: UserInfoListingModel[]) { const principal: Principal = this.authentication.current(); let role: number; if (principal) { @@ -229,13 +229,19 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { } }); } - if (role === 0) { + if (role === Role.Owner) { + return this.translate.instant('DMP-LISTING.OWNER'); + } else if (role === Role.Member) { + return this.translate.instant('DMP-LISTING.MEMBER'); + } else { return this.translate.instant('DMP-LISTING.OWNER'); } - else if (role === 1) { + } + + roleDisplay(value: UserInfoListingModel) { + if (value.role === Role.Member) { return this.translate.instant('DMP-LISTING.MEMBER'); - } - else { + } else { return this.translate.instant('DMP-LISTING.OWNER'); } } diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 03a240d41..acdd24fcf 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -489,6 +489,7 @@ }, "DMP-OVERVIEW": { "RESEARCHERS": "Researchers", + "COLLABORATORS": "Collaborators", "TOOLTIP": { "LEVEL-OF-ACCESS": "Level of Access", "INVOLVED-DATASETS": "Involved Dataset Descriptions", @@ -662,7 +663,8 @@ "GRANT": "Grant", "FUNDER": "Funder", "STATUS": "DMP Status", - "EXTERNAL-SOURCE-HINT": "List of values provided by external source(s)" + "EXTERNAL-SOURCE-HINT": "List of values provided by external source(s)", + "COLLABORATORS": "Collaborators" }, "ACTIONS": { "GO-TO-GRANT": "Go To DMP Grant", From ca160ccd22a12b75ee1e9cc7ab12ba9b414a311f Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 19 Dec 2019 12:28:11 +0200 Subject: [PATCH 037/106] Fixes bug showing Collaborators on published DMPs. --- .../src/app/ui/dmp/overview/dmp-overview.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html index 22ab7474a..339633493 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html @@ -162,7 +162,7 @@
{{ researcher.name }}
-
+
{{'DMP-OVERVIEW.COLLABORATORS' | translate}}
{{ user.name }}
From 3a58234282909abd6613a642a3c53b56589d381c Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 19 Dec 2019 13:08:20 +0200 Subject: [PATCH 038/106] Fixes bug on Dataset Description listing, fetching extra wrong items when "Member" criteria was selected. --- .../java/eu/eudat/data/dao/entities/DatasetDao.java | 3 ++- .../eu/eudat/data/dao/entities/DatasetDaoImpl.java | 12 +++++++++--- .../eu/eudat/logic/managers/DashBoardManager.java | 6 +++--- .../java/eu/eudat/logic/managers/DatasetManager.java | 4 +++- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDao.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDao.java index b3e81ec03..bcf5d134f 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDao.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDao.java @@ -6,13 +6,14 @@ import eu.eudat.data.entities.Dataset; import eu.eudat.data.entities.UserInfo; import eu.eudat.queryable.QueryableList; +import java.util.List; import java.util.UUID; public interface DatasetDao extends DatabaseAccessLayer { QueryableList getWithCriteria(DatasetCriteria criteria); - QueryableList getAuthenticated(QueryableList query, UserInfo principal); + QueryableList getAuthenticated(QueryableList query, UserInfo principal, List roles); Dataset isPublicDataset(UUID id); diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java index 1a68dcead..624180e11 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java @@ -13,8 +13,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; +import javax.persistence.criteria.Join; import javax.persistence.criteria.JoinType; import java.util.Arrays; +import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -87,9 +89,13 @@ public class DatasetDaoImpl extends DatabaseAccess implements DatasetDa } @Override - public QueryableList getAuthenticated(QueryableList query, UserInfo principal) { - if (principal.getId() == null) query.where((builder, root) -> builder.equal(root.get("isPublic"), true)); - else { + public QueryableList getAuthenticated(QueryableList query, UserInfo principal, List roles) { + if (roles != null && !roles.isEmpty()) { + query.where((builder, root) -> { + Join userJoin = root.join("dmp", JoinType.LEFT).join("users", JoinType.LEFT); + return builder.and(builder.equal(userJoin.join("user", JoinType.LEFT).get("id"), principal.getId()), userJoin.get("role").in(roles)); + }); + } else { query.where((builder, root) -> builder.equal(root.join("dmp", JoinType.LEFT).join("users", JoinType.LEFT).join("user", JoinType.LEFT).get("id"), principal.getId())); } return query; diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java index ccb9a6060..ae3cd99f1 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java @@ -80,7 +80,7 @@ public class DashBoardManager { List roles = new LinkedList<>(); CompletableFuture dmpFuture = dataManagementPlanRepository.getAuthenticated(dataManagementPlanRepository.getWithCriteria(dataManagementPlanCriteria), principal.getId(), roles).countAsync() .whenComplete((dmpsStats, throwable) -> statistics.setTotalDataManagementPlanCount(dmpsStats)); - CompletableFuture datasetFuture = datasetRepository.getAuthenticated(datasetRepository.getWithCriteria(datasetCriteria), user).countAsync() + CompletableFuture datasetFuture = datasetRepository.getAuthenticated(datasetRepository.getWithCriteria(datasetCriteria), user, roles).countAsync() .whenComplete((datasetsStats, throwable) -> statistics.setTotalDataSetCount(datasetsStats)); CompletableFuture grantFuture = grantRepository.getAuthenticated(grantRepository.getWithCriteria(grantCriteria), user).countAsync() .whenComplete((grantsStats, throwable) -> statistics.setTotalGrantCount(grantsStats)); @@ -113,7 +113,7 @@ public class DashBoardManager { .selectAsync(item -> recentActivityDataBuilder.label(item.getLabel()).timestamp(item.getModified()).id(item.getId().toString()).build()) .whenComplete((dmpActivities, throwable) -> activity.setRecentDmpActivities(dmpActivities)); - CompletableFuture> datasets = datasetRepository.getAuthenticated(datasetRepository.getWithCriteria(datasetCriteria), user) + CompletableFuture> datasets = datasetRepository.getAuthenticated(datasetRepository.getWithCriteria(datasetCriteria), user, roles) .withHint("datasetRecentActivity") .orderBy((builder, root) -> builder.desc(root.get("modified"))) .take(numberofactivities) @@ -149,7 +149,7 @@ public class DashBoardManager { .selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.DMP.getValue())) .whenComplete((dmpItems, throwable) -> searchBarItems.addAll(dmpItems)); - CompletableFuture> datasets = datasetRepository.getAuthenticated(datasetRepository.asQueryable(), user) + CompletableFuture> datasets = datasetRepository.getAuthenticated(datasetRepository.asQueryable(), user, roles) .withHint("datasetRecentActivity") .where((builder, root) -> builder.like(builder.upper(root.get("label")), "%" + like.toUpperCase() + "%")) .where((builder, root) -> builder.notEqual(root.get("status"), Dataset.Status.DELETED.getValue())) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java index 3a1d2e8f8..4ae589f0b 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java @@ -109,7 +109,9 @@ public class DatasetManager { } else items.where((builder, root) -> root.get("id").in(new UUID[]{UUID.randomUUID()})); } - QueryableList authItems = databaseRepository.getDatasetDao().getAuthenticated(items, userInfo); + List roles = new LinkedList<>(); + if (datasetTableRequest.getCriteria().getRole() != null) roles.add(datasetTableRequest.getCriteria().getRole()); + QueryableList authItems = databaseRepository.getDatasetDao().getAuthenticated(items, userInfo, roles); QueryableList pagedItems = PaginationManager.applyPaging(authItems, datasetTableRequest); DataTableData dataTable = new DataTableData(); From 655f2a44561148e2cbb720b416570ed8520de8bc Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 19 Dec 2019 15:26:53 +0200 Subject: [PATCH 039/106] Fixes bug of duplicating "role"criteria on Dataset listing query. --- .../main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java index 624180e11..6c56fe514 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java @@ -45,11 +45,11 @@ public class DatasetDaoImpl extends DatabaseAccess implements DatasetDa query.initSubQuery(String.class).where((builder, root) -> builder.equal(root.get("dmp").get("version"), query.subQueryMax((builder1, externalRoot, nestedRoot) -> builder1.equal(externalRoot.get("dmp").get("groupId"), nestedRoot.get("dmp").get("groupId")), Arrays.asList(new SelectionField(FieldSelectionType.COMPOSITE_FIELD, "dmp:version")), String.class))); if (criteria.getDmpIds() != null && !criteria.getDmpIds().isEmpty()) query.where((builder, root) -> root.get("dmp").get("id").in(criteria.getDmpIds())); - if (criteria.getRole() != null) { + /*if (criteria.getRole() != null) { query.where((builder, root) -> builder.equal(root.join("dmp").join("users").get("role"), criteria.getRole())); } else { query.where((builder, root) -> root.join("dmp").join("users").get("role").in(UserDMP.UserDMPRoles.getAllValues())); - } + }*/ if (criteria.getOrganisations() != null && !criteria.getOrganisations().isEmpty()) query.where((builder, root) -> root.join("dmp").join("organisations").get("reference").in(criteria.getOrganisations())); if (criteria.getGrants() != null && !criteria.getGrants().isEmpty()) From 462f6dcb6162df3ac37391d372a934752716db32 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 19 Dec 2019 15:27:16 +0200 Subject: [PATCH 040/106] Language fix. --- dmp-frontend/src/assets/i18n/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index acdd24fcf..004541b29 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -891,7 +891,7 @@ "DATASET-PROFILE-COMBO-BOX-TYPE": { "WORD-LIST": "Word List", "AUTOCOMPLETE": "Autocomplete", - "EXTERNAL-SOURCE-HINT": "External source", + "EXTERNAL-SOURCE-HINT": "List of values provided by external source(s)", "ACTIONS": { "YES": "Yes", "NO": "No" @@ -901,7 +901,7 @@ "RESEARCHERS": "Researchers", "DMPS": "DMPs", "DATASETS": "Dataset Descriptions", - "EXTERNAL-SOURCE-HINT": "External source" + "EXTERNAL-SOURCE-HINT": "List of values provided by external source(s)" } }, "ADDRESEARCHERS-EDITOR": { From 4daa6c4eb268add1a3ea41280c24d49c413d1411 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 19 Dec 2019 15:48:24 +0200 Subject: [PATCH 041/106] Adds restrictions on DMP edit view when user not creator. --- .../ui/dmp/editor/dmp-editor.component.html | 10 +++++----- .../app/ui/dmp/editor/dmp-editor.component.ts | 20 ++++++++++++++++--- .../dynamic-dmp-field-resolver.component.ts | 1 + .../general-tab/general-tab.component.html | 2 +- .../general-tab/general-tab.component.ts | 5 +++++ .../editor/grant-tab/grant-tab.component.html | 6 +++--- .../editor/grant-tab/grant-tab.component.ts | 7 ++++--- 7 files changed, 36 insertions(+), 15 deletions(-) diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.html b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.html index e96507cb5..f26d1fa67 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.html @@ -13,16 +13,16 @@ more_horiz - - - @@ -58,14 +58,14 @@ view_agenda {{ 'SIDE-BAR.GENERAL' | translate }} - + work_outline {{ 'DMP-LISTING.COLUMNS.GRANT' | translate }} - + diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts index 950ea4fa9..ef5a0d350 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts @@ -4,7 +4,6 @@ import { FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Params, Router } from '@angular/router'; import { DmpStatus } from '@app/core/common/enum/dmp-status'; -import { Status } from '@app/core/common/enum/Status'; import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; import { DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; import { DmpProfileListing } from '@app/core/model/dmp-profile/dmp-profile-listing'; @@ -19,7 +18,7 @@ import { AuthService } from '@app/core/services/auth/auth.service'; import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; import { DmpService } from '@app/core/services/dmp/dmp.service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; -import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { DmpEditorModel } from '@app/ui/dmp/editor/dmp-editor.model'; import { DmpFinalizeDialogComponent, DmpFinalizeDialogInput } from '@app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; @@ -35,7 +34,8 @@ import { TranslateService } from '@ngx-translate/core'; import * as FileSaver from 'file-saver'; import { Observable, of as observableOf } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import { Guid } from '@common/types/guid'; +import { Principal } from "@app/core/model/auth/Principal"; +import { Role } from "@app/core/common/enum/role"; @Component({ selector: 'app-dmp-editor-component', @@ -61,6 +61,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC filteredOptions: DmpProfileListing[]; selectedDmpProfileDefinition: DmpProfileDefinition; DynamicDmpFieldResolverComponent: any; + isUserOwner: boolean = true; constructor( private dmpProfileService: DmpProfileService, @@ -70,6 +71,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC private language: TranslateService, private dialog: MatDialog, private uiNotificationService: UiNotificationService, + private authentication: AuthService, private authService: AuthService, private formService: FormService ) { @@ -108,6 +110,11 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC this.dmp.funder = new FunderFormModel(); this.dmp.fromModel(data); this.formGroup = this.dmp.buildForm(); + this.setIsUserOwner(); + if (this.isUserOwner) { + this.isFinalized = true; + this.formGroup.disable(); + } //this.registerFormEventsForDmpProfile(this.dmp.definition); if (!this.editMode || this.dmp.status === DmpStatus.Finalized) { this.isFinalized = true; @@ -201,6 +208,13 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC return this.authService.current() != null; } + setIsUserOwner() { + if (this.dmp) { + const principal: Principal = this.authentication.current(); + this.isUserOwner = principal.id === this.dmp.users.find(x => x.role === Role.Owner).id; + } + } + registerFormEventsForNewItem() { this.breadCrumbs = observableOf([ { diff --git a/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.ts index d95540f87..23ff93644 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.ts @@ -26,6 +26,7 @@ export class DynamicDmpFieldResolverComponent implements OnInit, OnDestroy { @Input() dmpProfileId: string; @Input() dmpProfileDefinition: DmpProfileDefinition; @Input() formGroup: FormGroup; + @Input() isUserOwner: boolean; constructor( private dmpProfileService: DmpProfileService diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html index 2683c7562..a1090650e 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html @@ -68,7 +68,7 @@
- +
diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts index 1990eb528..63c146f4b 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts @@ -30,6 +30,7 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { @Input() formGroup: FormGroup = null; @Input() isNewVersion: boolean; + @Input() isUserOwner: boolean; profilesAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { filterFn: this.filterProfiles.bind(this), @@ -80,6 +81,10 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { if (this.isNewVersion) { this.formGroup.get('label').disable(); } + + if (!this.isUserOwner) { + this.formGroup.disable(); + } } registerFormEventsForDmpProfile(definitionProperties?: DmpProfileDefinition): void { diff --git a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.html b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.html index e4f7ae5a2..b2b8c4356 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.html @@ -24,7 +24,7 @@
-
+
settings_backup_restore {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.EXIST-FUNDER' | translate}} @@ -63,7 +63,7 @@
-
+
settings_backup_restore {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.EXIST-GRANT' | translate}} @@ -104,7 +104,7 @@
-
+
settings_backup_restore {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.EXIST-PROJECT' | translate}} diff --git a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts index 9920011fd..cf9d454ff 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts @@ -26,6 +26,7 @@ export class GrantTabComponent extends BaseComponent implements OnInit { @Input() isFinalized: boolean; @Input() isNewVersion: boolean; @Input() isNew: boolean; + @Input() isUserOwner: boolean; isCreateNew = false; isCreateNewProject = false; @@ -143,7 +144,7 @@ export class GrantTabComponent extends BaseComponent implements OnInit { this.grantformGroup.get('existGrant').disable(); this.grantformGroup.get('label').enable(); this.grantformGroup.get('description').enable(); - } else if (this.isFinalized || this.isNewVersion) { + } else if (this.isFinalized || this.isNewVersion || !this.isUserOwner) { this.grantformGroup.get('existGrant').disable(); this.grantformGroup.get('label').disable(); this.grantformGroup.get('description').disable(); @@ -161,7 +162,7 @@ export class GrantTabComponent extends BaseComponent implements OnInit { this.projectFormGroup.get('existProject').disable(); this.projectFormGroup.get('label').enable(); this.projectFormGroup.get('description').enable(); - } else if (this.isFinalized || this.isNewVersion) { + } else if (this.isFinalized || this.isNewVersion || !this.isUserOwner) { this.projectFormGroup.get('existProject').disable(); this.projectFormGroup.get('label').disable(); this.projectFormGroup.get('description').disable(); @@ -178,7 +179,7 @@ export class GrantTabComponent extends BaseComponent implements OnInit { if (this.isCreateNewFunder) { this.funderFormGroup.get('existFunder').disable(); this.funderFormGroup.get('label').enable(); - } else if (this.isFinalized || this.isNewVersion) { + } else if (this.isFinalized || this.isNewVersion || !this.isUserOwner) { this.funderFormGroup.get('existFunder').disable(); this.funderFormGroup.get('label').disable(); } else { From b6b2c9309609acd2d39880fc297bc00991724add Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Fri, 20 Dec 2019 12:18:57 +0200 Subject: [PATCH 042/106] Fixes bug of disabled form on DMP editor. --- dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts index ef5a0d350..bf196de0c 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts @@ -111,7 +111,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC this.dmp.fromModel(data); this.formGroup = this.dmp.buildForm(); this.setIsUserOwner(); - if (this.isUserOwner) { + if (!this.isUserOwner) { this.isFinalized = true; this.formGroup.disable(); } From 290aa5260c875cedb101ecb3c17e781b892a0e69 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Fri, 3 Jan 2020 12:55:12 +0200 Subject: [PATCH 043/106] Adds "if file exists" check functionality on setting configurable providers and fixes bug not closing input stream when error occures. (Issue #183) --- .../configloaders/DevelConfigLoader.java | 15 +++++++---- .../configloaders/ProductionConfigLoader.java | 27 ++++++++++++------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DevelConfigLoader.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DevelConfigLoader.java index 934a472c4..fa4885bae 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DevelConfigLoader.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DevelConfigLoader.java @@ -96,15 +96,20 @@ public class DevelConfigLoader implements ConfigLoader { } } - public void setConfigurableProviders() { + private void setConfigurableProviders() { String filePath = environment.getProperty("configuration.configurable_login_providers"); - String current = null; + String current; InputStream is = null; try { current = new java.io.File(".").getCanonicalPath(); - is = new URL("file:///" + current + filePath).openStream(); - ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - this.configurableProviders = mapper.readValue(is, ConfigurableProviders.class); + File tempFile = new File(current + filePath); + if (tempFile.exists()) { + is = new URL("file:///" + current + filePath).openStream(); + ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + this.configurableProviders = mapper.readValue(is, ConfigurableProviders.class); + } else { + this.configurableProviders = new ConfigurableProviders(); + } } catch (IOException e) { e.printStackTrace(); } finally { diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ProductionConfigLoader.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ProductionConfigLoader.java index 57d16e2c0..366ab1874 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ProductionConfigLoader.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ProductionConfigLoader.java @@ -11,10 +11,7 @@ import org.springframework.stereotype.Service; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.net.URL; import java.nio.file.Paths; import java.util.LinkedList; @@ -88,16 +85,26 @@ public class ProductionConfigLoader implements ConfigLoader { } } - public void setConfigurableProviders() { + private void setConfigurableProviders() { String filePath = environment.getProperty("configuration.configurable_login_providers"); - String current = null; + InputStream is = null; try { - current = new java.io.File(".").getCanonicalPath(); - InputStream is = new URL(Paths.get(filePath).toUri().toURL().toString()).openStream(); - ObjectMapper objectMapper = new ObjectMapper(); - this.configurableProviders = objectMapper.readValue(is, ConfigurableProviders.class); + File tempFile = new File(filePath); + if (tempFile.exists()) { + is = new URL(Paths.get(filePath).toUri().toURL().toString()).openStream(); + ObjectMapper objectMapper = new ObjectMapper(); + this.configurableProviders = objectMapper.readValue(is, ConfigurableProviders.class); + } else { + this.configurableProviders = new ConfigurableProviders(); + } } catch (IOException e) { e.printStackTrace(); + } finally { + try { + if (is != null) is.close(); + } catch (IOException e) { + System.out.println("Warning: Could not close a stream after reading from file: " + filePath); + } } } From 0f6583ca4b4f11315a4db323472475d793887db9 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Fri, 3 Jan 2020 16:52:27 +0200 Subject: [PATCH 044/106] Fixes bug on "Search bar" not fetching published DMP and published Dataset Descriptions. --- .../controllers/DashBoardController.java | 5 +- .../logic/managers/DashBoardManager.java | 54 +++++++++++++------ .../dashboard/searchbar/SearchBarItem.java | 15 ++++-- .../core/model/dashboard/search-bar-item.ts | 1 + .../app/ui/misc/search/search.component.html | 2 +- .../app/ui/misc/search/search.component.ts | 48 +++++++++++++---- dmp-frontend/src/assets/i18n/en.json | 8 ++- 7 files changed, 98 insertions(+), 35 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DashBoardController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DashBoardController.java index 9c2dff6a1..4fb4e00ca 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DashBoardController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DashBoardController.java @@ -1,6 +1,7 @@ package eu.eudat.controllers; import eu.eudat.logic.managers.DashBoardManager; +import eu.eudat.logic.security.claims.ClaimedAuthorities; import eu.eudat.logic.services.ApiContext; import eu.eudat.models.data.dashboard.recent.RecentActivity; import eu.eudat.models.data.dashboard.searchbar.SearchBarItem; @@ -8,6 +9,7 @@ import eu.eudat.models.data.dashboard.statistics.DashBoardStatistics; import eu.eudat.models.data.helpers.responses.ResponseItem; import eu.eudat.models.data.security.Principal; import eu.eudat.types.ApiMessageCode; +import eu.eudat.types.Authorities; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -46,7 +48,8 @@ public class DashBoardController extends BaseController { } @RequestMapping(method = RequestMethod.GET, value = {"/dashboard/search"}, produces = "application/json") - public ResponseEntity>> search(@RequestParam(name = "like") String like, Principal principal) { + public ResponseEntity>> search(@RequestParam(name = "like") String like, + @ClaimedAuthorities(claims = {Authorities.ADMIN, Authorities.MANAGER, Authorities.USER, Authorities.ANONYMOUS}) Principal principal) { List searchBarItemList = dashBoardManager.searchUserData(like, principal); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem>().status(ApiMessageCode.NO_MESSAGE).payload(searchBarItemList)); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java index ae3cd99f1..281ae0147 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java @@ -132,7 +132,6 @@ public class DashBoardManager { } public List searchUserData(String like, Principal principal) { - RecentActivity activity = new RecentActivity(); UserInfo user = new UserInfo(); user.setId(principal.getId()); DMPDao dataManagementPlanRepository = databaseRepository.getDmpDao(); @@ -141,32 +140,53 @@ public class DashBoardManager { List roles = new LinkedList<>(); List searchBarItems = new LinkedList<>(); - CompletableFuture> dmps = dataManagementPlanRepository.getAuthenticated(dataManagementPlanRepository.asQueryable(), principal.getId(), roles) - .withHint("dmpRecentActivity") + + CompletableFuture> publicDmps = dataManagementPlanRepository.asQueryable() .where((builder, root) -> builder.like(builder.upper(root.get("label")), "%" + like.toUpperCase() + "%")) .where((builder, root) -> builder.notEqual(root.get("status"), DMP.DMPStatus.DELETED.getValue())) + .where((builder, root) -> builder.equal(root.get("isPublic"), true)) .orderBy((builder, root) -> builder.desc(root.get("modified"))) - .selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.DMP.getValue())) + .selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.DMP.getValue(), true)) .whenComplete((dmpItems, throwable) -> searchBarItems.addAll(dmpItems)); - CompletableFuture> datasets = datasetRepository.getAuthenticated(datasetRepository.asQueryable(), user, roles) - .withHint("datasetRecentActivity") + CompletableFuture> publicDatasets = datasetRepository.asQueryable() .where((builder, root) -> builder.like(builder.upper(root.get("label")), "%" + like.toUpperCase() + "%")) - .where((builder, root) -> builder.notEqual(root.get("status"), Dataset.Status.DELETED.getValue())) - .where((builder, root) -> builder.notEqual(root.get("status"), Dataset.Status.CANCELED.getValue())) + .where((builder, root) -> builder.equal(root.get("status"), Dataset.Status.FINALISED.getValue())) + .where((builder, root) -> builder.equal(root.get("dmp").get("isPublic"), true)) .orderBy((builder, root) -> builder.desc(root.get("modified"))) - .selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.DATASET.getValue())) + .selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.DATASET.getValue(), true)) .whenComplete((dataSetItems, throwable) -> searchBarItems.addAll(dataSetItems)); - CompletableFuture> grants = grantRepository.getAuthenticated(grantRepository.asQueryable(), user) - .withHint("grantRecentActivity") - .where((builder, root) -> builder.like(builder.upper(root.get("label")), "%" + like.toUpperCase() + "%")) - .orderBy((builder, root) -> builder.desc(root.get("modified"))) - .selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.GRANT.getValue())) - .whenComplete((grantItems, throwable) -> searchBarItems.addAll(grantItems)); + if (principal.getId() != null) { + CompletableFuture> dmps = dataManagementPlanRepository.getAuthenticated(dataManagementPlanRepository.asQueryable(), principal.getId(), roles) + .withHint("dmpRecentActivity") + .where((builder, root) -> builder.like(builder.upper(root.get("label")), "%" + like.toUpperCase() + "%")) + .where((builder, root) -> builder.notEqual(root.get("status"), DMP.DMPStatus.DELETED.getValue())) + .orderBy((builder, root) -> builder.desc(root.get("modified"))) + .selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.DMP.getValue(), false)) + .whenComplete((dmpItems, throwable) -> searchBarItems.addAll(dmpItems)); + + CompletableFuture> datasets = datasetRepository.getAuthenticated(datasetRepository.asQueryable(), user, roles) + .withHint("datasetRecentActivity") + .where((builder, root) -> builder.like(builder.upper(root.get("label")), "%" + like.toUpperCase() + "%")) + .where((builder, root) -> builder.notEqual(root.get("status"), Dataset.Status.DELETED.getValue())) + .where((builder, root) -> builder.notEqual(root.get("status"), Dataset.Status.CANCELED.getValue())) + .orderBy((builder, root) -> builder.desc(root.get("modified"))) + .selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.DATASET.getValue(), false)) + .whenComplete((dataSetItems, throwable) -> searchBarItems.addAll(dataSetItems)); + + CompletableFuture> grants = grantRepository.getAuthenticated(grantRepository.asQueryable(), user) + .withHint("grantRecentActivity") + .where((builder, root) -> builder.like(builder.upper(root.get("label")), "%" + like.toUpperCase() + "%")) + .orderBy((builder, root) -> builder.desc(root.get("modified"))) + .selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.GRANT.getValue(), false)) + .whenComplete((grantItems, throwable) -> searchBarItems.addAll(grantItems)); + + CompletableFuture.allOf(grants, dmps, datasets, publicDmps, publicDatasets).join(); + } else { + CompletableFuture.allOf(publicDmps, publicDatasets).join(); + } - CompletableFuture.allOf(grants, dmps, datasets).join(); return searchBarItems; } - } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/searchbar/SearchBarItem.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/searchbar/SearchBarItem.java index 57ada987d..a698910f9 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/searchbar/SearchBarItem.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/searchbar/SearchBarItem.java @@ -1,17 +1,16 @@ package eu.eudat.models.data.dashboard.searchbar; -/** - * Created by ikalyvas on 7/26/2018. - */ public class SearchBarItem { private String id; private String label; private int type; + private boolean isPublished; - public SearchBarItem(String id, String label, int type) { + public SearchBarItem(String id, String label, int type, boolean isPublished) { this.id = id; this.label = label; this.type = type; + this.isPublished = isPublished; } public String getId() { @@ -37,4 +36,12 @@ public class SearchBarItem { public void setType(int type) { this.type = type; } + + public boolean getIsPublished() { + return isPublished; + } + + public void setPublished(boolean published) { + isPublished = published; + } } diff --git a/dmp-frontend/src/app/core/model/dashboard/search-bar-item.ts b/dmp-frontend/src/app/core/model/dashboard/search-bar-item.ts index b8e18cdde..7ee083226 100644 --- a/dmp-frontend/src/app/core/model/dashboard/search-bar-item.ts +++ b/dmp-frontend/src/app/core/model/dashboard/search-bar-item.ts @@ -4,4 +4,5 @@ export interface SearchBarItem { id: string; label: string; type: SearchBarType; + isPublished: boolean; } diff --git a/dmp-frontend/src/app/ui/misc/search/search.component.html b/dmp-frontend/src/app/ui/misc/search/search.component.html index f1f77cfa9..47230806e 100644 --- a/dmp-frontend/src/app/ui/misc/search/search.component.html +++ b/dmp-frontend/src/app/ui/misc/search/search.component.html @@ -8,7 +8,7 @@ {{ option.label }}
- {{ transformType(option.type) }} + {{ transformType(option.type, option.isPublished) }}
diff --git a/dmp-frontend/src/app/ui/misc/search/search.component.ts b/dmp-frontend/src/app/ui/misc/search/search.component.ts index 0fdad5a9a..2dd49ca75 100644 --- a/dmp-frontend/src/app/ui/misc/search/search.component.ts +++ b/dmp-frontend/src/app/ui/misc/search/search.component.ts @@ -1,5 +1,5 @@ -import {mergeMap, distinctUntilChanged, debounceTime} from 'rxjs/operators'; +import { mergeMap, distinctUntilChanged, debounceTime } from 'rxjs/operators'; import { Component, OnInit } from "@angular/core"; import { AuthService } from '../../../core/services/auth/auth.service'; import { FormControl } from "@angular/forms"; @@ -7,6 +7,7 @@ import { SearchBarService } from '../../../core/services/search-bar/search-bar.s import { Router } from '@angular/router'; import { Observable } from "rxjs"; import { SearchBarItem } from "../../../core/model/dashboard/search-bar-item"; +import { TranslateService } from "@ngx-translate/core"; export enum SearchBarType { Dataset = 0, @@ -24,12 +25,17 @@ export class SearchComponent implements OnInit { public searchControl = new FormControl(); filteredOptions: Observable; - constructor(private authentication: AuthService, private router: Router, private searchBarService: SearchBarService) {} + constructor( + private authentication: AuthService, + private router: Router, + private searchBarService: SearchBarService, + private language: TranslateService + ) { } ngOnInit() { - this.filteredOptions = this.searchControl.valueChanges.pipe(debounceTime(500),distinctUntilChanged(),mergeMap(x => { + this.filteredOptions = this.searchControl.valueChanges.pipe(debounceTime(500), distinctUntilChanged(), mergeMap(x => { return this.searchBarService.search(x); - }),); + })); } public isAuthenticated(): boolean { @@ -40,16 +46,36 @@ export class SearchComponent implements OnInit { this.search = false; this.searchControl.patchValue(null); const selectedSearchBarItem = event.option.value; - if (selectedSearchBarItem.type === SearchBarType.Dataset) { this.router.navigate(['datasets/edit/' + selectedSearchBarItem.id]); } - if (selectedSearchBarItem.type === SearchBarType.Grant) { this.router.navigate(['plans/grant/' + selectedSearchBarItem.id]); } - if (selectedSearchBarItem.type === SearchBarType.Dmp) { this.router.navigate(['plans/overview/' + selectedSearchBarItem.id]); } + if (!selectedSearchBarItem.isPublished) { + if (selectedSearchBarItem.type === SearchBarType.Dataset) { this.router.navigate(['datasets/edit/' + selectedSearchBarItem.id]); } + if (selectedSearchBarItem.type === SearchBarType.Grant) { this.router.navigate(['plans/grant/' + selectedSearchBarItem.id]); } + if (selectedSearchBarItem.type === SearchBarType.Dmp) { this.router.navigate(['plans/overview/' + selectedSearchBarItem.id]); } + } else { + if (selectedSearchBarItem.type === SearchBarType.Dataset) { this.router.navigate(['datasets/publicEdit/' + selectedSearchBarItem.id]); } + if (selectedSearchBarItem.type === SearchBarType.Dmp) { this.router.navigate(['explore-plans/overview/' + selectedSearchBarItem.id]); } + } } - transformType(type) { + transformType(type, isPublished) { + let subtitle: string; switch (type) { - case SearchBarType.Dataset: return 'Dataset'; - case SearchBarType.Dmp: return 'DMP'; - case SearchBarType.Grant: return 'Grant'; + case SearchBarType.Dataset: { + subtitle = this.language.instant('NAV-BAR.SEARCH.DATASET'); + break; + } + case SearchBarType.Dmp: { + subtitle = this.language.instant('NAV-BAR.SEARCH.DMP'); + break; + } + case SearchBarType.Grant: { + subtitle = this.language.instant('NAV-BAR.SEARCH.GRANT'); + break; + } + } + if (isPublished) { + return subtitle + " - " + this.language.instant('NAV-BAR.SEARCH.PUBLISHED') + } else { + return subtitle; } } } diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 004541b29..077b38c1b 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -175,7 +175,13 @@ "DATASET-TEMPLATES": "DATASET TEMPLATES", "TEMPLATE": "TEMPLATE", "DMP-TEMPLATES": "DMP TEMPLATES", - "USERS-BREADCRUMB": "USERS" + "USERS-BREADCRUMB": "USERS", + "SEARCH": { + "DATASET": "Dataset Description", + "DMP": "DMP", + "GRANT": "Grant", + "PUBLISHED": "Published" + } }, "SIDE-BAR": { "GENERAL": "GENERAL", From 89b98f5377858d880d0676c6ca3eede39710862d Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Fri, 3 Jan 2020 17:47:25 +0200 Subject: [PATCH 045/106] Fixes filter criteria bug on "Published DMP" and "Published Dataset Description" listings. --- .../explore-dataset-filters.component.ts | 20 ++++++++----------- .../explore-dmp-filters.component.ts | 16 +++++++-------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.ts b/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.ts index 1f3bc2f4f..d9a1e5f5b 100644 --- a/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.ts +++ b/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.ts @@ -254,9 +254,8 @@ export class ExploreDatasetFiltersComponent extends BaseComponent implements OnI this.facetCriteriaChange.emit(this.facetCriteria); } - onGrantOptionSelected(items: GrantListingModel[]) { - this.facetCriteria.grants.splice(0); - this.facetCriteria.grants.push(...items.map(x => x.id)); + onGrantOptionSelected(item: GrantListingModel) { + this.facetCriteria.grants.push(item.id); this.facetCriteriaChange.emit(this.facetCriteria); } @@ -268,9 +267,8 @@ export class ExploreDatasetFiltersComponent extends BaseComponent implements OnI } } - onDmpOptionSelected(items: DmpListingModel[]) { - this.facetCriteria.dmpIds.splice(0); - this.facetCriteria.dmpIds.push(...items.map(x => x.id)); + onDmpOptionSelected(item: DmpListingModel) { + this.facetCriteria.dmpIds.push(item.id); this.facetCriteriaChange.emit(this.facetCriteria); } @@ -282,9 +280,8 @@ export class ExploreDatasetFiltersComponent extends BaseComponent implements OnI } } - onProfileOptionSelected(items: DatasetProfileModel[]) { - this.facetCriteria.datasetProfile.splice(0); - this.facetCriteria.datasetProfile.push(...items.map(x => x.id)); + onProfileOptionSelected(item: DatasetProfileModel) { + this.facetCriteria.datasetProfile.push(item.id); this.facetCriteriaChange.emit(this.facetCriteria); } @@ -296,9 +293,8 @@ export class ExploreDatasetFiltersComponent extends BaseComponent implements OnI } } - onOrganizationOptionSelected(items: OrganizationModel[]) { - this.facetCriteria.dmpOrganisations.splice(0); - this.facetCriteria.dmpOrganisations.push(...items.map(x => x.id)); + onOrganizationOptionSelected(item: OrganizationModel) { + this.facetCriteria.dmpOrganisations.push(item.id); this.facetCriteriaChange.emit(this.facetCriteria); } diff --git a/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component.ts b/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component.ts index d65d47541..99917f0e4 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component.ts +++ b/dmp-frontend/src/app/ui/explore-dmp/dmp-explore-filters/explore-dmp-filters.component.ts @@ -197,9 +197,9 @@ export class ExploreDmpFiltersComponent extends BaseCriteriaComponent implements this.facetCriteriaChange.emit(this.facetCriteria); } - onProfileOptionSelected(items: DatasetProfileModel[]) { - this.facetCriteria.datasetProfile.splice(0); - this.facetCriteria.datasetProfile.push(...items.map(x => x.id)); + onProfileOptionSelected(items: DatasetProfileModel) { + //this.facetCriteria.datasetProfile.splice(0); + this.facetCriteria.datasetProfile.push(items.id); this.facetCriteriaChange.emit(this.facetCriteria); } @@ -228,9 +228,8 @@ export class ExploreDmpFiltersComponent extends BaseCriteriaComponent implements this.facetCriteriaChange.emit(this.facetCriteria); } - onOrganizationOptionSelected(items: OrganizationModel[]) { - this.facetCriteria.dmpOrganisations.splice(0); - this.facetCriteria.dmpOrganisations.push(...items.map(x => x.id)); + onOrganizationOptionSelected(item: OrganizationModel) { + this.facetCriteria.dmpOrganisations.push(item.id); this.facetCriteriaChange.emit(this.facetCriteria); } @@ -242,9 +241,8 @@ export class ExploreDmpFiltersComponent extends BaseCriteriaComponent implements } } - onGrantOptionSelected(items: GrantListingModel[]) { - this.facetCriteria.grants.splice(0); - this.facetCriteria.grants.push(...items.map(x => x.id)); + onGrantOptionSelected(item: GrantListingModel) { + this.facetCriteria.grants.push(item.id); this.facetCriteriaChange.emit(this.facetCriteria); } From bc0fd3672229d7d3591e7ff45ac25592ff956dab Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Fri, 3 Jan 2020 18:38:27 +0200 Subject: [PATCH 046/106] Hides "Contact-Support" footer option when user not logged in. --- .../sidebar/sidebar-footer/sidebar-footer.component.html | 2 +- .../ui/sidebar/sidebar-footer/sidebar-footer.component.ts | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.html b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.html index ba92feae2..4dd12fe7f 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.html +++ b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.html @@ -20,7 +20,7 @@
-
+

{{'FOOTER.CONTACT-SUPPORT' | translate}}

diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.ts b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.ts index fcab57335..dda6326be 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.ts +++ b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/sidebar-footer.component.ts @@ -13,6 +13,7 @@ import { FormService } from '@common/forms/form-service'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; +import { AuthService } from "@app/core/services/auth/auth.service"; @Component({ selector: 'app-sidebar-footer', @@ -30,7 +31,8 @@ export class SidebarFooterComponent extends BaseComponent implements OnInit { public router: Router, private contactSupportService: ContactSupportService, private uiNotificationService: UiNotificationService, - private formService: FormService + private formService: FormService, + private authentication: AuthService, ) { super(); } @@ -110,4 +112,8 @@ export class SidebarFooterComponent extends BaseComponent implements OnInit { (this.contactEmailFormModel.validationErrorModel)[item] = (validationErrorModel)[item]; }); } + + public isAuthenticated(): boolean { + return !(!this.authentication.current()); + } } From 6eaff65ea82ee84cb3838a70bff43bccded5b2d0 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Tue, 7 Jan 2020 18:15:07 +0200 Subject: [PATCH 047/106] Hides DMP properties that shouldn't be visible on "DMP overview" view. --- .../ui/dmp/overview/dmp-overview.component.html | 4 ++-- .../ui/dmp/overview/dmp-overview.component.ts | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html index 339633493..87060f906 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html @@ -17,7 +17,7 @@ -
-
+
settings

{{ roleDisplayFromList(dmp.users) }}

diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts index 20da2f5be..9ad6bbf8c 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts @@ -238,6 +238,19 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { } } + isUserDMPRelated() { + const principal: Principal = this.authentication.current(); + let isRelated: boolean = false; + if (this.dmp && principal) { + this.dmp.users.forEach(element => { + if (element.id === principal.id) { + isRelated = true; + } + }) + } + return isRelated; + } + roleDisplay(value: UserInfoListingModel) { if (value.role === Role.Member) { return this.translate.instant('DMP-LISTING.MEMBER'); @@ -374,6 +387,10 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { this.router.navigate(['/plans/versions/' + rowId], { queryParams: { groupLabel: rowLabel } }); } + public isAuthenticated(): boolean { + return !(!this.authentication.current()); + } + // advancedClicked() { // const dialogRef = this.dialog.open(ExportMethodDialogComponent, { // maxWidth: '500px', From fa22017d48efd44c5395d2c1713a74ab684e0b7e Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Tue, 7 Jan 2020 18:17:21 +0200 Subject: [PATCH 048/106] Fixes clone functionality not working on published DMPs. --- .../main/java/eu/eudat/controllers/DMPs.java | 2 +- .../managers/DataManagementPlanManager.java | 28 +++++++--------- .../app/ui/dmp/clone/dmp-clone.component.html | 4 +-- .../app/ui/dmp/clone/dmp-clone.component.ts | 2 ++ .../general-tab/general-tab.component.ts | 3 +- .../editor/grant-tab/grant-tab.component.html | 6 ++-- .../editor/grant-tab/grant-tab.component.ts | 33 ++++++++++++++++--- 7 files changed, 50 insertions(+), 28 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java index beca226a5..c2652536c 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java @@ -95,7 +95,7 @@ public class DMPs extends BaseController { if (contentType.equals("application/xml") || contentType.equals("application/msword")) { return this.dataManagementPlanManager.getDocument(id, contentType, principal, this.configLoader); } else { - eu.eudat.models.data.dmp.DataManagementPlan dataManagementPlan = this.dataManagementPlanManager.getSingle(id, principal, this.dynamicGrantConfiguration); + eu.eudat.models.data.dmp.DataManagementPlan dataManagementPlan = this.dataManagementPlanManager.getSingle(id, principal); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).payload(dataManagementPlan)); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index 7bdb35e7e..a1bd6e2ba 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -339,30 +339,24 @@ public class DataManagementPlanManager { return this.datasetManager.convertToPDF(file, environment, fileName); }*/ - public eu.eudat.models.data.dmp.DataManagementPlan getSingle(String id, Principal principal, DynamicGrantConfiguration dynamicGrantConfiguration) throws InstantiationException, IllegalAccessException { + public eu.eudat.models.data.dmp.DataManagementPlan getSingle(String id, Principal principal) { DMP dataManagementPlanEntity = databaseRepository.getDmpDao().find(UUID.fromString(id)); - if (dataManagementPlanEntity.getUsers().stream().filter(userInfo -> userInfo.getUser().getId() == principal.getId()).collect(Collectors.toList()).size() == 0) - throw new UnauthorisedException(); - eu.eudat.models.data.dmp.DataManagementPlan datamanagementPlan = new eu.eudat.models.data.dmp.DataManagementPlan(); - datamanagementPlan.fromDataModel(dataManagementPlanEntity); + if (dataManagementPlanEntity.getUsers().stream().noneMatch(userInfo -> userInfo.getUser().getId() == principal.getId())) { + if (!dataManagementPlanEntity.isPublic()) { + throw new UnauthorisedException(); + } + } + eu.eudat.models.data.dmp.DataManagementPlan dataManagementPlan = new eu.eudat.models.data.dmp.DataManagementPlan(); + dataManagementPlan.fromDataModel(dataManagementPlanEntity); Map dmpProperties = dataManagementPlanEntity.getDmpProperties() != null ? new org.json.JSONObject(dataManagementPlanEntity.getDmpProperties()).toMap() : null; -// datamanagementPlan.setDynamicFields(dynamicGrantConfiguration.getFields().stream().map(item -> { -// DynamicFieldWithValue fieldWithValue = new DynamicFieldWithValue(); -// fieldWithValue.setId(item.getId()); -// fieldWithValue.setDependencies(item.getDependencies()); -// fieldWithValue.setName(item.getName()); -// fieldWithValue.setQueryProperty(item.getQueryProperty()); -// fieldWithValue.setRequired(item.getRequired()); -// return fieldWithValue; -// }).collect(Collectors.toList())); - if (dmpProperties != null && datamanagementPlan.getDynamicFields() != null) - datamanagementPlan.getDynamicFields().forEach(item -> { + if (dmpProperties != null && dataManagementPlan.getDynamicFields() != null) + dataManagementPlan.getDynamicFields().forEach(item -> { Map properties = (Map) dmpProperties.get(item.getId()); if (properties != null) item.setValue(new Tuple<>(properties.get("id"), properties.get("label"))); }); - return datamanagementPlan; + return dataManagementPlan; } public DataManagementPlanOverviewModel getOverviewSingle(String id, Principal principal) throws InstantiationException, IllegalAccessException { diff --git a/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.html b/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.html index e79ab5628..546df6e76 100644 --- a/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.html +++ b/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.html @@ -19,14 +19,14 @@ view_agenda {{ 'SIDE-BAR.GENERAL' | translate }} - + work_outline {{ 'DMP-LISTING.COLUMNS.GRANT' | translate }} - + diff --git a/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts b/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts index 9a46888aa..e3ec8a6e6 100644 --- a/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts +++ b/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts @@ -35,6 +35,8 @@ export class DmpCloneComponent extends BaseComponent implements OnInit { selectedTab = 0; parentDmpLabel: string; isNewVersion: boolean = false; + isClone: boolean = true; + isNew: boolean = false; constructor( private route: ActivatedRoute, diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts index 63c146f4b..f02ac1a82 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts @@ -31,6 +31,7 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { @Input() formGroup: FormGroup = null; @Input() isNewVersion: boolean; @Input() isUserOwner: boolean; + @Input() isClone: boolean; profilesAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { filterFn: this.filterProfiles.bind(this), @@ -82,7 +83,7 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { this.formGroup.get('label').disable(); } - if (!this.isUserOwner) { + if (!this.isUserOwner && !this.isClone) { this.formGroup.disable(); } } diff --git a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.html b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.html index b2b8c4356..6e7cd3fcb 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.html @@ -24,7 +24,7 @@
-
+
settings_backup_restore {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.EXIST-FUNDER' | translate}} @@ -63,7 +63,7 @@
-
+
settings_backup_restore {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.EXIST-GRANT' | translate}} @@ -104,7 +104,7 @@
-
+
settings_backup_restore {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.EXIST-PROJECT' | translate}} diff --git a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts index cf9d454ff..bf703b3d0 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/grant-tab/grant-tab.component.ts @@ -27,6 +27,7 @@ export class GrantTabComponent extends BaseComponent implements OnInit { @Input() isNewVersion: boolean; @Input() isNew: boolean; @Input() isUserOwner: boolean; + @Input() isClone: boolean; isCreateNew = false; isCreateNewProject = false; @@ -64,7 +65,7 @@ export class GrantTabComponent extends BaseComponent implements OnInit { initialItems: () => this.searchFunder(''), displayFn: (item) => item['label'], titleFn: (item) => item['label'], - subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') + subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')) } this.grantAutoCompleteConfiguration = { @@ -72,7 +73,7 @@ export class GrantTabComponent extends BaseComponent implements OnInit { initialItems: () => this.searchGrant(''), displayFn: (item) => item['label'] + this.getGrantIdText(item), titleFn: (item) => item['label'] + this.getGrantIdText(item), - subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') + subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')) }; this.projectAutoCompleteConfiguration = { @@ -80,7 +81,7 @@ export class GrantTabComponent extends BaseComponent implements OnInit { initialItems: () => this.searchProject(''), displayFn: (item) => item['label'], titleFn: (item) => item['label'], - subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') + subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')) } this.isCreateNew = (this.grantformGroup.get('label').value != null && this.grantformGroup.get('label').value.length > 0); @@ -90,7 +91,7 @@ export class GrantTabComponent extends BaseComponent implements OnInit { this.setProjectValidators(); this.setFunderValidators(); this.registerFormListeners(); - if (this.isNew) { + if (this.isNew && !this.isClone) { this.grantformGroup.reset(); this.grantformGroup.disable(); } @@ -144,6 +145,12 @@ export class GrantTabComponent extends BaseComponent implements OnInit { this.grantformGroup.get('existGrant').disable(); this.grantformGroup.get('label').enable(); this.grantformGroup.get('description').enable(); + } else if (this.isClone) { + this.grantformGroup.get('existGrant').enable(); + this.grantformGroup.get('label').disable(); + this.grantformGroup.get('label').reset(); + this.grantformGroup.get('description').disable(); + this.grantformGroup.get('description').reset(); } else if (this.isFinalized || this.isNewVersion || !this.isUserOwner) { this.grantformGroup.get('existGrant').disable(); this.grantformGroup.get('label').disable(); @@ -162,6 +169,12 @@ export class GrantTabComponent extends BaseComponent implements OnInit { this.projectFormGroup.get('existProject').disable(); this.projectFormGroup.get('label').enable(); this.projectFormGroup.get('description').enable(); + } else if (this.isClone) { + this.projectFormGroup.get('existProject').enable(); + this.projectFormGroup.get('label').disable() + this.projectFormGroup.get('label').reset(); + this.projectFormGroup.get('description').disable(); + this.projectFormGroup.get('description').reset(); } else if (this.isFinalized || this.isNewVersion || !this.isUserOwner) { this.projectFormGroup.get('existProject').disable(); this.projectFormGroup.get('label').disable(); @@ -179,6 +192,14 @@ export class GrantTabComponent extends BaseComponent implements OnInit { if (this.isCreateNewFunder) { this.funderFormGroup.get('existFunder').disable(); this.funderFormGroup.get('label').enable(); + } else if (this.isClone) { + if (this.funderFormGroup.get('existFunder')) { + this.funderFormGroup.get('existFunder').enable(); + this.funderFormGroup.get('label').disable(); + this.funderFormGroup.get('label').reset(); + } else { + this.funderFormGroup.get('label').enable(); + } } else if (this.isFinalized || this.isNewVersion || !this.isUserOwner) { this.funderFormGroup.get('existFunder').disable(); this.funderFormGroup.get('label').disable(); @@ -213,4 +234,8 @@ export class GrantTabComponent extends BaseComponent implements OnInit { isGrantDisabled() { return this.grantformGroup.disabled; } + + showToggleButton() { + return (!this.isFinalized && this.isUserOwner) || this.isClone; + } } From f29aec07cc06b3c9c1774b2bdd86bf368726a81d Mon Sep 17 00:00:00 2001 From: apapachristou Date: Wed, 8 Jan 2020 09:42:26 +0200 Subject: [PATCH 049/106] Uploads profile default placeholder --- .../src/assets/images/profile-placeholder.png | Bin 0 -> 127170 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 dmp-frontend/src/assets/images/profile-placeholder.png diff --git a/dmp-frontend/src/assets/images/profile-placeholder.png b/dmp-frontend/src/assets/images/profile-placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..c13e0c32fa7ecce3952c26577bb2091162865bdd GIT binary patch literal 127170 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 literal 0 HcmV?d00001 From 493ab9763e9eeb3ffc2273109b2cdb387bbf11b7 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Wed, 8 Jan 2020 11:46:16 +0200 Subject: [PATCH 050/106] SQL script for setting the Dataset's Status "Canceled" where DMP is published and them not "Finalized". --- ..._Update_Dataset_Statuses_To_Canceled_For_Old_Cases.sql | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 dmp-db-scema/updates/06/01_Update_Dataset_Statuses_To_Canceled_For_Old_Cases.sql diff --git a/dmp-db-scema/updates/06/01_Update_Dataset_Statuses_To_Canceled_For_Old_Cases.sql b/dmp-db-scema/updates/06/01_Update_Dataset_Statuses_To_Canceled_For_Old_Cases.sql new file mode 100644 index 000000000..9809fbbdb --- /dev/null +++ b/dmp-db-scema/updates/06/01_Update_Dataset_Statuses_To_Canceled_For_Old_Cases.sql @@ -0,0 +1,8 @@ +UPDATE "Dataset" AS dataset +SET "Status" = 2 +WHERE dataset."ID" in ( + SELECT dataset1."ID" + FROM "Dataset" AS dataset1 + INNER JOIN "DMP" AS dmp ON dmp."ID" = dataset1."DMP" + WHERE dmp."isPublic" = true AND dataset1."Status" = 0 +) \ No newline at end of file From 3da0cc9ad42d5d7c857f830315adf7fcc8a50787 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Wed, 8 Jan 2020 13:04:04 +0200 Subject: [PATCH 051/106] Fixes not showing "New Version" option on DMP overview action menu. --- .../src/app/ui/dmp/overview/dmp-overview.component.html | 2 +- dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html index 87060f906..7933e2671 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html @@ -11,7 +11,7 @@ more_horiz -
-
+

{{dmp.description}}

+
+

{{'DMP-LISTING.COLUMNS.VERSION' | translate}} : {{dmp.version}}

+
diff --git a/dmp-frontend/src/app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component.html b/dmp-frontend/src/app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component.html index 1668731ed..b036ef35c 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component.html +++ b/dmp-frontend/src/app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component.html @@ -22,6 +22,9 @@

{{dmp.description}}

+
+

{{'DMP-LISTING.COLUMNS.VERSION' | translate}} : {{dmp.version}}

+
diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 077b38c1b..121132dd9 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -377,7 +377,8 @@ "ACTIONS": "Actions", "DATASETS": "Dataset Descriptions", "STATUS": "Status", - "PEOPLE": "People" + "PEOPLE": "People", + "VERSION": "Version" }, "ACTIONS": { "NEW": "New DMP", From 2798fa3a3984ca256b8bcf2f9562530ad98d9270 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 9 Jan 2020 17:19:47 +0200 Subject: [PATCH 058/106] Fixes query on published DMPs now fetching the latest version that is published. --- .../items/table/dmp/DataManagmentPlanPublicTableRequest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/query/items/table/dmp/DataManagmentPlanPublicTableRequest.java b/dmp-backend/data/src/main/java/eu/eudat/data/query/items/table/dmp/DataManagmentPlanPublicTableRequest.java index 826a42c47..ed0ecdb22 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/query/items/table/dmp/DataManagmentPlanPublicTableRequest.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/query/items/table/dmp/DataManagmentPlanPublicTableRequest.java @@ -38,8 +38,8 @@ public class DataManagmentPlanPublicTableRequest extends TableQuery root.join("organisations").get("reference").in(this.getCriteria().getDmpOrganisations()))); query.initSubQuery(String.class).where((builder, root) -> builder.equal(root.get("version"), - query.subQueryMax((builder1, externalRoot, nestedRoot) -> builder1.equal(externalRoot.get("groupId"), - nestedRoot.get("groupId")), Arrays.asList(new SelectionField(FieldSelectionType.FIELD, "version")), String.class))); + query.subQueryMax((builder1, externalRoot, nestedRoot) -> builder1.and(builder1.equal(externalRoot.get("groupId"), + nestedRoot.get("groupId")), builder1.equal(nestedRoot.get("isPublic"), true)), Arrays.asList(new SelectionField(FieldSelectionType.FIELD, "version")), String.class))); return query; } From 18c785cd9392e9c52608e6ecceeaadefa8bb740f Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Fri, 10 Jan 2020 12:44:00 +0200 Subject: [PATCH 059/106] Fixes how DMP versions are fetched when published and adds UI elemets on listings corresponding to that change. --- .../DataManagementPlanPublicCriteria.java | 16 ++++++++ .../DataManagmentPlanPublicTableRequest.java | 12 ++++-- .../query/explore-dmp/explore-dmp-criteria.ts | 2 + .../app/ui/dmp/editor/dmp-editor.component.ts | 19 +++++---- .../ui/dmp/listing/dmp-listing.component.html | 8 ++++ .../ui/dmp/listing/dmp-listing.component.scss | 8 ++++ .../ui/dmp/listing/dmp-listing.component.ts | 21 ++++++++++ .../ui/dmp/overview/dmp-overview.component.ts | 8 +++- .../explore-dataset-filters.component.ts | 2 +- .../explore-dmp-listing.component.html | 9 ++++- .../explore-dmp-listing.component.scss | 8 ++++ .../explore-dmp-listing.component.ts | 40 ++++++++++++++----- .../app/ui/explore-dmp/explore-dmp.routing.ts | 7 ++++ dmp-frontend/src/assets/i18n/en.json | 3 +- 14 files changed, 137 insertions(+), 26 deletions(-) diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DataManagementPlanPublicCriteria.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DataManagementPlanPublicCriteria.java index edc1ffa9f..cc96186fc 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DataManagementPlanPublicCriteria.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DataManagementPlanPublicCriteria.java @@ -12,6 +12,8 @@ public class DataManagementPlanPublicCriteria extends Criteria { public List datasetProfile; private List dmpOrganisations; private Integer role; + private boolean allVersions; + private List groupIds; public GrantStateType getGrantStatus() { return grantStatus; @@ -47,4 +49,18 @@ public class DataManagementPlanPublicCriteria extends Criteria { public void setRole(Integer role) { this.role = role; } + + public boolean getAllVersions() { + return allVersions; + } + public void setAllVersions(boolean allVersions) { + this.allVersions = allVersions; + } + + public List getGroupIds() { + return groupIds; + } + public void setGroupIds(List groupIds) { + this.groupIds = groupIds; + } } diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/query/items/table/dmp/DataManagmentPlanPublicTableRequest.java b/dmp-backend/data/src/main/java/eu/eudat/data/query/items/table/dmp/DataManagmentPlanPublicTableRequest.java index ed0ecdb22..f359fcb4b 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/query/items/table/dmp/DataManagmentPlanPublicTableRequest.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/query/items/table/dmp/DataManagmentPlanPublicTableRequest.java @@ -36,10 +36,14 @@ public class DataManagmentPlanPublicTableRequest extends TableQuery root.join("associatedDmps").get("id").in(this.getCriteria().datasetProfile)); if (this.getCriteria().getDmpOrganisations() != null && !this.getCriteria().getDmpOrganisations().isEmpty()) query.where(((builder, root) -> root.join("organisations").get("reference").in(this.getCriteria().getDmpOrganisations()))); - - query.initSubQuery(String.class).where((builder, root) -> builder.equal(root.get("version"), - query.subQueryMax((builder1, externalRoot, nestedRoot) -> builder1.and(builder1.equal(externalRoot.get("groupId"), - nestedRoot.get("groupId")), builder1.equal(nestedRoot.get("isPublic"), true)), Arrays.asList(new SelectionField(FieldSelectionType.FIELD, "version")), String.class))); + if (!this.getCriteria().getAllVersions()) { + query.initSubQuery(String.class).where((builder, root) -> builder.equal(root.get("version"), + query.subQueryMax((builder1, externalRoot, nestedRoot) -> builder1.and(builder1.equal(externalRoot.get("groupId"), + nestedRoot.get("groupId")), builder1.equal(nestedRoot.get("isPublic"), true)), Arrays.asList(new SelectionField(FieldSelectionType.FIELD, "version")), String.class))); + } + if (this.getCriteria().getGroupIds() != null && !this.getCriteria().getGroupIds().isEmpty()) { + query.where((builder, root) -> root.get("groupId").in(this.getCriteria().getGroupIds())); + } return query; } diff --git a/dmp-frontend/src/app/core/query/explore-dmp/explore-dmp-criteria.ts b/dmp-frontend/src/app/core/query/explore-dmp/explore-dmp-criteria.ts index e577c31aa..376d14196 100644 --- a/dmp-frontend/src/app/core/query/explore-dmp/explore-dmp-criteria.ts +++ b/dmp-frontend/src/app/core/query/explore-dmp/explore-dmp-criteria.ts @@ -8,4 +8,6 @@ export class ExploreDmpCriteriaModel extends BaseCriteria { public grants: string[] = []; public datasetProfile: string[] = []; public dmpOrganisations: string[] = []; + public allVersions: boolean; + public groupIds: string[] = []; } diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts index bf196de0c..c9cb70752 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts @@ -485,14 +485,17 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), } }); - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - if (result && !result.cancelled) { - this.formGroup.get('status').setValue(DmpStatus.Finalized); - this.formGroup.get('datasetsToBeFinalized').setValue(result.datasetsToBeFinalized); - this.formSubmit(false); - dialogRef.close(); - } - }); + dialogRef.afterClosed() + .pipe(takeUntil(this._destroyed)) + .subscribe(result => { + if (result && !result.cancelled) { + this.formGroup.get('status').setValue(DmpStatus.Finalized); + this.formGroup.get('datasetsToBeFinalized').setValue(result.datasetsToBeFinalized); + this.formSubmit(false); + //this.router.navigate(['/plans/overview/' + this.formGroup.get('id').value]); + dialogRef.close(); + } + }); } // advancedClicked() { diff --git a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.html b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.html index 18d5dc1fe..04e6675f5 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.html +++ b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.html @@ -4,6 +4,14 @@

{{'DMP-LISTING.TITLE' | translate}} {{titlePrefix}}

+
+ + {{'DMP-LISTING.VIEW-ALL-VERSIONS' | translate}} + + + {{this.groupLabel}} + +
diff --git a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.scss b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.scss index 4def11f1b..ead048e9b 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.scss +++ b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.scss @@ -51,6 +51,14 @@ display: none !important; } +.all-versions { + color: #999999 !important; +} + +.dmp-label { + color: #089dbb !important; +} + // .bot-paginator { // margin-top: auto; // } diff --git a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts index 060eb213e..384dced5c 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts @@ -38,6 +38,8 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread titlePrefix: string; totalCount: number; listingItems: DmpListingModel[] = []; + allVersions: boolean = false; + groupLabel: string; constructor( private dmpService: DmpService, @@ -72,6 +74,25 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages)); }) + } else if (params['groupId']) { + this.itemId = params['groupId']; + this.showGrant = true; + const breadCrumbs = []; + this.allVersions = true; + + this.language.get('NAV-BAR.MY-DMPS').pipe(takeUntil(this._destroyed)).subscribe(x => { + this.breadCrumbs = observableOf([ + { + parentComponentName: null, + label: x, + url: '/plans' + }] + ); + }) + this.criteria.setCriteria(this.getDefaultCriteria()); + this.groupLabel = this.route.snapshot.queryParams.groupLabel; + this.refresh(); + this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages)); } else { this.itemId = params['groupId']; this.showGrant = true; diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts index 35a749461..4b2e8b51e 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts @@ -92,7 +92,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { setIsUserOwner() { if (this.dmp) { const principal: Principal = this.authentication.current(); - if (principal) this.isUserOwner = principal.id === this.dmp.users.find(x => x.role === Role.Owner).id; + if (principal) this.isUserOwner = principal.id === this.dmp.users.find(x => x.role === Role.Owner).id; } } @@ -385,7 +385,11 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { } viewVersions(rowId: String, rowLabel: String) { - this.router.navigate(['/plans/versions/' + rowId], { queryParams: { groupLabel: rowLabel } }); + if (this.dmp.isPublic && !this.isUserOwner) { + this.router.navigate(['/explore-plans/versions/' + rowId], { queryParams: { groupLabel: rowLabel } }); + } else { + this.router.navigate(['/plans/versions/' + rowId], { queryParams: { groupLabel: rowLabel } }); + } } public isAuthenticated(): boolean { diff --git a/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.ts b/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.ts index d9a1e5f5b..084a35f7f 100644 --- a/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.ts +++ b/dmp-frontend/src/app/ui/explore-dataset/filters/explore-dataset-filters.component.ts @@ -310,7 +310,7 @@ export class ExploreDatasetFiltersComponent extends BaseComponent implements OnI const fields: Array = new Array(); fields.push('-finalizedAt'); const dmpDataTableRequest: DataTableRequest = new DataTableRequest(0, null, { fields: fields }); - dmpDataTableRequest.criteria = new ExploreDatasetCriteriaModel(); + dmpDataTableRequest.criteria = new ExploreDmpCriteriaModel(); dmpDataTableRequest.criteria.like = value; return this.dmpService.getPublicPaged(dmpDataTableRequest, "autocomplete") } diff --git a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.html b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.html index 394cdf4b5..1652e34fe 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.html +++ b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.html @@ -10,7 +10,14 @@

{{'DMP-LISTING.TITLE' | translate}}

- +
+ + {{'DMP-LISTING.VIEW-ALL-VERSIONS' | translate}} + + + {{this.groupLabel}} + +
diff --git a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.scss b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.scss index d56c694f6..fa94d00e3 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.scss +++ b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.scss @@ -76,3 +76,11 @@ text-center { ::ng-deep .mat-paginator-navigation-previous { margin-left: auto !important; } + +.all-versions { + color: #999999 !important; +} + +.dmp-label { + color: #089dbb !important; +} diff --git a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.ts b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.ts index 0ab48acfb..9ca409955 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.ts +++ b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.ts @@ -24,12 +24,15 @@ export class ExploreDmpListingComponent extends BaseComponent implements OnInit, @ViewChild(MatPaginator, { static: true }) _paginator: MatPaginator; sort = new MatSort(); - exploreDmpCriteriaModel: ExploreDmpCriteriaModel; + exploreDmpCriteriaModel: ExploreDmpCriteriaModel = new ExploreDmpCriteriaModel(); titlePrefix: string; totalCount: number; listingItems: DmpListingModel[] = []; breadCrumbs: Observable; linkToDmpId: string; + groupId: string; + allVersions: boolean = false; + groupLabel: string; constructor( private dmpService: DmpService, @@ -43,15 +46,32 @@ export class ExploreDmpListingComponent extends BaseComponent implements OnInit, } ngOnInit() { - this.refresh(); + this.route.params + .pipe(takeUntil(this._destroyed)) + .subscribe(params => { + if (params['groupId']) { + this.groupId = params['groupId']; + this.exploreDmpCriteriaModel.groupIds.push(this.groupId); + this.exploreDmpCriteriaModel.allVersions = true; + this.allVersions = true; + this.route.queryParams + .pipe(takeUntil(this._destroyed)) + .subscribe(queryParams => { + if (queryParams["groupLabel"]) { + this.groupLabel = queryParams["groupLabel"]; + } + }) + } - const breadCrumbs = []; - breadCrumbs.push({ - parentComponentName: null, - label: this.language.instant('NAV-BAR.PUBLIC-DMPS'), - url: "/explore-plans" - }) - this.breadCrumbs = observableOf(breadCrumbs); + this.refresh(); + const breadCrumbs = []; + breadCrumbs.push({ + parentComponentName: null, + label: this.language.instant('NAV-BAR.PUBLIC-DMPS'), + url: "/explore-plans" + }) + this.breadCrumbs = observableOf(breadCrumbs); + }) } refresh() { @@ -76,6 +96,8 @@ export class ExploreDmpListingComponent extends BaseComponent implements OnInit, onCriteriaChange(event: ExploreDmpCriteriaModel) { this.exploreDmpCriteriaModel = event; + if (this.allVersions == true) this.exploreDmpCriteriaModel.allVersions = this.allVersions; + if (this.groupId) this.exploreDmpCriteriaModel.groupIds.push(this.groupId); this._paginator.pageIndex = 0; this.refresh(); } diff --git a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp.routing.ts b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp.routing.ts index 6b5ad0cb9..4918a250d 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp.routing.ts +++ b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp.routing.ts @@ -11,6 +11,13 @@ const routes: Routes = [ breadcrumb: true } }, + { + path: 'versions/:groupId', + component: ExploreDmpListingComponent, + data: { + breadcrumb: true + }, + }, { path: 'overview/:publicId', component: DmpOverviewComponent, diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 121132dd9..91bb8dcd0 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -411,7 +411,8 @@ "LEVEL-OF-ACCESS": "Level of Access", "INVOLVED-DATASETS": "Involved Dataset Descriptions", "TEMPLATES-INVOLVED": "Dataset Description Templates Involved" - } + }, + "VIEW-ALL-VERSIONS": "All versions of" }, "DMP-PUBLIC-LISTING": { "TITLE": "Published Data Management Plans", From 03f025764e46fa4f8397b03707493ef82ffe4ff3 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Fri, 10 Jan 2020 13:50:24 +0200 Subject: [PATCH 060/106] Fixes bug on published DMPs vesrion listing. --- .../listing-item/explore-dmp-listing-item.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmp-frontend/src/app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component.html b/dmp-frontend/src/app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component.html index b036ef35c..407534416 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component.html +++ b/dmp-frontend/src/app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component.html @@ -1,5 +1,5 @@
- +
From 009bd68f719e422e3b84981ee53e14c954c103bf Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Mon, 13 Jan 2020 10:59:48 +0200 Subject: [PATCH 061/106] Fixes bug on setting "Creation User" on a external fetched Grant. --- .../java/eu/eudat/logic/managers/DataManagementPlanManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index efa0dadfe..1770852b3 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -691,6 +691,7 @@ public class DataManagementPlanManager { if (grantEntity != null) grant.setId(grantEntity.getId()); else { grant.setType(Grant.GrantType.EXTERNAL.getValue()); + grant.setCreationUser(null); grantDao.createOrUpdate(grant); } } From bf5526103a163f995571804e507a92a2426ce5c6 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Mon, 13 Jan 2020 12:17:06 +0200 Subject: [PATCH 062/106] SQL scripts for updating "Reference" on Funder, Grant and Project to now use the "dmp:" prefix and their unique id as part of it. --- ...er_Grant_Project_References_For_Internal_Items.sql | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 dmp-db-scema/updates/06/02_Update_Funder_Grant_Project_References_For_Internal_Items.sql diff --git a/dmp-db-scema/updates/06/02_Update_Funder_Grant_Project_References_For_Internal_Items.sql b/dmp-db-scema/updates/06/02_Update_Funder_Grant_Project_References_For_Internal_Items.sql new file mode 100644 index 000000000..6fe80768b --- /dev/null +++ b/dmp-db-scema/updates/06/02_Update_Funder_Grant_Project_References_For_Internal_Items.sql @@ -0,0 +1,11 @@ +UPDATE "Funder" +SET "Reference" = CONCAT('dmp:', "ID") +WHERE "Reference" LIKE 'dmp:%'; + +UPDATE "Grant" +SET "Reference" = CONCAT('dmp:', "ID") +WHERE "Reference" LIKE 'dmp:%'; + +UPDATE "Project" +SET "Reference" = CONCAT('dmp:', "ID") +WHERE "Reference" LIKE 'dmp:%'; \ No newline at end of file From 2e2e003378a7867fb1ed48b988ae9e5a41cdfbb4 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Mon, 13 Jan 2020 18:22:13 +0200 Subject: [PATCH 063/106] SQL script for updating internal created researchers' "Reference". --- .../06/03_Update_Researcher_Internal_Entities_Reference.sql | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 dmp-db-scema/updates/06/03_Update_Researcher_Internal_Entities_Reference.sql diff --git a/dmp-db-scema/updates/06/03_Update_Researcher_Internal_Entities_Reference.sql b/dmp-db-scema/updates/06/03_Update_Researcher_Internal_Entities_Reference.sql new file mode 100644 index 000000000..080cf05d7 --- /dev/null +++ b/dmp-db-scema/updates/06/03_Update_Researcher_Internal_Entities_Reference.sql @@ -0,0 +1,6 @@ +UPDATE "Researcher" +SET "Reference" = CONCAT('dmp:', "ID") +WHERE "ID" IN ( + SELECT "ID" FROM "Researcher" + WHERE "Reference" LIKE 'dmp:%' +) \ No newline at end of file From 9d627a11daa1d680a10b95996ab6bb6d1ad95e14 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Tue, 14 Jan 2020 12:26:36 +0200 Subject: [PATCH 064/106] Adds functionality to create a map of keys and their respected display values of every external endpoint used in the configuration xml. --- .../config/configloaders/ConfigLoader.java | 2 + .../configloaders/DevelConfigLoader.java | 97 +++++++++++++++++-- .../configloaders/ProductionConfigLoader.java | 96 +++++++++++++++++- 3 files changed, 185 insertions(+), 10 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ConfigLoader.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ConfigLoader.java index 8a935aa53..37a166027 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ConfigLoader.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ConfigLoader.java @@ -5,10 +5,12 @@ import eu.eudat.logic.security.customproviders.ConfigurableProvider.entities.Con import org.apache.poi.xwpf.usermodel.XWPFDocument; import java.util.List; +import java.util.Map; public interface ConfigLoader { ExternalUrls getExternalUrls(); List getRdaProperties(); XWPFDocument getDocument(); ConfigurableProviders getConfigurableProviders(); + Map getKeyToSourceMap(); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DevelConfigLoader.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DevelConfigLoader.java index fa4885bae..6f613f64f 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DevelConfigLoader.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DevelConfigLoader.java @@ -9,16 +9,27 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import java.io.*; import java.net.URL; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Service("configLoader") @Profile("devel") @@ -28,6 +39,7 @@ public class DevelConfigLoader implements ConfigLoader { private List rdaProperties; private XWPFDocument document; private ConfigurableProviders configurableProviders; + private Map keyToSourceMap; @Autowired private Environment environment; @@ -58,7 +70,7 @@ public class DevelConfigLoader implements ConfigLoader { private void setRdaProperties() { String filePath = environment.getProperty("configuration.rda"); - String current = null; + String current; BufferedReader reader; List rdaList = new LinkedList<>(); try { @@ -79,7 +91,7 @@ public class DevelConfigLoader implements ConfigLoader { private void setDocument() { String filePath = environment.getProperty("configuration.h2020template"); - String current = null; + String current; InputStream is = null; try { current = new java.io.File(".").getCanonicalPath(); @@ -121,6 +133,30 @@ public class DevelConfigLoader implements ConfigLoader { } } + private void setKeyToSourceMap() { + String filePath = this.environment.getProperty("configuration.externalUrls"); + System.out.println("Loaded also config file: " + filePath); + Document doc = getXmlDocumentFromFilePath(filePath); + if (doc == null) { + this.keyToSourceMap = null; + return; + } + String xpathExpression = "//key"; + Map keysToSourceMap = new HashMap<>(); + List keys = getXmlValuesFromXPath(doc, xpathExpression); + keys = keys.stream().distinct().collect(Collectors.toList()); + for (String key : keys) { + String sourceExpression = String.format("//urlConfig[key='%s']/label", key); + List sources = getXmlValuesFromXPath(doc, sourceExpression); + if (sources.size() != 0) { + keysToSourceMap.put(key, sources.get(0)); + } + } + this.keyToSourceMap = keysToSourceMap; + } + + + public ExternalUrls getExternalUrls() { this.setExternalUrls(); return externalUrls; @@ -140,4 +176,53 @@ public class DevelConfigLoader implements ConfigLoader { this.setConfigurableProviders(); return configurableProviders; } + + public Map getKeyToSourceMap() { + this.setKeyToSourceMap(); + return keyToSourceMap; + } + + private Document getXmlDocumentFromFilePath(String filePath) { + InputStream is = null; + Document doc; + try { + String current = new java.io.File(".").getCanonicalPath(); + is = new URL("file:///" + current + filePath).openStream(); + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + doc = documentBuilder.parse(is); + return doc; + } catch (IOException | ParserConfigurationException | SAXException e) { + e.printStackTrace(); + } finally { + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + System.out.println("Warning: Could not close a stream after reading from file: " + filePath); + } + } + return null; + } + + private List getXmlValuesFromXPath(Document doc, String expression) { + XPath xPath = XPathFactory.newInstance().newXPath(); + NodeList nodeList = null; + List values = new LinkedList<>(); + try { + nodeList = (NodeList) xPath.compile(expression).evaluate(doc, XPathConstants.NODESET); + } catch (XPathExpressionException e) { + e.printStackTrace(); + } + if (nodeList != null) { + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + if (node.hasChildNodes()) { + values.add(nodeList.item(i).getChildNodes().item(0).getNodeValue()); + } + } + } + return values; + } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ProductionConfigLoader.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ProductionConfigLoader.java index 366ab1874..3d16a4950 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ProductionConfigLoader.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ProductionConfigLoader.java @@ -8,14 +8,28 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; import java.io.*; import java.net.URL; import java.nio.file.Paths; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Service("configLoader") @Profile({ "production", "staging" }) @@ -25,6 +39,7 @@ public class ProductionConfigLoader implements ConfigLoader { private List rdaProperties; private XWPFDocument document; private ConfigurableProviders configurableProviders; + private Map keyToSourceMap; @Autowired private Environment environment; @@ -36,7 +51,6 @@ public class ProductionConfigLoader implements ConfigLoader { InputStream is = null; try { current = new java.io.File(".").getCanonicalPath(); - JAXBContext jaxbContext = JAXBContext.newInstance(ExternalUrls.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); is = new URL(Paths.get(fileUrl).toUri().toURL().toString()).openStream(); @@ -75,13 +89,18 @@ public class ProductionConfigLoader implements ConfigLoader { private void setDocument() { String filePath = environment.getProperty("configuration.h2020template"); - String current = null; + InputStream is = null; try { - current = new java.io.File(".").getCanonicalPath(); - InputStream is = new URL(Paths.get(filePath).toUri().toURL().toString()).openStream(); + is = new URL(Paths.get(filePath).toUri().toURL().toString()).openStream(); this.document = new XWPFDocument(is); } catch (IOException e) { e.printStackTrace(); + } finally { + try { + if (is != null) is.close(); + } catch (IOException e) { + System.out.println("Warning: Could not close a stream after reading from file: " + filePath); + } } } @@ -107,6 +126,27 @@ public class ProductionConfigLoader implements ConfigLoader { } } } + private void setKeyToSourceMap() { + String filePath = this.environment.getProperty("configuration.externalUrls"); + System.out.println("Loaded also config file: " + filePath); + Document doc = getXmlDocumentFromFilePath(filePath); + if (doc == null) { + this.keyToSourceMap = null; + return; + } + String xpathExpression = "//key"; + Map keysToSourceMap = new HashMap<>(); + List keys = getXmlValuesFromXPath(doc, xpathExpression); + keys = keys.stream().distinct().collect(Collectors.toList()); + for (String key : keys) { + String sourceExpression = String.format("//urlConfig[key='%s']/label", key); + List sources = getXmlValuesFromXPath(doc, sourceExpression); + if (sources.size() != 0) { + keysToSourceMap.put(key, sources.get(0)); + } + } + this.keyToSourceMap = keysToSourceMap; + } public ExternalUrls getExternalUrls() { this.setExternalUrls(); @@ -127,4 +167,52 @@ public class ProductionConfigLoader implements ConfigLoader { this.setConfigurableProviders(); return configurableProviders; } + + public Map getKeyToSourceMap() { + this.setKeyToSourceMap(); + return keyToSourceMap; + } + + private Document getXmlDocumentFromFilePath(String filePath) { + InputStream is = null; + Document doc; + try { + is = new URL(Paths.get(filePath).toUri().toURL().toString()).openStream(); + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + doc = documentBuilder.parse(is); + return doc; + } catch (IOException | ParserConfigurationException | SAXException e) { + e.printStackTrace(); + } finally { + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + System.out.println("Warning: Could not close a stream after reading from file: " + filePath); + } + } + return null; + } + + private List getXmlValuesFromXPath(Document doc, String expression) { + XPath xPath = XPathFactory.newInstance().newXPath(); + NodeList nodeList = null; + List values = new LinkedList<>(); + try { + nodeList = (NodeList) xPath.compile(expression).evaluate(doc, XPathConstants.NODESET); + } catch (XPathExpressionException e) { + e.printStackTrace(); + } + if (nodeList != null) { + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + if (node.hasChildNodes()) { + values.add(nodeList.item(i).getChildNodes().item(0).getNodeValue()); + } + } + } + return values; + } } \ No newline at end of file From ff9aa1404721e3a80688d5c11c40e18071167b7c Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Tue, 14 Jan 2020 12:33:48 +0200 Subject: [PATCH 065/106] Refactors how researchers are fetched from external sources and saved in general. --- .../eu/eudat/data/entities/Researcher.java | 4 +- .../model/models/ResearcherBuilder.java | 23 +++++- .../logic/managers/ResearcherManager.java | 16 ++++- .../eu/eudat/models/data/dmp/Researcher.java | 71 +++++++++++++------ .../external/ExternalSourcesItemModel.java | 8 +++ .../ResearchersExternalSourcesModel.java | 3 +- .../app/core/model/researcher/researcher.ts | 1 + .../general-tab/general-tab.component.ts | 4 +- 8 files changed, 99 insertions(+), 31 deletions(-) diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/entities/Researcher.java b/dmp-backend/data/src/main/java/eu/eudat/data/entities/Researcher.java index 1ede09a23..7777a883f 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/entities/Researcher.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/entities/Researcher.java @@ -19,8 +19,8 @@ import java.util.UUID; public class Researcher implements DataEntity { @Id - @GeneratedValue - @GenericGenerator(name = "uuid2", strategy = "uuid2") + /*@GeneratedValue + @GenericGenerator(name = "uuid2", strategy = "uuid2")*/ @Column(name = "\"ID\"", updatable = false, nullable = false, columnDefinition = "BINARY(16)") private UUID id; diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/ResearcherBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/ResearcherBuilder.java index ba001431d..c8f9f0084 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/ResearcherBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/ResearcherBuilder.java @@ -3,15 +3,14 @@ package eu.eudat.logic.builders.model.models; import eu.eudat.logic.builders.Builder; import eu.eudat.models.data.dmp.Researcher; -/** - * Created by ikalyvas on 3/6/2018. - */ public class ResearcherBuilder extends Builder { private String label; private String name; private String id; + private String reference; private int status; private String tag; + private String key; public String getLabel() { return label; @@ -40,6 +39,13 @@ public class ResearcherBuilder extends Builder { return this; } + public String getReference() { return reference; } + + public ResearcherBuilder reference(String reference) { + this.reference = reference; + return this; + } + public int getStatus() { return status; } @@ -58,14 +64,25 @@ public class ResearcherBuilder extends Builder { return this; } + public String getKey() { + return key; + } + + public ResearcherBuilder key(String key) { + this.key = key; + return this; + } + @Override public Researcher build() { Researcher researcher = new Researcher(); researcher.setId(id); + researcher.setReference(reference); researcher.setLabel(label); researcher.setName(name); researcher.setStatus(status); researcher.setTag(tag); + researcher.setKey(key); return researcher; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/ResearcherManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/ResearcherManager.java index e09988e80..0d9104056 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/ResearcherManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/ResearcherManager.java @@ -3,6 +3,8 @@ package eu.eudat.logic.managers; import eu.eudat.logic.builders.model.models.ResearcherBuilder; import eu.eudat.data.entities.Researcher; import eu.eudat.logic.proxy.config.ExternalUrlCriteria; +import eu.eudat.logic.proxy.config.configloaders.ConfigLoader; +import eu.eudat.logic.utilities.helpers.ListHelper; import eu.eudat.models.data.external.ExternalSourcesItemModel; import eu.eudat.models.data.external.ResearchersExternalSourcesModel; import eu.eudat.data.query.items.item.researcher.ResearcherCriteriaRequest; @@ -17,7 +19,6 @@ import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.stream.Collectors; /** @@ -28,11 +29,13 @@ public class ResearcherManager { private ApiContext apiContext; private RemoteFetcher remoteFetcher; + private ConfigLoader configLoader; @Autowired - public ResearcherManager(ApiContext apiContext) { + public ResearcherManager(ApiContext apiContext, ConfigLoader configLoader) { this.apiContext = apiContext; this.remoteFetcher = apiContext.getOperationsContext().getRemoteFetcher(); + this.configLoader = configLoader; } public Researcher create(eu.eudat.models.data.researcher.Researcher researcher, Principal principal) throws Exception { @@ -46,6 +49,13 @@ public class ResearcherManager { QueryableList items = apiContext.getOperationsContext().getDatabaseRepository().getResearcherDao().getWithCriteria(researcherCriteriaRequest.getCriteria()); items.where((builder, root) -> builder.equal(root.get("creationUser").get("id"), principal.getId())); List researchers = items.select(item -> new eu.eudat.models.data.dmp.Researcher().fromDataModel(item)); + Map keyToSourceMap = configLoader.getKeyToSourceMap(); + for (eu.eudat.models.data.dmp.Researcher item : researchers) { + if (item.getKey().equals("Internal")) + item.setTag(item.getKey()); + else + item.setTag(keyToSourceMap.get(item.getKey())); + } ExternalUrlCriteria externalUrlCriteria = new ExternalUrlCriteria(researcherCriteriaRequest.getCriteria().getName()); List> remoteRepos = remoteFetcher.getResearchers(externalUrlCriteria,null); ResearchersExternalSourcesModel researchersExternalSourcesModel = new ResearchersExternalSourcesModel().fromExternalItem(remoteRepos); @@ -53,8 +63,10 @@ public class ResearcherManager { eu.eudat.models.data.dmp.Researcher researcher = apiContext.getOperationsContext().getBuilderFactory().getBuilder(ResearcherBuilder.class) .label(externalListingItem.getAbbreviation()) .id(externalListingItem.getId()) + .reference(externalListingItem.getRemoteId()) .name(externalListingItem.getName()) .tag(externalListingItem.getTag()) + .key(externalListingItem.getKey()) .build(); researchers.add(researcher); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Researcher.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Researcher.java index c610c92e6..17779610e 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Researcher.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Researcher.java @@ -4,18 +4,20 @@ import eu.eudat.models.DataModel; import eu.eudat.logic.utilities.helpers.LabelGenerator; import java.util.Date; +import java.util.UUID; public class Researcher implements DataModel, LabelGenerator { private String label; private String name; private String id; + private String reference; private int status; private String tag; + private String key; public String getLabel() { return label; } - public void setLabel(String label) { this.label = label; } @@ -23,7 +25,6 @@ public class Researcher implements DataModel> values) { for (Map item : values) { ExternalSourcesItemModel model = new ExternalSourcesItemModel(); - model.setId(item.get("pid")); + model.setRemoteId(item.get("pid")); model.setUri(item.get("uri")); model.setName(item.get("name")); model.setTag(item.get("tag")); + model.setKey(item.get("key")); this.add(model); } return this; diff --git a/dmp-frontend/src/app/core/model/researcher/researcher.ts b/dmp-frontend/src/app/core/model/researcher/researcher.ts index 0a1b250f6..6c5bf6a98 100644 --- a/dmp-frontend/src/app/core/model/researcher/researcher.ts +++ b/dmp-frontend/src/app/core/model/researcher/researcher.ts @@ -1,6 +1,7 @@ export interface ResearcherModel { id: String; name: String; + reference: String; lastName: String; uri: String; email: String; diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts index f02ac1a82..f931e3451 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts @@ -159,9 +159,9 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { const newItem = { label: null, name: fullName, - id: "dmp:" + fullName, + id: null, status: 0, - tag: "Internal", + key: "Internal", }; const researchersArray = this.formGroup.get('researchers').value || []; researchersArray.push(newItem); From 3aa7dc048114a940ba3350405ef180ea2da9a260 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Tue, 14 Jan 2020 13:00:02 +0200 Subject: [PATCH 066/106] Refactors Funder, Grant and Project external fetching by adding distinct values for key, indicating the source it was fetched, and it's respected display value. --- .../builders/model/models/FunderBuilder.java | 7 ++ .../builders/model/models/GrantBuilder.java | 11 +- .../builders/model/models/ProjectBuilder.java | 7 ++ .../eudat/logic/managers/FunderManager.java | 3 + .../eu/eudat/logic/managers/GrantManager.java | 1 + .../eudat/logic/managers/ProjectManager.java | 1 + .../logic/proxy/fetching/RemoteFetcher.java | 11 +- .../external/FundersExternalSourcesModel.java | 1 + .../external/GrantsExternalSourcesModel.java | 1 + .../ProjectsExternalSourcesModel.java | 7 ++ .../eu/eudat/models/data/funder/Funder.java | 35 ++++-- .../eu/eudat/models/data/grant/Grant.java | 30 +++-- .../eu/eudat/models/data/project/Project.java | 24 ++-- .../web/src/main/resources/ExternalUrls.xml | 116 +++++++++++++++--- 14 files changed, 201 insertions(+), 54 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/FunderBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/FunderBuilder.java index 0bbcc235f..ae8414d49 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/FunderBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/FunderBuilder.java @@ -17,6 +17,7 @@ public class FunderBuilder extends Builder { private Date modified; private Integer type; private String source; + private String key; public FunderBuilder id(UUID id) { this.id = id; @@ -63,6 +64,11 @@ public class FunderBuilder extends Builder { return this; } + public FunderBuilder key(String key) { + this.key = key; + return this; + } + @Override public Funder build() { Funder funder = new Funder(); @@ -75,6 +81,7 @@ public class FunderBuilder extends Builder { funder.setModified(modified); funder.setType(type); funder.setSource(source); + funder.setKey(key); return funder; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/GrantBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/GrantBuilder.java index 12f87f4d9..cd8d57df2 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/GrantBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/GrantBuilder.java @@ -9,9 +9,6 @@ import java.util.Date; import java.util.List; import java.util.UUID; -/** - * Created by ikalyvas on 2/15/2018. - */ public class GrantBuilder extends Builder { private UUID id; @@ -44,6 +41,8 @@ public class GrantBuilder extends Builder { private String source; + private String key; + public GrantBuilder id(UUID id) { this.id = id; return this; @@ -119,6 +118,11 @@ public class GrantBuilder extends Builder { return this; } + public GrantBuilder key(String key) { + this.key = key; + return this; + } + @Override public Grant build() { Grant grant = new Grant(); @@ -137,6 +141,7 @@ public class GrantBuilder extends Builder { grant.setCreationUser(creationUser); grant.setStartDate(startDate); grant.setSource(source); + grant.setKey(key); return grant; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/ProjectBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/ProjectBuilder.java index d0741d631..a0560d5d5 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/ProjectBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/ProjectBuilder.java @@ -28,6 +28,7 @@ public class ProjectBuilder extends Builder { private Date modified; private String description; private String source; + private String key; public ProjectBuilder id(UUID id) { this.id = id; @@ -109,6 +110,11 @@ public class ProjectBuilder extends Builder { return this; } + public ProjectBuilder key(String key) { + this.key = key; + return this; + } + @Override public Project build() { Project project = new Project(); @@ -127,6 +133,7 @@ public class ProjectBuilder extends Builder { project.setCreationUser(creationUser); project.setStartDate(startDate); project.setSource(source); + project.setKey(key); return project; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/FunderManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/FunderManager.java index 1db66f391..a14a1e8df 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/FunderManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/FunderManager.java @@ -3,6 +3,7 @@ package eu.eudat.logic.managers; import eu.eudat.data.query.items.item.funder.FunderCriteriaRequest; import eu.eudat.logic.builders.model.models.FunderBuilder; import eu.eudat.logic.proxy.config.ExternalUrlCriteria; +import eu.eudat.logic.proxy.config.configloaders.ConfigLoader; import eu.eudat.logic.proxy.config.exceptions.HugeResultSet; import eu.eudat.logic.proxy.config.exceptions.NoURLFound; import eu.eudat.logic.proxy.fetching.RemoteFetcher; @@ -47,6 +48,8 @@ public class FunderManager { eu.eudat.models.data.funder.Funder funder = apiContext.getOperationsContext().getBuilderFactory().getBuilder(FunderBuilder.class) .reference(externalListingItem.getRemoteId()).label(externalListingItem.getName()) .status(eu.eudat.data.entities.Funder.Status.fromInteger(0)) + .key(externalListingItem.getKey()) + .source(externalListingItem.getTag()) .build(); if (externalListingItem.getSource() != null) { funder.setSource(externalListingItem.getSource()); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/GrantManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/GrantManager.java index e3c0c7360..e69ca22e6 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/GrantManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/GrantManager.java @@ -134,6 +134,7 @@ public class GrantManager { eu.eudat.models.data.grant.Grant grant = apiContext.getOperationsContext().getBuilderFactory().getBuilder(GrantBuilder.class) .reference(externalListingItem.getRemoteId()).label(externalListingItem.getName()) .description(externalListingItem.getDescription()).uri(externalListingItem.getUri()) + .key(externalListingItem.getKey()) .abbreviation(externalListingItem.getAbbreviation()).status(eu.eudat.data.entities.Grant.Status.fromInteger(0)) .source(externalListingItem.getTag()) .build(); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/ProjectManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/ProjectManager.java index bd9b494b0..6919a5de5 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/ProjectManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/ProjectManager.java @@ -48,6 +48,7 @@ public class ProjectManager { .reference(externalListingItem.getRemoteId()).label(externalListingItem.getName()) .description(externalListingItem.getDescription()).uri(externalListingItem.getUri()) .abbreviation(externalListingItem.getAbbreviation()).status(eu.eudat.data.entities.Project.Status.fromInteger(0)) + .key(externalListingItem.getKey()) .source(externalListingItem.getTag()) .build(); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java index 9c6c90d44..3ffcfb193 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java @@ -129,7 +129,7 @@ public class RemoteFetcher { for (UrlConfiguration urlConfig : urlConfigs) { ifFunderQueryExist(urlConfig, externalUrlCriteria); if (urlConfig.getType() == null || urlConfig.getType().equals("External")) { - results.addAll(getAllResultsFromUrl(urlConfig.getUrl(), fetchStrategy, urlConfig.getData(), urlConfig.getPaginationPath(), externalUrlCriteria, urlConfig.getLabel(), urlConfig.getContentType(), urlConfig.getFirstpage())); + results.addAll(getAllResultsFromUrl(urlConfig.getUrl(), fetchStrategy, urlConfig.getData(), urlConfig.getPaginationPath(), externalUrlCriteria, urlConfig.getLabel(), urlConfig.getKey(), urlConfig.getContentType(), urlConfig.getFirstpage())); } else if (urlConfig.getType() != null && urlConfig.getType().equals("Internal")) { results.addAll(getAllResultsFromMockUpJson(urlConfig.getUrl(), externalUrlCriteria.getLike())); } @@ -184,14 +184,14 @@ public class RemoteFetcher { return completedPath; } - private List> getAllResultsFromUrl(String path, FetchStrategy fetchStrategy, final DataUrlConfiguration jsonDataPath, final String jsonPaginationPath, ExternalUrlCriteria externalUrlCriteria, String key, String contentType, String firstPage) throws HugeResultSet { + private List> getAllResultsFromUrl(String path, FetchStrategy fetchStrategy, final DataUrlConfiguration jsonDataPath, final String jsonPaginationPath, ExternalUrlCriteria externalUrlCriteria, String tag, String key, String contentType, String firstPage) throws HugeResultSet { Set pages = new HashSet<>(); String replacedPath = replaceCriteriaOnUrl(path, externalUrlCriteria, firstPage); Results results = getResultsFromUrl(replacedPath, jsonDataPath, jsonPaginationPath, contentType); if (fetchStrategy == FetchStrategy.FIRST) - return results == null ? new LinkedList<>() : results.getResults().stream().peek(x -> x.put("tag", key)).collect(Collectors.toList()); + return results == null ? new LinkedList<>() : results.getResults().stream().peek(x -> x.put("tag", tag)).peek(x -> x.put("key", key)).collect(Collectors.toList()); if (results != null && results.getPagination() != null && results.getPagination().get("pages") != null) //if has more pages, add them to the pages set for (int i = 2; i <= results.getPagination().get("pages"); i++) @@ -210,7 +210,7 @@ public class RemoteFetcher { Results remainingResults = optionalResults.orElseGet(Results::new); remainingResults.getResults().addAll(results.getResults()); - return remainingResults.getResults().stream().peek(x -> x.put("tag", key)).collect(Collectors.toList()); + return remainingResults.getResults().stream().peek(x -> x.put("tag", tag)).collect(Collectors.toList()); } @@ -271,8 +271,7 @@ public class RemoteFetcher { String filePath = Paths.get(path).toUri().toURL().toString(); ObjectMapper mapper = new ObjectMapper(); internalResults = mapper.readValue(new File(filePath), new TypeReference>>(){}); - searchListMap(internalResults, query); - return internalResults; + return searchListMap(internalResults, query); } catch (Exception e) { e.printStackTrace(); return new LinkedList<>(); diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/external/FundersExternalSourcesModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/external/FundersExternalSourcesModel.java index 5526a5552..9ef6c2c8d 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/external/FundersExternalSourcesModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/external/FundersExternalSourcesModel.java @@ -15,6 +15,7 @@ public class FundersExternalSourcesModel extends ExternalListingItem private Date modified; private Integer type; private String source; + private String key; public UUID getId() { return id; @@ -80,6 +81,13 @@ public class Funder implements DataModel this.source = source; } + public String getKey() { + return key; + } + public void setKey(String key) { + this.key = key; + } + @Override public Funder fromDataModel(eu.eudat.data.entities.Funder entity) { this.id = entity.getId(); @@ -93,9 +101,9 @@ public class Funder implements DataModel if (entity.getReference() != null) { String source = entity.getReference().substring(0, entity.getReference().indexOf(":")); if (source.equals("dmp")) { - this.source = "Internal"; + this.key = "Internal"; } else { - this.source = source; + this.key = source; } } @@ -105,19 +113,26 @@ public class Funder implements DataModel @Override public eu.eudat.data.entities.Funder toDataModel() { eu.eudat.data.entities.Funder entity = new eu.eudat.data.entities.Funder(); - entity.setId(UUID.randomUUID()); + if (this.getId() != null) { + entity.setId(this.getId()); + } else { + entity.setId(UUID.randomUUID()); + } entity.setLabel(this.label); entity.setType(this.type); - if (this.source != null && this.source.equals("Internal")) this.source = "dmp"; - if (this.source == null && this.reference != null && this.reference.startsWith("dmp:")) { - entity.setReference(this.reference); + // If internal, key has no value, fill it. + if ((this.source != null && this.source.equals("Internal")) || (this.key != null && this.key.equals("Internal"))) this.key = "dmp"; + // Logic for the different "key" cases. + if ((this.key == null || this.key.trim().isEmpty()) && (this.source != null && !this.source.trim().isEmpty())) { + this.key = this.source; } - if (this.reference != null && !this.reference.trim().isEmpty() - && this.source != null && !this.source.trim().isEmpty()) { - if (this.source.equals(this.reference.substring(0, this.source.length()))) { + if (this.reference != null && this.reference.startsWith("dmp:")) { + entity.setReference(this.reference); + } else if (this.reference != null && !this.reference.trim().isEmpty() && this.key != null && !this.key.trim().isEmpty()) { + if (this.key.equals(this.reference.substring(0, this.key.length()))) { entity.setReference(this.reference); } else { - entity.setReference(this.source.toLowerCase() + ":" + this.reference); + entity.setReference(this.key.toLowerCase() + ":" + this.reference); } } entity.setDefinition(this.definition); diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/grant/Grant.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/grant/Grant.java index 7d42a3964..798b3a6ab 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/grant/Grant.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/grant/Grant.java @@ -32,6 +32,7 @@ public class Grant implements DataModel { private List files; private UUID funderId; private String source; + private String key; public UUID getId() { return id; @@ -159,6 +160,13 @@ public class Grant implements DataModel { this.source = source; } + public String getKey() { + return key; + } + public void setKey(String key) { + this.key = key; + } + @Override public Grant fromDataModel(eu.eudat.data.entities.Grant entity) { this.id = entity.getId(); @@ -180,9 +188,9 @@ public class Grant implements DataModel { if (entity.getReference() != null) { String source = entity.getReference().substring(0, entity.getReference().indexOf(":")); if (source.equals("dmp")) { - this.source = "Internal"; + this.key = "Internal"; } else { - this.source = source; + this.key = source; } } @@ -192,20 +200,22 @@ public class Grant implements DataModel { @Override public eu.eudat.data.entities.Grant toDataModel() { eu.eudat.data.entities.Grant entity = new eu.eudat.data.entities.Grant(); - entity.setId(UUID.randomUUID()); + if (this.getId() != null) { + entity.setId(this.getId()); + } else { + entity.setId(UUID.randomUUID()); + } entity.setAbbreviation(this.abbreviation); entity.setLabel(this.label); entity.setType(this.type); - if (this.source != null && this.source.equals("Internal")) this.source = "dmp"; - if (this.source == null && this.reference != null && this.reference.startsWith("dmp:")) { + if ((this.source != null && this.source.equals("Internal")) || (this.key != null && this.key.equals("Internal"))) this.key = "dmp"; + if (this.reference != null && this.reference.startsWith("dmp:")) { entity.setReference(this.reference); - } - if (this.reference != null && !this.reference.trim().isEmpty() - && this.source != null && !this.source.trim().isEmpty()) { - if (this.source.equals(this.reference.substring(0, this.source.length()))) { + } else if (this.reference != null && !this.reference.trim().isEmpty() && this.key != null && !this.key.trim().isEmpty()) { + if (this.key.equals(this.reference.substring(0, this.key.length()))) { entity.setReference(this.reference); } else { - entity.setReference(this.source.toLowerCase() + ":" + this.reference); + entity.setReference(this.key.toLowerCase() + ":" + this.reference); } } entity.setUri(this.uri); diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/project/Project.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/project/Project.java index 45be84962..430eb6017 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/project/Project.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/project/Project.java @@ -29,6 +29,7 @@ public class Project implements DataModel files; private String source; + private String key; public UUID getId() { return id; @@ -149,6 +150,13 @@ public class Project implements DataModelInternal 1 Internal - mockData/RegistriesInternalMockUpData.json + web/src/main/resources/mockData/RegistriesInternalMockUpData.json $['data'][*]['attributes'] @@ -109,7 +109,7 @@ 1 Internal - mockData/TagsInternalMockUpData.json + web/src/main/resources/mockData/TagsInternalMockUpData.json $['data'][*]['attributes'] @@ -146,7 +146,7 @@ $['meta']['pagination']['page','pages','count'] - openAIRE + openaire 1 https://services.openaire.eu/search/v2/api/resources?query=((oaftype%20exact%20project)%20and%20((projectcode_nt%20exact%20%22{like}%22)or({like}))){funderQuery}&page={page}&size={pageSize}&format=json @@ -185,7 +185,7 @@ internal 1 - mockData/GrantInternalMockUpData.json + web/src/main/resources/mockData/GrantInternalMockUpData.json Internal $['data'][*]['attributes'] @@ -224,7 +224,7 @@ $['meta']['pagination']['page','pages','count'] - openAIRE + openaire 1 External @@ -265,7 +265,7 @@ 1 Internal - mockData/ProjectInternalMockUpData.json + web/src/main/resources/mockData/ProjectInternalMockUpData.json $['data'][*]['attributes'] @@ -283,6 +283,74 @@ + + openaire + + 1 + External + https://services.openaire.eu/search/v2/api/publications?&refine=true&fields=relfunder&page={page}&size=0&format=json + 0 + application/json; charset=utf-8 + + $['refineResults']['relfunder'][*] + + 'name' + 'id' + 'count' + + + + + openaire + + 1 + External + https://services.openaire.eu/search/v2/api/datasets?&refine=true&fields=relfunder&page=0&size={page}&format=json + 0 + application/json; charset=utf-8 + + $['refineResults']['relfunder'][*] + + 'name' + 'id' + 'count' + + + + + openaire + + 1 + External + https://services.openaire.eu/search/v2/api/software?&refine=true&fields=relfunder&page={page}&size=0&format=json + 0 + application/json; charset=utf-8 + + $['refineResults']['relfunder'][*] + + 'name' + 'id' + 'count' + + + + + openaire + + 1 + External + https://services.openaire.eu/search/v2/api/other?&refine=true&fields=relfunder&page={page}&size=0&format=json + 0 + application/json; charset=utf-8 + + $['refineResults']['relfunder'][*] + + 'name' + 'id' + 'count' + + + - openAire - + cristin + 1 External https://eestore.paas2.uninett.no/api/projectrepo/?search={like}&page={page}&size={pageSize} @@ -317,11 +385,26 @@ 'name' 'uri' 'description' - 'source' $['meta']['pagination']['page','pages','count'] + + crossref + + 1 + External + https://api.crossref.org/funders?query={like}&rows={pageSize} + application/json; charset=utf-8 + + $['message']['items'][*] + + 'name' + 'id' + 'count' + + + - - - -
diff --git a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.scss b/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.scss index e69de29bb..3d2ff8cf7 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.scss +++ b/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.scss @@ -0,0 +1,10 @@ +.toc-pane-container { + &.is-sticky~.nav-spacer { + height: 500px; // the container size } + // height: calc(100vh - 100px); // the container size } + } +} + +.is-sticky { + margin-top: 70px !important; +} diff --git a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts index a32b77b64..e1684f122 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts @@ -9,6 +9,7 @@ import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from "@ngx-translate/core"; import { Observable } from "rxjs"; import { takeUntil } from "rxjs/operators"; +import { LinkToScroll } from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents'; @Component({ selector: 'app-dataset-editor-wizard-component', @@ -122,4 +123,9 @@ export class DatasetEditorWizardComponent extends BaseComponent implements OnIni window.scrollTo(0, 0); } } + + linkToScroll: LinkToScroll; + onStepFound(linkToScroll: LinkToScroll) { + this.linkToScroll = linkToScroll; + } } diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.module.ts b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.module.ts index 99bdfc6e5..eda54f35c 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.module.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.module.ts @@ -14,6 +14,8 @@ import { QuickWizardEditorComponent } from '@app/ui/quick-wizard/quick-wizard-ed import { QuickWizardRoutingModule } from '@app/ui/quick-wizard/quick-wizard.routing'; import { CommonFormsModule } from '@common/forms/common-forms.module'; import { CommonUiModule } from '@common/ui/common-ui.module'; +import { TableOfContentsModule } from '../misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.module'; +import { AngularStickyThingsModule } from '@w11k/angular-sticky-things'; @NgModule({ imports: [ @@ -24,7 +26,9 @@ import { CommonUiModule } from '@common/ui/common-ui.module'; ConfirmationDialogModule, QuickWizardRoutingModule, DatasetDescriptionFormModule, - DmpModule + DmpModule, + TableOfContentsModule, + AngularStickyThingsModule ], declarations: [ GrantEditorWizardComponent, From 6bb9ef444dcac23d2b4c28843ca5bc7d693787e3 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Thu, 16 Jan 2020 12:32:25 +0200 Subject: [PATCH 079/106] Admin Login can performed also by pressing the Enter key (ref #223) --- .../src/app/ui/auth/admin-login/admin-login.component.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dmp-frontend/src/app/ui/auth/admin-login/admin-login.component.ts b/dmp-frontend/src/app/ui/auth/admin-login/admin-login.component.ts index 61c1cadf5..589b8a41c 100644 --- a/dmp-frontend/src/app/ui/auth/admin-login/admin-login.component.ts +++ b/dmp-frontend/src/app/ui/auth/admin-login/admin-login.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, HostListener } from '@angular/core'; import { Router } from '@angular/router'; import { Credential } from '@app/core/model/auth/credential'; import { AuthService } from '@app/core/services/auth/auth.service'; @@ -17,6 +17,10 @@ export class AdminLoginComponent extends BaseComponent implements OnInit { public auth2: any; public credential: Credential; + @HostListener('document:keydown.enter', ['$event']) onKeydownHandler() { + this.nativeLogin(); + } + constructor( private authService: AuthService, private uiNotificationService: UiNotificationService, From 116aa365c511fe9aa24230f6bc33ad59786923f4 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 16 Jan 2020 13:34:12 +0200 Subject: [PATCH 080/106] Refactors Organisation external fetching and fixes how reference prefix is added in respect of the that change. --- .../eu/eudat/controllers/Organisations.java | 13 ++- .../logic/builders/BuilderFactoryImpl.java | 5 +- .../model/models/OrganisationBuilder.java | 88 +++++++++++++++++++ .../logic/managers/OrganisationsManager.java | 30 +++++-- .../eudat/models/data/dmp/Organisation.java | 33 ++++--- .../OrganisationsExternalSourcesModel.java | 3 +- 6 files changed, 144 insertions(+), 28 deletions(-) create mode 100644 dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/OrganisationBuilder.java diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/Organisations.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/Organisations.java index 76b5557f3..2158b892c 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/Organisations.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/Organisations.java @@ -2,12 +2,10 @@ package eu.eudat.controllers; import eu.eudat.data.query.items.table.organisations.OrganisationsTableRequest; import eu.eudat.logic.managers.OrganisationsManager; -import eu.eudat.logic.proxy.config.ExternalUrlCriteria; import eu.eudat.logic.proxy.config.exceptions.HugeResultSet; import eu.eudat.logic.proxy.config.exceptions.NoURLFound; import eu.eudat.logic.services.ApiContext; import eu.eudat.models.data.dmp.Organisation; -import eu.eudat.models.data.external.OrganisationsExternalSourcesModel; import eu.eudat.models.data.helpers.common.DataTableData; import eu.eudat.models.data.helpers.responses.ResponseItem; import eu.eudat.models.data.security.Principal; @@ -19,7 +17,6 @@ import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.util.List; -import java.util.Map; @RestController @@ -28,6 +25,8 @@ import java.util.Map; public class Organisations extends BaseController { private OrganisationsManager organisationsManager; + private ApiContext apiContext; + @Autowired public Organisations(ApiContext apiContext, OrganisationsManager organisationsManager) { super(apiContext); @@ -36,13 +35,11 @@ public class Organisations extends BaseController { @RequestMapping(method = RequestMethod.GET, value = {"/external/organisations"}, produces = "application/json") public @ResponseBody - ResponseEntity> listExternalOrganisations( + ResponseEntity>> listExternalOrganisations( @RequestParam(value = "query", required = false) String query, @RequestParam(value = "type", required = false) String type ) throws HugeResultSet, NoURLFound { - ExternalUrlCriteria externalUrlCriteria = new ExternalUrlCriteria(query); - List> remoteRepos = this.getApiContext().getOperationsContext().getRemoteFetcher().getOrganisations(externalUrlCriteria, type); - OrganisationsExternalSourcesModel organisationsExternalSourcesModel = new OrganisationsExternalSourcesModel().fromExternalItem(remoteRepos); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(organisationsExternalSourcesModel).status(ApiMessageCode.NO_MESSAGE)); + List organisations = organisationsManager.getCriteriaWithExternal(query, type); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem>().payload(organisations).status(ApiMessageCode.NO_MESSAGE)); } @RequestMapping(method = RequestMethod.POST, value = {"/internal/organisations"}, produces = "application/json") diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/BuilderFactoryImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/BuilderFactoryImpl.java index 4bdaba8f3..9a99fcc9f 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/BuilderFactoryImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/BuilderFactoryImpl.java @@ -7,9 +7,7 @@ import eu.eudat.logic.builders.model.criteria.RegistryCriteriaBuilder; import eu.eudat.logic.builders.model.models.*; import org.springframework.stereotype.Service; -/** - * Created by ikalyvas on 2/15/2018. - */ + @Service("builderFactory") public class BuilderFactoryImpl implements BuilderFactory { @@ -29,6 +27,7 @@ public class BuilderFactoryImpl implements BuilderFactory { if (tClass.equals(ResearcherBuilder.class)) return (T) new ResearcherBuilder(); if (tClass.equals(ExternalDatasetCriteriaBuilder.class)) return (T) new ExternalDatasetCriteriaBuilder(); if (tClass.equals(RecentActivityDataBuilder.class)) return (T) new RecentActivityDataBuilder(); + if (tClass.equals(OrganisationBuilder.class)) return (T) new OrganisationBuilder(); return null; } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/OrganisationBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/OrganisationBuilder.java new file mode 100644 index 000000000..04e2ab7e8 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/OrganisationBuilder.java @@ -0,0 +1,88 @@ +package eu.eudat.logic.builders.model.models; + +import eu.eudat.logic.builders.Builder; +import eu.eudat.models.data.dmp.Organisation; + +public class OrganisationBuilder extends Builder { + private String label; + private String name; + private String id; + private String reference; + private int status; + private String tag; + private String key; + + public String getLabel() { + return label; + } + + public OrganisationBuilder label(String label) { + this.label = label; + return this; + } + + public String getName() { + return name; + } + + public OrganisationBuilder name(String name) { + this.name = name; + return this; + } + + public String getId() { + return id; + } + + public OrganisationBuilder id(String id) { + this.id = id; + return this; + } + + public String getReference() { return reference; } + + public OrganisationBuilder reference(String reference) { + this.reference = reference; + return this; + } + + public int getStatus() { + return status; + } + + public OrganisationBuilder status(int status) { + this.status = status; + return this; + } + + public String getTag() { + return tag; + } + + public OrganisationBuilder tag(String tag) { + this.tag = tag; + return this; + } + + public String getKey() { + return key; + } + + public OrganisationBuilder key(String key) { + this.key = key; + return this; + } + + @Override + public Organisation build() { + Organisation Organisation = new Organisation(); + Organisation.setId(id); + Organisation.setReference(reference); + Organisation.setLabel(label); + Organisation.setName(name); + Organisation.setStatus(status); + Organisation.setTag(tag); + Organisation.setKey(key); + return Organisation; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/OrganisationsManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/OrganisationsManager.java index 0f5d8617d..5e67be552 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/OrganisationsManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/OrganisationsManager.java @@ -1,24 +1,25 @@ package eu.eudat.logic.managers; -import eu.eudat.data.dao.criteria.OrganisationCriteria; import eu.eudat.data.dao.entities.OrganisationDao; -import eu.eudat.data.entities.DMP; -import eu.eudat.data.query.items.table.dmp.DataManagmentPlanPublicTableRequest; import eu.eudat.data.query.items.table.organisations.OrganisationsTableRequest; +import eu.eudat.logic.builders.model.models.OrganisationBuilder; +import eu.eudat.logic.proxy.config.ExternalUrlCriteria; +import eu.eudat.logic.proxy.config.exceptions.HugeResultSet; +import eu.eudat.logic.proxy.config.exceptions.NoURLFound; import eu.eudat.logic.services.ApiContext; import eu.eudat.logic.services.operations.DatabaseRepository; -import eu.eudat.models.HintedModelFactory; import eu.eudat.models.data.dmp.Organisation; +import eu.eudat.models.data.external.ExternalSourcesItemModel; +import eu.eudat.models.data.external.OrganisationsExternalSourcesModel; import eu.eudat.models.data.helpers.common.DataTableData; -import eu.eudat.models.data.listingmodels.DataManagementPlanListingModel; import eu.eudat.models.data.security.Principal; import eu.eudat.queryable.QueryableList; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @Component @@ -64,4 +65,21 @@ public class OrganisationsManager { return organisationDataTableData; } + + public List getCriteriaWithExternal(String query, String type) throws HugeResultSet, NoURLFound { + ExternalUrlCriteria externalUrlCriteria = new ExternalUrlCriteria(query); + List> remoteRepos = apiContext.getOperationsContext().getRemoteFetcher().getOrganisations(externalUrlCriteria, type); + OrganisationsExternalSourcesModel organisationsExternalSourcesModel = new OrganisationsExternalSourcesModel().fromExternalItem(remoteRepos); + List organisations = new LinkedList<>(); + for (ExternalSourcesItemModel externalListingItem : organisationsExternalSourcesModel) { + Organisation organisation = apiContext.getOperationsContext().getBuilderFactory().getBuilder(OrganisationBuilder.class) + .name(externalListingItem.getName()) + .reference(externalListingItem.getRemoteId()) + .tag(externalListingItem.getTag()) + .key(externalListingItem.getKey()) + .build(); + organisations.add(organisation); + } + return organisations.stream().distinct().collect(Collectors.toList()); + } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Organisation.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Organisation.java index 77e6b127b..0cb2b1296 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Organisation.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Organisation.java @@ -9,8 +9,10 @@ public class Organisation implements DataModel> values) { for (Map item : values) { ExternalSourcesItemModel model = new ExternalSourcesItemModel(); - model.setId(item.get("pid")); + model.setRemoteId(item.get("pid")); model.setUri(item.get("uri")); model.setName(item.get("name")); model.setTag(item.get("tag")); + model.setKey(item.get("key")); this.add(model); } return this; From 476915b23c6710edf853bf5fb85b0c628b16e954 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Thu, 16 Jan 2020 16:00:58 +0200 Subject: [PATCH 081/106] The DMPs on Dataset Editor (+ wizard) will have creation time subtitle and are ordered by creation time descended --- .../data/listingmodels/DataManagementPlanListingModel.java | 1 + .../dmp-selector/dataset-dmp-selector.component.ts | 3 ++- .../app/ui/dataset/dataset-wizard/dataset-wizard.component.ts | 3 ++- dmp-frontend/src/assets/i18n/en.json | 3 ++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DataManagementPlanListingModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DataManagementPlanListingModel.java index bfb8bf1cc..a942eb67d 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DataManagementPlanListingModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DataManagementPlanListingModel.java @@ -187,6 +187,7 @@ public class DataManagementPlanListingModel implements DataModel new AssociatedProfile().fromData(item)).collect(Collectors.toList()); return this; } diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts b/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts index 21105181b..619925565 100644 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts +++ b/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts @@ -50,6 +50,7 @@ export class DatasetDmpSelector extends BaseComponent implements OnInit, IBreadC initialItems: (extraData) => this.searchDmp(''), displayFn: (item) => item['label'], titleFn: (item) => item['label'], + subtitleFn: (item) => new Date(item['creationTime']).toISOString() }; this.formGroup.get('dmp').valueChanges @@ -71,7 +72,7 @@ export class DatasetDmpSelector extends BaseComponent implements OnInit, IBreadC searchDmp(query: string): Observable { const fields: Array = new Array(); - fields.push('asc'); + fields.push('-created'); const dmpDataTableRequest: DataTableRequest = new DataTableRequest(0, null, { fields: fields }); dmpDataTableRequest.criteria = new DmpCriteria(); dmpDataTableRequest.criteria.status = DmpStatus.Draft; diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts index a3b16e9dc..31cb4e454 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts @@ -92,6 +92,7 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr initialItems: (extraData) => this.searchDmp(''), displayFn: (item) => this.getDatasetDisplay(item), titleFn: (item) => item['label'], + subtitleFn: (item) => this.language.instant('DATASET-WIZARD.FIRST-STEP.SUB-TITLE') + new Date(item['creationTime']).toISOString() // iconFn: (item) => this.publicMode ? '' : (item['status'] ? 'lock' : 'lock_open'), // linkFn: (item) => this.publicMode ? '/explore-plans/overview/' + item['id'] : '/plans/overview/' + item['id'] }; @@ -345,7 +346,7 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr searchDmp(query: string): Observable { const fields: Array = new Array(); - fields.push('asc'); + fields.push('-created'); const dmpDataTableRequest: DataTableRequest = new DataTableRequest(0, null, { fields: fields }); dmpDataTableRequest.criteria = new DmpCriteria(); dmpDataTableRequest.criteria.like = query; diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 91bb8dcd0..323a66133 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -448,7 +448,8 @@ "FIRST-STEP": { "TITLE": "Dataset Description Information", "DMP": "Data Management Plan", - "PROFILE": "Dataset Description Template" + "PROFILE": "Dataset Description Template", + "SUB-TITLE": "Created At: " }, "SECOND-STEP": { "TITLE": "External References", From 691508aa0c05007acbe847aae1ab5eab30cb2ad5 Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Thu, 16 Jan 2020 17:14:50 +0200 Subject: [PATCH 082/106] Fixes bug on being able to fetch deleted DMPs on "DMP overview" view. --- .../src/main/java/eu/eudat/controllers/DMPs.java | 10 +++++++--- .../logic/managers/DataManagementPlanManager.java | 5 ++++- .../app/ui/dmp/overview/dmp-overview.component.ts | 15 ++++++++++++++- dmp-frontend/src/assets/i18n/en.json | 3 +++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java index c2652536c..659226f6b 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java @@ -115,9 +115,13 @@ public class DMPs extends BaseController { @RequestMapping(method = RequestMethod.GET, value = {"/overview/{id}"}) public @ResponseBody - ResponseEntity getOverviewSingle(@PathVariable String id, Principal principal) throws IllegalAccessException, InstantiationException { - DataManagementPlanOverviewModel dataManagementPlan = this.dataManagementPlanManager.getOverviewSingle(id, principal); - return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).payload(dataManagementPlan)); + ResponseEntity getOverviewSingle(@PathVariable String id, Principal principal) { + try { + DataManagementPlanOverviewModel dataManagementPlan = this.dataManagementPlanManager.getOverviewSingle(id, principal); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).payload(dataManagementPlan)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE)); + } } @RequestMapping(method = RequestMethod.GET, value = {"/public/{id}"}) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index 1770852b3..3bb21190f 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -359,8 +359,11 @@ public class DataManagementPlanManager { return dataManagementPlan; } - public DataManagementPlanOverviewModel getOverviewSingle(String id, Principal principal) throws InstantiationException, IllegalAccessException { + public DataManagementPlanOverviewModel getOverviewSingle(String id, Principal principal) throws Exception { DMP dataManagementPlanEntity = databaseRepository.getDmpDao().find(UUID.fromString(id)); + if (dataManagementPlanEntity.getStatus() == DMP.DMPStatus.DELETED.getValue()) { + throw new Exception("DMP is deleted."); + } if (dataManagementPlanEntity.getUsers() .stream().filter(userInfo -> userInfo.getUser().getId() == principal.getId()) .collect(Collectors.toList()).size() == 0) diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts index 4b2e8b51e..ee60fa07b 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts @@ -69,7 +69,11 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DMPS'), url: "/plans" }); breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/overview/' + this.dmp.id }); this.breadCrumbs = observableOf(breadCrumbs); - }) + }, (error: any) => { + if (error.status === 404) { + return this.onFetchingDeletedCallbackError('/plans/'); + } + }); } else if (publicId != null) { this.isNew = false; @@ -84,11 +88,20 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC-DMPS'), url: "/explore-plans" }); breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/publicOverview/' + this.dmp.id }); this.breadCrumbs = observableOf(breadCrumbs); + }, (error: any) => { + if (error.status === 404) { + return this.onFetchingDeletedCallbackError('/plans/'); + } }); } }); } + onFetchingDeletedCallbackError(redirectRoot: string) { + this.uiNotificationService.snackBarNotification(this.language.instant('DMP-OVERVIEW.ERROR.DELETED-DMP'), SnackBarNotificationLevel.Error); + this.router.navigate([redirectRoot]); + } + setIsUserOwner() { if (this.dmp) { const principal: Principal = this.authentication.current(); diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 91bb8dcd0..0a1b96930 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -502,6 +502,9 @@ "LEVEL-OF-ACCESS": "Level of Access", "INVOLVED-DATASETS": "Involved Dataset Descriptions", "TEMPLATES-INVOLVED": "Dataset Description Templates Involved" + }, + "ERROR": { + "DELETED-DMP": "The requested DMP is deleted" } }, "DATASET-LISTING": { From ae84be5844ebafb3372aa79b11b306eadac9310a Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Thu, 16 Jan 2020 17:46:24 +0200 Subject: [PATCH 083/106] Replaced System.out.println, System.err.println and printStackTrace with a logger (ref #223) --- .../data/converters/DateToUTCConverter.java | 7 +++-- .../eu/eudat/data/query/definition/Query.java | 9 +++--- .../eu/eudat/elastic/entities/Dataset.java | 5 +++- .../elastic/repository/ElasticRepository.java | 5 +++- .../QueryableHibernateList.java | 5 +++- .../java/eu/eudat/cache/ResponsesCache.java | 7 +++-- .../DynamicFunderConfigurationDevelImpl.java | 10 ++++--- .../DynamicFunderConfigurationProdImpl.java | 10 ++++--- .../DynamicGrantConfigurationDevelImpl.java | 10 ++++--- .../DynamicGrantConfigurationProdImpl.java | 10 ++++--- .../DynamicProjectConfigurationDevelImpl.java | 10 ++++--- .../DynamicProjectConfigurationProdImpl.java | 10 ++++--- .../eu/eudat/controllers/ContactEmail.java | 5 +++- .../main/java/eu/eudat/controllers/DMPs.java | 7 +++-- .../controllers/DatasetWizardController.java | 5 +++- .../ControllerErrorHandler.java | 15 +++++----- .../managers/DataManagementPlanManager.java | 11 +++++--- .../DataManagementProfileManager.java | 7 +++-- .../eudat/logic/managers/DatasetManager.java | 9 ++++-- .../logic/managers/DatasetProfileManager.java | 7 +++-- .../eudat/logic/managers/DocumentManager.java | 7 +++-- .../configloaders/DevelConfigLoader.java | 28 ++++++++++--------- .../configloaders/ProductionConfigLoader.java | 28 ++++++++++--------- .../logic/proxy/fetching/RemoteFetcher.java | 13 +++++---- .../CustomAuthenticationProvider.java | 10 ++++--- .../helpers/FileStorageServiceImpl.java | 5 +++- .../AbstractAuthenticationService.java | 5 +++- .../ConfirmationEmailServiceImpl.java | 13 +++++---- .../utilities/InvitationServiceImpl.java | 14 +++++----- .../services/utilities/MailServiceImpl.java | 5 +++- .../utilities/builders/ModelBuilder.java | 15 ++++++---- .../logic/utilities/builders/XmlBuilder.java | 9 ++++-- .../utilities/documents/word/WordBuilder.java | 5 +++- .../ImportXmlBuilderDatasetProfile.java | 5 +++- .../dmpXml/ImportXmlBuilderDmpProfile.java | 5 +++- .../eu/eudat/models/HintedModelFactory.java | 8 ++++-- .../eu/eudat/models/data/dmp/Researcher.java | 5 +++- .../ProjectsExternalSourcesModel.java | 5 +++- .../data/rda/DatasetRDAExportModel.java | 7 +++-- 39 files changed, 228 insertions(+), 128 deletions(-) diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/converters/DateToUTCConverter.java b/dmp-backend/data/src/main/java/eu/eudat/data/converters/DateToUTCConverter.java index 35fb84dae..e0fd8e070 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/converters/DateToUTCConverter.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/converters/DateToUTCConverter.java @@ -1,5 +1,7 @@ package eu.eudat.data.converters; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.format.datetime.DateFormatter; import javax.persistence.AttributeConverter; @@ -15,6 +17,7 @@ import java.util.TimeZone; */ @Converter public class DateToUTCConverter implements AttributeConverter { + private static final Logger logger = LoggerFactory.getLogger(DateToUTCConverter.class); @Override public Date convertToDatabaseColumn(Date attribute) { @@ -25,7 +28,7 @@ public class DateToUTCConverter implements AttributeConverter { String date = formatterIST.format(attribute); return formatterIST.parse(date); } catch (ParseException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } return null; } @@ -39,7 +42,7 @@ public class DateToUTCConverter implements AttributeConverter { String date = formatterIST.format(dbData); return formatterIST.parse(date); } catch (ParseException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } return null; } diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/query/definition/Query.java b/dmp-backend/data/src/main/java/eu/eudat/data/query/definition/Query.java index aee35ca35..cb808bae6 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/query/definition/Query.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/query/definition/Query.java @@ -3,8 +3,11 @@ package eu.eudat.data.query.definition; import eu.eudat.data.dao.criteria.Criteria; import eu.eudat.queryable.QueryableList; import eu.eudat.queryable.queryableentity.DataEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public abstract class Query, T extends DataEntity> implements CriteriaQuery { + private static final Logger logger = LoggerFactory.getLogger(Query.class); private C criteria; private QueryableList query; @@ -33,10 +36,8 @@ public abstract class Query, T extends DataEntity> impleme q.setCriteria(criteria); q.setQuery(query); return q; - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); + } catch (InstantiationException | IllegalAccessException e) { + logger.error (e.getMessage(), e); } return null; } diff --git a/dmp-backend/elastic/src/main/java/eu/eudat/elastic/entities/Dataset.java b/dmp-backend/elastic/src/main/java/eu/eudat/elastic/entities/Dataset.java index 2fca86b57..177417ffd 100644 --- a/dmp-backend/elastic/src/main/java/eu/eudat/elastic/entities/Dataset.java +++ b/dmp-backend/elastic/src/main/java/eu/eudat/elastic/entities/Dataset.java @@ -1,6 +1,8 @@ package eu.eudat.elastic.entities; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.LinkedList; @@ -11,6 +13,7 @@ import java.util.Map; * Created by ikalyvas on 7/5/2018. */ public class Dataset implements ElasticEntity { + private static final Logger logger = LoggerFactory.getLogger(Dataset.class); private String id; private List tags = new LinkedList<>(); @@ -40,7 +43,7 @@ public class Dataset implements ElasticEntity { try { x.toElasticEntity(builder); } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } }); builder.endArray(); diff --git a/dmp-backend/elastic/src/main/java/eu/eudat/elastic/repository/ElasticRepository.java b/dmp-backend/elastic/src/main/java/eu/eudat/elastic/repository/ElasticRepository.java index 90b9f3d36..aca4d8dea 100644 --- a/dmp-backend/elastic/src/main/java/eu/eudat/elastic/repository/ElasticRepository.java +++ b/dmp-backend/elastic/src/main/java/eu/eudat/elastic/repository/ElasticRepository.java @@ -6,6 +6,8 @@ import eu.eudat.elastic.entities.ElasticEntity; import org.elasticsearch.client.Client; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; @@ -13,6 +15,7 @@ import java.io.IOException; * Created by ikalyvas on 7/5/2018. */ public abstract class ElasticRepository implements Repository { + private static final Logger logger = LoggerFactory.getLogger(ElasticRepository.class); private RestHighLevelClient client; public RestHighLevelClient getClient() { @@ -29,7 +32,7 @@ public abstract class ElasticRepository implements QueryableList { + private static final Logger logger = LoggerFactory.getLogger(QueryableHibernateList.class); private Collector collector = new Collector(); private EntityManager manager; @@ -264,7 +267,7 @@ public class QueryableHibernateList implements QueryableLi try { return (T) this.tClass.newInstance().buildFromTuple(groupedResults.get(x.get("id")), this.fields, ""); } catch (InstantiationException | IllegalAccessException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } return null; }).collect(Collectors.toList())); diff --git a/dmp-backend/web/src/main/java/eu/eudat/cache/ResponsesCache.java b/dmp-backend/web/src/main/java/eu/eudat/cache/ResponsesCache.java index fc1dba6ae..c87d616ab 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/cache/ResponsesCache.java +++ b/dmp-backend/web/src/main/java/eu/eudat/cache/ResponsesCache.java @@ -2,6 +2,8 @@ package eu.eudat.cache; import com.google.common.cache.CacheBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.guava.GuavaCache; @@ -17,6 +19,7 @@ import java.util.concurrent.TimeUnit; @Component @EnableCaching public class ResponsesCache { + private static final Logger logger = LoggerFactory.getLogger(ResponsesCache.class); public static long HOW_MANY = 30; public static TimeUnit TIME_UNIT = TimeUnit.MINUTES; @@ -24,7 +27,7 @@ public class ResponsesCache { @Bean public CacheManager cacheManager() { - System.out.print("Loading ResponsesCache..."); + logger.info("Loading ResponsesCache..."); SimpleCacheManager simpleCacheManager = new SimpleCacheManager(); List caches = new ArrayList(); caches.add(new GuavaCache("repositories", CacheBuilder.newBuilder().expireAfterAccess(HOW_MANY, TIME_UNIT).build())); @@ -38,7 +41,7 @@ public class ResponsesCache { caches.add(new GuavaCache("researchers", CacheBuilder.newBuilder().expireAfterAccess(HOW_MANY, TIME_UNIT).build())); caches.add(new GuavaCache("externalDatasets", CacheBuilder.newBuilder().expireAfterAccess(HOW_MANY, TIME_UNIT).build())); simpleCacheManager.setCaches(caches); - System.out.println("OK"); + logger.info("OK"); return simpleCacheManager; } diff --git a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicfunder/DynamicFunderConfigurationDevelImpl.java b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicfunder/DynamicFunderConfigurationDevelImpl.java index a1839073d..edad07650 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicfunder/DynamicFunderConfigurationDevelImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicfunder/DynamicFunderConfigurationDevelImpl.java @@ -4,6 +4,8 @@ import eu.eudat.configurations.dynamicfunder.entities.Configuration; import eu.eudat.configurations.dynamicfunder.entities.Property; import eu.eudat.models.data.dynamicfields.Dependency; import eu.eudat.models.data.dynamicfields.DynamicField; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; @@ -19,6 +21,7 @@ import java.util.List; @Service("dynamicFunderConfiguration") @Profile("devel") public class DynamicFunderConfigurationDevelImpl implements DynamicFunderConfiguration { + private static final Logger logger = LoggerFactory.getLogger(DynamicFunderConfigurationDevelImpl.class); private Configuration configuration; private List fields; @@ -32,7 +35,7 @@ public class DynamicFunderConfigurationDevelImpl implements DynamicFunderConfigu public Configuration getConfiguration() { if (this.configuration != null) return this.configuration; String fileUrl = this.environment.getProperty("configuration.dynamicFunderUrl"); - System.out.println("Loaded also config file: " + fileUrl); + logger.info("Loaded also config file: " + fileUrl); String current = null; InputStream is = null; try { @@ -43,13 +46,12 @@ public class DynamicFunderConfigurationDevelImpl implements DynamicFunderConfigu is = new URL("file:///"+ current + "/web/src/main/resources/FunderConfiguration.xml").openStream(); this.configuration = (Configuration) jaxbUnmarshaller.unmarshal(is); } catch (Exception ex) { - ex.printStackTrace(); - System.out.println("Cannot find in folder" + current); + logger.error("Cannot find in folder" + current, ex); } finally { try { if (is != null) is.close(); } catch (IOException e) { - System.out.println("Warning: Could not close a stream after reading from file: " + fileUrl); + logger.warn("Warning: Could not close a stream after reading from file: " + fileUrl, e); } } return this.configuration; diff --git a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicfunder/DynamicFunderConfigurationProdImpl.java b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicfunder/DynamicFunderConfigurationProdImpl.java index 699ff9580..1e8adbfdc 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicfunder/DynamicFunderConfigurationProdImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicfunder/DynamicFunderConfigurationProdImpl.java @@ -4,6 +4,8 @@ import eu.eudat.configurations.dynamicfunder.entities.Configuration; import eu.eudat.configurations.dynamicfunder.entities.Property; import eu.eudat.models.data.dynamicfields.Dependency; import eu.eudat.models.data.dynamicfields.DynamicField; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; @@ -20,6 +22,7 @@ import java.util.List; @Service("dynamicFunderConfiguration") @Profile({ "production", "staging" }) public class DynamicFunderConfigurationProdImpl implements DynamicFunderConfiguration { + private static final Logger logger = LoggerFactory.getLogger(DynamicFunderConfigurationProdImpl.class); private Configuration configuration; private List fields; @@ -33,7 +36,7 @@ public class DynamicFunderConfigurationProdImpl implements DynamicFunderConfigur public Configuration getConfiguration() { if (this.configuration != null) return this.configuration; String fileUrl = this.environment.getProperty("configuration.dynamicFunderUrl"); - System.out.println("Loaded also config file: " + fileUrl); + logger.info("Loaded also config file: " + fileUrl); String current = null; InputStream is = null; try { @@ -44,13 +47,12 @@ public class DynamicFunderConfigurationProdImpl implements DynamicFunderConfigur is = new URL(Paths.get(fileUrl).toUri().toURL().toString()).openStream(); this.configuration = (Configuration) jaxbUnmarshaller.unmarshal(is); } catch (Exception ex) { - ex.printStackTrace(); - System.out.println("Cannot find in folder" + current); + logger.error("Cannot find in folder" + current, ex); } finally { try { if (is != null) is.close(); } catch (IOException e) { - System.out.println("Warning: Could not close a stream after reading from file: " + fileUrl); + logger.warn("Warning: Could not close a stream after reading from file: " + fileUrl, e); } } return this.configuration; diff --git a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicgrant/DynamicGrantConfigurationDevelImpl.java b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicgrant/DynamicGrantConfigurationDevelImpl.java index 92acd774a..13128d7d9 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicgrant/DynamicGrantConfigurationDevelImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicgrant/DynamicGrantConfigurationDevelImpl.java @@ -4,6 +4,8 @@ import eu.eudat.configurations.dynamicgrant.entities.Configuration; import eu.eudat.configurations.dynamicgrant.entities.Property; import eu.eudat.models.data.dynamicfields.Dependency; import eu.eudat.models.data.dynamicfields.DynamicField; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; @@ -24,6 +26,7 @@ import java.util.List; @Service("dynamicGrantConfiguration") @Profile("devel") public class DynamicGrantConfigurationDevelImpl implements DynamicGrantConfiguration { + private static final Logger logger = LoggerFactory.getLogger(DynamicGrantConfigurationDevelImpl.class); private Configuration configuration; @@ -40,7 +43,7 @@ public class DynamicGrantConfigurationDevelImpl implements DynamicGrantConfigura public Configuration getConfiguration() { if (this.configuration != null) return this.configuration; String fileUrl = this.environment.getProperty("configuration.dynamicGrantUrl"); - System.out.println("Loaded also config file: " + fileUrl); + logger.info("Loaded also config file: " + fileUrl); String current = null; InputStream is = null; try { @@ -51,13 +54,12 @@ public class DynamicGrantConfigurationDevelImpl implements DynamicGrantConfigura is = new URL("file:///"+ current + "/web/src/main/resources/GrantConfiguration.xml").openStream(); this.configuration = (Configuration) jaxbUnmarshaller.unmarshal(is); } catch (Exception ex) { - ex.printStackTrace(); - System.out.println("Cannot find in folder" + current); + logger.error("Cannot find in folder" + current, ex); } finally { try { if (is != null) is.close(); } catch (IOException e) { - System.out.println("Warning: Could not close a stream after reading from file: " + fileUrl); + logger.warn("Warning: Could not close a stream after reading from file: " + fileUrl, e); } } return this.configuration; diff --git a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicgrant/DynamicGrantConfigurationProdImpl.java b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicgrant/DynamicGrantConfigurationProdImpl.java index 9fc72b985..db6d0c0ec 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicgrant/DynamicGrantConfigurationProdImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicgrant/DynamicGrantConfigurationProdImpl.java @@ -4,6 +4,8 @@ import eu.eudat.configurations.dynamicgrant.entities.Configuration; import eu.eudat.configurations.dynamicgrant.entities.Property; import eu.eudat.models.data.dynamicfields.Dependency; import eu.eudat.models.data.dynamicfields.DynamicField; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; @@ -24,6 +26,7 @@ import java.util.List; @Service("dynamicGrantConfiguration") @Profile({ "production", "staging" }) public class DynamicGrantConfigurationProdImpl implements DynamicGrantConfiguration { + private static final Logger logger = LoggerFactory.getLogger(DynamicGrantConfigurationProdImpl.class); private Configuration configuration; @@ -40,7 +43,7 @@ public class DynamicGrantConfigurationProdImpl implements DynamicGrantConfigurat public Configuration getConfiguration() { if (this.configuration != null) return this.configuration; String fileUrl = this.environment.getProperty("configuration.dynamicGrantUrl"); - System.out.println("Loaded also config file: " + fileUrl); + logger.info("Loaded also config file: " + fileUrl); String current = null; InputStream is = null; try { @@ -51,13 +54,12 @@ public class DynamicGrantConfigurationProdImpl implements DynamicGrantConfigurat is = new URL(Paths.get(fileUrl).toUri().toURL().toString()).openStream(); this.configuration = (Configuration) jaxbUnmarshaller.unmarshal(is); } catch (Exception ex) { - ex.printStackTrace(); - System.out.println("Cannot find in folder" + current); + logger.error("Cannot find in folder" + current, ex); } finally { try { if (is != null) is.close(); } catch (IOException e) { - System.out.println("Warning: Could not close a stream after reading from file: " + fileUrl); + logger.warn("Warning: Could not close a stream after reading from file: " + fileUrl, e); } } return this.configuration; diff --git a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicproject/DynamicProjectConfigurationDevelImpl.java b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicproject/DynamicProjectConfigurationDevelImpl.java index 757990db1..fb1c17787 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicproject/DynamicProjectConfigurationDevelImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicproject/DynamicProjectConfigurationDevelImpl.java @@ -4,6 +4,8 @@ import eu.eudat.configurations.dynamicproject.entities.Configuration; import eu.eudat.configurations.dynamicproject.entities.Property; import eu.eudat.models.data.dynamicfields.Dependency; import eu.eudat.models.data.dynamicfields.DynamicField; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; @@ -20,6 +22,7 @@ import java.util.List; @Service("dynamicProjectConfiguration") @Profile("devel") public class DynamicProjectConfigurationDevelImpl implements DynamicProjectConfiguration{ + private static final Logger logger = LoggerFactory.getLogger(DynamicProjectConfigurationDevelImpl.class); private Configuration configuration; private List fields; @@ -34,7 +37,7 @@ public class DynamicProjectConfigurationDevelImpl implements DynamicProjectConfi public Configuration getConfiguration() { if (this.configuration != null) return this.configuration; String fileUrl = this.environment.getProperty("configuration.dynamicProjectUrl"); - System.out.println("Loaded also config file: " + fileUrl); + logger.info("Loaded also config file: " + fileUrl); String current = null; InputStream is = null; try { @@ -45,13 +48,12 @@ public class DynamicProjectConfigurationDevelImpl implements DynamicProjectConfi is = new URL("file:///"+ current + "/web/src/main/resources/ProjectConfiguration.xml").openStream(); this.configuration = (Configuration) jaxbUnmarshaller.unmarshal(is); } catch (Exception ex) { - ex.printStackTrace(); - System.out.println("Cannot find in folder" + current); + logger.error("Cannot find in folder" + current, ex); } finally { try { if (is != null) is.close(); } catch (IOException e) { - System.out.println("Warning: Could not close a stream after reading from file: " + fileUrl); + logger.warn("Warning: Could not close a stream after reading from file: " + fileUrl, e); } } return this.configuration; diff --git a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicproject/DynamicProjectConfigurationProdImpl.java b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicproject/DynamicProjectConfigurationProdImpl.java index a6627c6d1..f3ad8c010 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicproject/DynamicProjectConfigurationProdImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicproject/DynamicProjectConfigurationProdImpl.java @@ -4,6 +4,8 @@ import eu.eudat.configurations.dynamicproject.entities.Configuration; import eu.eudat.configurations.dynamicproject.entities.Property; import eu.eudat.models.data.dynamicfields.Dependency; import eu.eudat.models.data.dynamicfields.DynamicField; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; @@ -21,6 +23,7 @@ import java.util.List; @Service("dynamicProjectConfiguration") @Profile({ "production", "staging" }) public class DynamicProjectConfigurationProdImpl implements DynamicProjectConfiguration{ + private static final Logger logger = LoggerFactory.getLogger(DynamicProjectConfigurationProdImpl.class); private Configuration configuration; @@ -37,7 +40,7 @@ public class DynamicProjectConfigurationProdImpl implements DynamicProjectConfig public Configuration getConfiguration() { if (this.configuration != null) return this.configuration; String fileUrl = this.environment.getProperty("configuration.dynamicProjectUrl"); - System.out.println("Loaded also config file: " + fileUrl); + logger.info("Loaded also config file: " + fileUrl); String current = null; InputStream is = null; try { @@ -48,13 +51,12 @@ public class DynamicProjectConfigurationProdImpl implements DynamicProjectConfig is = new URL(Paths.get(fileUrl).toUri().toURL().toString()).openStream(); this.configuration = (Configuration) jaxbUnmarshaller.unmarshal(is); } catch (Exception ex) { - ex.printStackTrace(); - System.out.println("Cannot find in folder" + current); + logger.error("Cannot find in folder" + current, ex); } finally { try { if (is != null) is.close(); } catch (IOException e) { - System.out.println("Warning: Could not close a stream after reading from file: " + fileUrl); + logger.warn("Warning: Could not close a stream after reading from file: " + fileUrl, e); } } return this.configuration; diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/ContactEmail.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/ContactEmail.java index 5b0054cac..78b53595c 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/ContactEmail.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/ContactEmail.java @@ -5,6 +5,8 @@ import eu.eudat.models.data.ContactEmail.ContactEmailModel; import eu.eudat.models.data.helpers.responses.ResponseItem; import eu.eudat.models.data.security.Principal; import eu.eudat.types.ApiMessageCode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -15,6 +17,7 @@ import javax.transaction.Transactional; @CrossOrigin @RequestMapping(value = "api/contactEmail") public class ContactEmail { + private static final Logger logger = LoggerFactory.getLogger(ContactEmail.class); private ContactEmailManager contactEmailManager; @@ -31,7 +34,7 @@ public class ContactEmail { this.contactEmailManager.sendContactEmail(contactEmailModel, principal); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE)); } catch (Exception ex) { - ex.printStackTrace(); + logger.error(ex.getMessage(), ex); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE).message(ex.getMessage())); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java index c2652536c..19d28dcb5 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java @@ -29,6 +29,8 @@ import eu.eudat.models.data.security.Principal; import eu.eudat.query.DMPQuery; import eu.eudat.types.ApiMessageCode; import eu.eudat.types.Authorities; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.http.HttpHeaders; @@ -55,6 +57,7 @@ import java.util.UUID; @CrossOrigin @RequestMapping(value = {"/api/dmps/"}) public class DMPs extends BaseController { + private static final Logger logger = LoggerFactory.getLogger(DMPs.class); private DynamicGrantConfiguration dynamicGrantConfiguration; private Environment environment; @@ -195,7 +198,7 @@ public class DMPs extends BaseController { String name = file.getName().substring(0, file.getName().length() - 5); File pdffile = datasetManager.convertToPDF(file, environment, name); InputStream resource = new FileInputStream(pdffile); - System.out.println("Mime Type of " + file.getName() + " is " + + logger.info("Mime Type of " + file.getName() + " is " + new MimetypesFileTypeMap().getContentType(file)); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.setContentLength(pdffile.length()); @@ -269,7 +272,7 @@ public class DMPs extends BaseController { String zenodoDOI = this.dataManagementPlanManager.createZenodoDoi(UUID.fromString(id), principal, configLoader); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE).message("Successfully created DOI for Data Datamanagement Plan in question.").payload(zenodoDOI)); } catch (Exception e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE).message(e.getMessage())); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DatasetWizardController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DatasetWizardController.java index f25beabdd..17573e46a 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DatasetWizardController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DatasetWizardController.java @@ -19,6 +19,8 @@ import eu.eudat.models.data.security.Principal; import eu.eudat.models.data.user.composite.PagedDatasetProfile; import eu.eudat.types.ApiMessageCode; import org.apache.poi.util.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.http.HttpHeaders; @@ -44,6 +46,7 @@ import static eu.eudat.types.Authorities.ANONYMOUS; @CrossOrigin @RequestMapping(value = {"api/datasetwizard"}) public class DatasetWizardController extends BaseController { + private static final Logger logger = LoggerFactory.getLogger(DatasetWizardController.class); private Environment environment; private DatasetManager datasetManager; @@ -191,7 +194,7 @@ public class DatasetWizardController extends BaseController { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).message("Import was unsuccessful.")); } } catch (Exception e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).message("Import was unsuccessful.")); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/controllerhandler/ControllerErrorHandler.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/controllerhandler/ControllerErrorHandler.java index 55ff5e514..02054bdba 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/controllerhandler/ControllerErrorHandler.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/controllerhandler/ControllerErrorHandler.java @@ -4,11 +4,12 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.SerializationFeature; -import eu.eudat.core.logger.Logger; import eu.eudat.core.models.exception.ApiExceptionLoggingModel; import eu.eudat.models.data.helpers.responses.ResponseItem; import eu.eudat.models.data.security.Principal; import eu.eudat.types.ApiMessageCode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ControllerAdvice; @@ -27,13 +28,14 @@ import java.util.Map; @ControllerAdvice @Priority(5) public class ControllerErrorHandler { + private static final Logger logger = LoggerFactory.getLogger(ControllerErrorHandler.class); - private Logger logger; +// private Logger logger; - @Autowired + /*@Autowired public ControllerErrorHandler(Logger logger) { this.logger = logger; - } + }*/ @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @@ -49,12 +51,11 @@ public class ControllerErrorHandler { exceptionMap.put("exception", json); apiExceptionLoggingModel.setData(ow.writeValueAsString(exceptionMap)); } catch (JsonProcessingException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } apiExceptionLoggingModel.setMessage(ex.getMessage()); apiExceptionLoggingModel.setType(LoggingType.ERROR); - ex.printStackTrace(); - this.logger.error(apiExceptionLoggingModel); + logger.error(ex.getMessage(), ex); return new ResponseItem().message(ex.getMessage()).status(ApiMessageCode.DEFAULT_ERROR_MESSAGE); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index 1770852b3..0e998d33d 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -50,6 +50,8 @@ import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.core.io.FileSystemResource; @@ -76,6 +78,7 @@ import java.util.stream.Collectors; @Component public class DataManagementPlanManager { + private static final Logger logger = LoggerFactory.getLogger(DataManagementPlanManager.class); private ApiContext apiContext; private DatasetManager datasetManager; @@ -309,7 +312,7 @@ public class DataManagementPlanManager { try { wordBuilder.build(document, pagedDatasetProfile, visibilityRuleService); } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } // Page break at the end of the Dataset. XWPFParagraph parBreakDataset = document.createParagraph(); @@ -975,7 +978,7 @@ public class DataManagementPlanManager { try { mapper.writeValue(file, rdaExportModel); } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } InputStream resource = new FileInputStream(file); @@ -1033,7 +1036,7 @@ public class DataManagementPlanManager { DmpImportModel dmpImportModel = (DmpImportModel) jaxbUnmarshaller.unmarshal(in); dataManagementPlans.add(dmpImportModel); } catch (IOException | JAXBException ex) { - ex.printStackTrace(); + logger.error(ex.getMessage(), ex); } // TODO Iterate through the list of dataManagementPlans. // Creates new dataManagementPlan to fill it with the data model that was parsed from the xml. @@ -1096,7 +1099,7 @@ public class DataManagementPlanManager { //createOrUpdate(apiContext, dm, principal); - System.out.println(dm); + logger.info(dm.toString()); } return dataManagementPlans; diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementProfileManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementProfileManager.java index 1355b9884..983165034 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementProfileManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementProfileManager.java @@ -21,6 +21,8 @@ import eu.eudat.models.data.listingmodels.DataManagementPlanProfileListingModel; import eu.eudat.models.data.security.Principal; import eu.eudat.queryable.QueryableList; import eu.eudat.logic.services.ApiContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @@ -43,6 +45,7 @@ import org.w3c.dom.Element; */ @Component public class DataManagementProfileManager { + private static final Logger logger = LoggerFactory.getLogger(DataManagementProfileManager.class); private ApiContext apiContext; private DatabaseRepository databaseRepository; @@ -93,7 +96,7 @@ public class DataManagementProfileManager { public ResponseEntity getDocument(DataManagementPlanProfileListingModel dmpProfile, String label) throws IllegalAccessException, IOException, InstantiationException { FileEnvelope envelope = getXmlDocument(dmpProfile, label); InputStream resource = new FileInputStream(envelope.getFile()); - System.out.println("Mime Type of " + envelope.getFilename() + " is " + + logger.info("Mime Type of " + envelope.getFilename() + " is " + new MimetypesFileTypeMap().getContentType(envelope.getFile())); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.setContentLength(envelope.getFile().length()); @@ -124,7 +127,7 @@ public class DataManagementProfileManager { try { return xmlBuilder.build(convert(multiPartFile)); } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } return null; } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java index 4ae589f0b..ee76ea42c 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java @@ -36,6 +36,8 @@ import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.core.io.FileSystemResource; @@ -73,6 +75,7 @@ import java.util.zip.ZipInputStream; @Component public class DatasetManager { + private static final Logger logger = LoggerFactory.getLogger(DatasetManager.class); private ApiContext apiContext; private DatabaseRepository databaseRepository; @@ -544,7 +547,7 @@ public class DatasetManager { public ResponseEntity getDocument(String id, VisibilityRuleService visibilityRuleService, String contentType) throws IllegalAccessException, IOException, InstantiationException { FileEnvelope envelope = getXmlDocument(id, visibilityRuleService); InputStream resource = new FileInputStream(envelope.getFile()); - System.out.println("Mime Type of " + envelope.getFilename() + " is " + + logger.info("Mime Type of " + envelope.getFilename() + " is " + new MimetypesFileTypeMap().getContentType(envelope.getFile())); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.setContentLength(envelope.getFile().length()); @@ -574,7 +577,7 @@ public class DatasetManager { DatasetImportPagedDatasetProfile datasetImport = (DatasetImportPagedDatasetProfile) jaxbUnmarshaller.unmarshal(in); importModel = datasetImport; } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } // Checks if XML datasetProfileId GroupId matches the one selected. @@ -585,7 +588,7 @@ public class DatasetManager { throw new Exception(); } } catch (Exception e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); return null; } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetProfileManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetProfileManager.java index 7bff0808a..079359827 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetProfileManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetProfileManager.java @@ -22,6 +22,8 @@ import eu.eudat.models.data.externaldataset.ExternalAutocompleteFieldModel; import eu.eudat.models.data.helpers.common.DataTableData; import eu.eudat.queryable.QueryableList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.*; import org.springframework.stereotype.Component; @@ -41,6 +43,7 @@ import java.io.*; @Component public class DatasetProfileManager { + private static final Logger logger = LoggerFactory.getLogger(DatasetProfileManager.class); private ApiContext apiContext; private DatabaseRepository databaseRepository; @@ -119,7 +122,7 @@ public class DatasetProfileManager { public ResponseEntity getDocument(eu.eudat.models.data.user.composite.DatasetProfile datasetProfile, String label) throws IllegalAccessException, IOException, InstantiationException { FileEnvelope envelope = getXmlDocument(datasetProfile, label); InputStream resource = new FileInputStream(envelope.getFile()); - System.out.println("Mime Type of " + envelope.getFilename() + " is " + + logger.info("Mime Type of " + envelope.getFilename() + " is " + new MimetypesFileTypeMap().getContentType(envelope.getFile())); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.setContentLength(envelope.getFile().length()); @@ -151,7 +154,7 @@ public class DatasetProfileManager { try { return xmlBuilder.build(convert(multiPartFile)); } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } return null; } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DocumentManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DocumentManager.java index 1f7cfbee1..c50e987c7 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DocumentManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DocumentManager.java @@ -13,6 +13,8 @@ import eu.eudat.models.data.user.composite.PagedDatasetProfile; import org.apache.commons.io.IOUtils; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; import org.springframework.core.io.FileSystemResource; import org.springframework.http.*; @@ -36,6 +38,7 @@ import java.util.zip.ZipInputStream; */ @Service public class DocumentManager { + private static final Logger logger = LoggerFactory.getLogger(DocumentManager.class); private ApiContext context; private DatasetManager datasetManager; @@ -104,12 +107,12 @@ public class DocumentManager { Map mediaResult = new RestTemplate().getForObject(environment.getProperty("pdf.converter.url") + "/api/v1/" + queueResult.get("id"), Map.class); - System.out.println("Status: " + mediaResult.get("status")); + logger.info("Status: " + mediaResult.get("status")); while (!mediaResult.get("status").equals("finished")) { Thread.sleep(500); mediaResult = new RestTemplate().getForObject(environment.getProperty("pdf.converter.url") + "api/v1/" + queueResult.get("id"), Map.class); - System.out.println("Polling"); + logger.info("Polling"); } RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().add(new ByteArrayHttpMessageConverter()); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DevelConfigLoader.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DevelConfigLoader.java index 72769662b..14d5099f0 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DevelConfigLoader.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DevelConfigLoader.java @@ -5,6 +5,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import eu.eudat.logic.proxy.config.ExternalUrls; import eu.eudat.logic.security.customproviders.ConfigurableProvider.entities.ConfigurableProviders; import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; @@ -33,6 +35,7 @@ import java.util.stream.Collectors; @Service("configLoader") @Profile("devel") public class DevelConfigLoader implements ConfigLoader { + private static final Logger logger = LoggerFactory.getLogger(DevelConfigLoader.class); private ExternalUrls externalUrls; private List rdaProperties; @@ -45,7 +48,7 @@ public class DevelConfigLoader implements ConfigLoader { private void setExternalUrls() { String fileUrl = this.environment.getProperty("configuration.externalUrls"); - System.out.println("Loaded also config file: " + fileUrl); + logger.info("Loaded also config file: " + fileUrl); InputStream is = null; try { JAXBContext jaxbContext = JAXBContext.newInstance(ExternalUrls.class); @@ -53,13 +56,12 @@ public class DevelConfigLoader implements ConfigLoader { is = getClass().getClassLoader().getResource(fileUrl).openStream(); externalUrls = (ExternalUrls) jaxbUnmarshaller.unmarshal(is); } catch (Exception ex) { - ex.printStackTrace(); - System.err.println("Cannot find resource in classpath"); + logger.error("Cannot find resource in classpath", ex); } finally { try { if (is != null) is.close(); } catch (IOException | NullPointerException e) { - System.err.println("Warning: Could not close a stream after reading from file: " + fileUrl); + logger.warn("Warning: Could not close a stream after reading from file: " + fileUrl, e); } } } @@ -77,7 +79,7 @@ public class DevelConfigLoader implements ConfigLoader { } reader.close(); } catch (IOException | NullPointerException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } rdaProperties = rdaList; @@ -90,12 +92,12 @@ public class DevelConfigLoader implements ConfigLoader { is = getClass().getClassLoader().getResource(filePath).openStream(); this.document = new XWPFDocument(is); } catch (IOException | NullPointerException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } finally { try { if (is != null) is.close(); } catch (IOException e) { - System.err.println("Warning: Could not close a stream after reading from file: " + filePath); + logger.warn("Warning: Could not close a stream after reading from file: " + filePath, e); } } } @@ -108,19 +110,19 @@ public class DevelConfigLoader implements ConfigLoader { ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); this.configurableProviders = mapper.readValue(is, ConfigurableProviders.class); } catch (IOException | NullPointerException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } finally { try { if (is != null) is.close(); } catch (IOException e) { - System.err.println("Warning: Could not close a stream after reading from file: " + filePath); + logger.warn("Warning: Could not close a stream after reading from file: " + filePath, e); } } } private void setKeyToSourceMap() { String filePath = this.environment.getProperty("configuration.externalUrls"); - System.out.println("Loaded also config file: " + filePath); + logger.info("Loaded also config file: " + filePath); Document doc = getXmlDocumentFromFilePath(filePath); if (doc == null) { this.keyToSourceMap = null; @@ -177,14 +179,14 @@ public class DevelConfigLoader implements ConfigLoader { doc = documentBuilder.parse(is); return doc; } catch (IOException | ParserConfigurationException | SAXException | NullPointerException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } finally { try { if (is != null) { is.close(); } } catch (IOException e) { - System.out.println("Warning: Could not close a stream after reading from file: " + filePath); + logger.warn("Warning: Could not close a stream after reading from file: " + filePath, e); } } return null; @@ -197,7 +199,7 @@ public class DevelConfigLoader implements ConfigLoader { try { nodeList = (NodeList) xPath.compile(expression).evaluate(doc, XPathConstants.NODESET); } catch (XPathExpressionException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } if (nodeList != null) { for (int i = 0; i < nodeList.getLength(); i++) { diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ProductionConfigLoader.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ProductionConfigLoader.java index 3d16a4950..9d53f645f 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ProductionConfigLoader.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ProductionConfigLoader.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import eu.eudat.logic.proxy.config.ExternalUrls; import eu.eudat.logic.security.customproviders.ConfigurableProvider.entities.ConfigurableProviders; import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; @@ -34,6 +36,7 @@ import java.util.stream.Collectors; @Service("configLoader") @Profile({ "production", "staging" }) public class ProductionConfigLoader implements ConfigLoader { + private static final Logger logger = LoggerFactory.getLogger(ProductionConfigLoader.class); private ExternalUrls externalUrls; private List rdaProperties; @@ -46,7 +49,7 @@ public class ProductionConfigLoader implements ConfigLoader { private void setExternalUrls() { String fileUrl = this.environment.getProperty("configuration.externalUrls"); - System.out.println("Loaded also config file: " + fileUrl); + logger.info("Loaded also config file: " + fileUrl); String current = null; InputStream is = null; try { @@ -57,13 +60,12 @@ public class ProductionConfigLoader implements ConfigLoader { externalUrls = (ExternalUrls) jaxbUnmarshaller.unmarshal(is); } catch (Exception ex) { - ex.printStackTrace(); - System.out.println("Cannot find in folder" + current); + logger.error("Cannot find in folder" + current, ex); } finally { try { if (is != null) is.close(); } catch (IOException e) { - System.out.println("Warning: Could not close a stream after reading from file: " + fileUrl); + logger.warn("Warning: Could not close a stream after reading from file: " + fileUrl, e); } } } @@ -81,7 +83,7 @@ public class ProductionConfigLoader implements ConfigLoader { } reader.close(); } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } rdaProperties = rdaList; @@ -94,12 +96,12 @@ public class ProductionConfigLoader implements ConfigLoader { is = new URL(Paths.get(filePath).toUri().toURL().toString()).openStream(); this.document = new XWPFDocument(is); } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } finally { try { if (is != null) is.close(); } catch (IOException e) { - System.out.println("Warning: Could not close a stream after reading from file: " + filePath); + logger.warn("Warning: Could not close a stream after reading from file: " + filePath, e); } } } @@ -117,18 +119,18 @@ public class ProductionConfigLoader implements ConfigLoader { this.configurableProviders = new ConfigurableProviders(); } } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } finally { try { if (is != null) is.close(); } catch (IOException e) { - System.out.println("Warning: Could not close a stream after reading from file: " + filePath); + logger.warn("Warning: Could not close a stream after reading from file: " + filePath, e); } } } private void setKeyToSourceMap() { String filePath = this.environment.getProperty("configuration.externalUrls"); - System.out.println("Loaded also config file: " + filePath); + logger.info("Loaded also config file: " + filePath); Document doc = getXmlDocumentFromFilePath(filePath); if (doc == null) { this.keyToSourceMap = null; @@ -183,14 +185,14 @@ public class ProductionConfigLoader implements ConfigLoader { doc = documentBuilder.parse(is); return doc; } catch (IOException | ParserConfigurationException | SAXException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } finally { try { if (is != null) { is.close(); } } catch (IOException e) { - System.out.println("Warning: Could not close a stream after reading from file: " + filePath); + logger.warn("Warning: Could not close a stream after reading from file: " + filePath, e); } } return null; @@ -203,7 +205,7 @@ public class ProductionConfigLoader implements ConfigLoader { try { nodeList = (NodeList) xPath.compile(expression).evaluate(doc, XPathConstants.NODESET); } catch (XPathExpressionException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } if (nodeList != null) { for (int i = 0; i < nodeList.getLength(); i++) { diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java index 3ffcfb193..e7a53c40f 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java @@ -8,6 +8,8 @@ import eu.eudat.logic.proxy.config.*; import eu.eudat.logic.proxy.config.configloaders.ConfigLoader; import eu.eudat.logic.proxy.config.exceptions.HugeResultSet; import eu.eudat.logic.proxy.config.exceptions.NoURLFound; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @@ -25,6 +27,7 @@ import java.util.stream.Collectors; @Service public class RemoteFetcher { + private static final Logger logger = LoggerFactory.getLogger(RemoteFetcher.class); private ConfigLoader configLoader; @@ -163,7 +166,7 @@ public class RemoteFetcher { try { funderId = URLEncoder.encode(externalUrlCriteria.getFunderId(), "UTF-8"); } catch (UnsupportedEncodingException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } completedPath = completedPath.replace("{funderId}", funderId); } @@ -251,13 +254,13 @@ public class RemoteFetcher { return results; } } catch (MalformedURLException e1) { - e1.printStackTrace(); + logger.error(e1.getMessage(), e1); } //maybe print smth... catch (IOException e2) { - e2.printStackTrace(); + logger.error(e2.getMessage(), e2); } //maybe print smth... catch (Exception exception) { - exception.printStackTrace(); + logger.error(exception.getMessage(), exception); } //maybe print smth... finally { } @@ -273,7 +276,7 @@ public class RemoteFetcher { internalResults = mapper.readValue(new File(filePath), new TypeReference>>(){}); return searchListMap(internalResults, query); } catch (Exception e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); return new LinkedList<>(); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/security/CustomAuthenticationProvider.java b/dmp-backend/web/src/main/java/eu/eudat/logic/security/CustomAuthenticationProvider.java index 5e8c75dd6..f002d93d7 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/security/CustomAuthenticationProvider.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/security/CustomAuthenticationProvider.java @@ -6,6 +6,8 @@ import eu.eudat.exceptions.security.UnauthorisedException; import eu.eudat.models.data.login.LoginInfo; import eu.eudat.models.data.security.Principal; import eu.eudat.logic.security.validators.TokenValidatorFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -14,6 +16,7 @@ import java.security.GeneralSecurityException; @Component public class CustomAuthenticationProvider { + private static final Logger logger = LoggerFactory.getLogger(CustomAuthenticationProvider.class); @Autowired @@ -25,14 +28,13 @@ public class CustomAuthenticationProvider { Principal principal = this.tokenValidatorFactory.getProvider(credentials.getProvider()).validateToken(credentials); return principal; } catch (NonValidTokenException e) { - e.printStackTrace(); - System.out.println("Could not validate a user by his token! Reason: " + e.getMessage()); + logger.error("Could not validate a user by his token! Reason: " + e.getMessage(), e); throw new UnauthorisedException("Token validation failed - Not a valid token"); } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); throw new UnauthorisedException("IO Exeption"); } catch (NullEmailException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); throw new NullEmailException(); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/FileStorageServiceImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/FileStorageServiceImpl.java index e8909696f..244a8e503 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/FileStorageServiceImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/FileStorageServiceImpl.java @@ -2,6 +2,8 @@ package eu.eudat.logic.services.helpers; import eu.eudat.exceptions.files.TempFileNotFoundException; import eu.eudat.models.data.files.ContentFile; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; @@ -22,6 +24,7 @@ import java.util.UUID; */ @Service("fileStorageService") public class FileStorageServiceImpl implements FileStorageService { + private static final Logger logger = LoggerFactory.getLogger(FileStorageServiceImpl.class); private Environment environment; @@ -68,7 +71,7 @@ public class FileStorageServiceImpl implements FileStorageService { Files.createDirectory(Paths.get(environment.getProperty("files.storage.final"))); } } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/AbstractAuthenticationService.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/AbstractAuthenticationService.java index 731ea109c..cb7506ab6 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/AbstractAuthenticationService.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/AbstractAuthenticationService.java @@ -15,12 +15,15 @@ import eu.eudat.models.data.loginprovider.LoginProviderUser; import eu.eudat.models.data.security.Principal; import eu.eudat.types.Authorities; import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; import org.springframework.transaction.annotation.Transactional; import java.util.*; public abstract class AbstractAuthenticationService implements AuthenticationService { + private static final Logger logger = LoggerFactory.getLogger(AbstractAuthenticationService.class); protected ApiContext apiContext; protected Environment environment; @@ -86,7 +89,7 @@ public abstract class AbstractAuthenticationService implements AuthenticationSer try { credential = this.autoCreateUser(credentials.getUsername(), credentials.getSecret()); } catch (Exception e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); return null; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/ConfirmationEmailServiceImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/ConfirmationEmailServiceImpl.java index 9b7db8421..c92cb231b 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/ConfirmationEmailServiceImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/ConfirmationEmailServiceImpl.java @@ -1,9 +1,10 @@ package eu.eudat.logic.services.utilities; -import eu.eudat.core.logger.Logger; import eu.eudat.data.dao.entities.LoginConfirmationEmailDao; import eu.eudat.data.entities.LoginConfirmationEmail; import eu.eudat.models.data.mail.SimpleMail; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; @@ -13,11 +14,12 @@ import java.util.concurrent.CompletableFuture; @Service("ConfirmationEmailService") public class ConfirmationEmailServiceImpl implements ConfirmationEmailService { - private Logger logger; + private static final Logger logger = LoggerFactory.getLogger(ConfirmationEmailServiceImpl.class); + //private Logger logger; private Environment environment; - public ConfirmationEmailServiceImpl(Logger logger, Environment environment) { - this.logger = logger; + public ConfirmationEmailServiceImpl(/*Logger logger,*/ Environment environment) { +// this.logger = logger; this.environment = environment; } @@ -48,8 +50,7 @@ public class ConfirmationEmailServiceImpl implements ConfirmationEmailService { try { mailService.sendSimpleMail(mail); } catch (Exception ex) { - ex.printStackTrace(); - this.logger.error(ex, ex.getMessage()); + logger.error(ex.getMessage(), ex); } }); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/InvitationServiceImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/InvitationServiceImpl.java index 4f28028b4..ed175bda2 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/InvitationServiceImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/InvitationServiceImpl.java @@ -1,6 +1,5 @@ package eu.eudat.logic.services.utilities; -import eu.eudat.core.logger.Logger; import eu.eudat.core.models.exception.ApiExceptionLoggingModel; import eu.eudat.data.dao.entities.DMPDao; import eu.eudat.data.dao.entities.InvitationDao; @@ -8,6 +7,8 @@ import eu.eudat.data.entities.DMP; import eu.eudat.data.entities.Invitation; import eu.eudat.data.entities.UserInfo; import eu.eudat.models.data.mail.SimpleMail; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.http.HttpStatus; @@ -25,13 +26,13 @@ import java.util.stream.Collectors; @Service("invitationService") public class InvitationServiceImpl implements InvitationService { - - private Logger logger; + private static final Logger logger = LoggerFactory.getLogger(InvitationServiceImpl.class); +// private Logger logger; private Environment environment; @Autowired - public InvitationServiceImpl(Logger logger, Environment environment) { - this.logger = logger; + public InvitationServiceImpl(/*Logger logger,*/ Environment environment) { +// this.logger = logger; this.environment = environment; } @@ -75,8 +76,7 @@ public class InvitationServiceImpl implements InvitationService { try { mailService.sendSimpleMail(mail); } catch (Exception ex) { - ex.printStackTrace(); - this.logger.error(ex, ex.getMessage()); + logger.error(ex.getMessage(), ex); } }); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/MailServiceImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/MailServiceImpl.java index fb1983949..2ef6c4720 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/MailServiceImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/utilities/MailServiceImpl.java @@ -2,6 +2,8 @@ package eu.eudat.logic.services.utilities; import eu.eudat.models.data.mail.SimpleMail; import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.core.env.Environment; @@ -17,6 +19,7 @@ import java.io.*; @Service("mailService") public class MailServiceImpl implements MailService { + private static final Logger logger = LoggerFactory.getLogger(MailServiceImpl.class); private Environment env; @@ -54,7 +57,7 @@ public class MailServiceImpl implements MailService { IOUtils.copy(inputStream, writer, "UTF-8"); return writer.toString(); } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } return ""; } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/builders/ModelBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/builders/ModelBuilder.java index 76d14be74..906d3d392 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/builders/ModelBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/builders/ModelBuilder.java @@ -5,6 +5,8 @@ import eu.eudat.models.data.components.commons.datafield.*; import eu.eudat.models.data.entities.xmlmodels.modeldefinition.DatabaseModelDefinition; import eu.eudat.logic.utilities.interfaces.ModelDefinition; import eu.eudat.logic.utilities.interfaces.ViewStyleDefinition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Element; import java.util.LinkedList; @@ -12,15 +14,16 @@ import java.util.List; import java.util.Map; public class ModelBuilder { + private static final Logger logger = LoggerFactory.getLogger(ModelBuilder.class); public , T extends DatabaseModelDefinition> List toModelDefinition(List items, Class clazz) { List list = new LinkedList(); for (U item : items) { try { list.add(item.toDatabaseDefinition(clazz.newInstance())); } catch (InstantiationException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } catch (IllegalAccessException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } } return list; @@ -32,9 +35,9 @@ public class ModelBuilder { try { list.add(item.toDatabaseDefinition(clazz.newInstance())); } catch (InstantiationException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } catch (IllegalAccessException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } } return list; @@ -48,9 +51,9 @@ public class ModelBuilder { modelItem.fromDatabaseDefinition(item); list.add(modelItem); } catch (InstantiationException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } catch (IllegalAccessException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } } return list; diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/builders/XmlBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/builders/XmlBuilder.java index 7735fe326..408bbfde8 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/builders/XmlBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/builders/XmlBuilder.java @@ -1,5 +1,7 @@ package eu.eudat.logic.utilities.builders; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -21,6 +23,7 @@ import java.io.StringWriter; public class XmlBuilder { + private static final Logger logger = LoggerFactory.getLogger(XmlBuilder.class); public static Document getDocument() { DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); @@ -31,7 +34,7 @@ public class XmlBuilder { return doc; } catch (ParserConfigurationException e) { // TODO Auto-generated catch block - e.printStackTrace(); + logger.error(e.getMessage(), e); return null; } } @@ -48,7 +51,7 @@ public class XmlBuilder { return writer.toString(); } catch (TransformerException e) { // TODO Auto-generated catch block - e.printStackTrace(); + logger.error(e.getMessage(), e); return null; } } @@ -63,7 +66,7 @@ public class XmlBuilder { return doc; } catch (ParserConfigurationException | SAXException | IOException e) { // TODO Auto-generated catch block - e.printStackTrace(); + logger.error(e.getMessage(), e); return null; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java index 261ca04d4..39a217ec2 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java @@ -19,6 +19,8 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLvl; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STNumberFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.math.BigInteger; @@ -27,6 +29,7 @@ import java.util.List; import java.util.Map; public class WordBuilder { + private static final Logger logger = LoggerFactory.getLogger(WordBuilder.class); private Map> options = new HashMap<>(); private CTAbstractNum cTAbstractNum; @@ -186,7 +189,7 @@ public class WordBuilder { CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); number.setVal(BigInteger.valueOf(indent)); } catch (IOException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/ImportXmlBuilderDatasetProfile.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/ImportXmlBuilderDatasetProfile.java index ffd789d76..b7931bd74 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/ImportXmlBuilderDatasetProfile.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/ImportXmlBuilderDatasetProfile.java @@ -1,5 +1,7 @@ package eu.eudat.logic.utilities.documents.xml.datasetProfileXml; import eu.eudat.logic.utilities.documents.xml.datasetProfileXml.datasetProfileModel.DatasetProfile; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; @@ -7,6 +9,7 @@ import javax.xml.bind.Unmarshaller; import java.io.*; public class ImportXmlBuilderDatasetProfile { + private static final Logger logger = LoggerFactory.getLogger(ImportXmlBuilderDatasetProfile.class); public DatasetProfile build(File xmlFile) throws IOException { DatasetProfile datasetProfile = new DatasetProfile(); @@ -16,7 +19,7 @@ public class ImportXmlBuilderDatasetProfile { Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); datasetProfile = (DatasetProfile) unmarshaller.unmarshal(xmlFile); } catch (JAXBException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } return datasetProfile; diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/dmpXml/ImportXmlBuilderDmpProfile.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/dmpXml/ImportXmlBuilderDmpProfile.java index 717b6ac2b..7962beb51 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/dmpXml/ImportXmlBuilderDmpProfile.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/dmpXml/ImportXmlBuilderDmpProfile.java @@ -1,6 +1,8 @@ package eu.eudat.logic.utilities.documents.xml.dmpXml; import eu.eudat.logic.utilities.documents.xml.dmpXml.dmpProfileModel.DmpProfile; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; @@ -9,6 +11,7 @@ import java.io.File; import java.io.IOException; public class ImportXmlBuilderDmpProfile { + private static final Logger logger = LoggerFactory.getLogger(ImportXmlBuilderDmpProfile.class); public DmpProfile build(File xmlFile) throws IOException { DmpProfile dmpProfile = new DmpProfile(); @@ -18,7 +21,7 @@ public class ImportXmlBuilderDmpProfile { Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); dmpProfile = (DmpProfile) unmarshaller.unmarshal(xmlFile); } catch (JAXBException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } return dmpProfile; diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/HintedModelFactory.java b/dmp-backend/web/src/main/java/eu/eudat/models/HintedModelFactory.java index 15a418112..305aebc7d 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/HintedModelFactory.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/HintedModelFactory.java @@ -1,16 +1,20 @@ package eu.eudat.models; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class HintedModelFactory { + private static final Logger logger = LoggerFactory.getLogger(HintedModelFactory.class); public static String getHint(Class clazz) { try { return clazz.newInstance().getHint(); } catch (InstantiationException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); return null; } catch (IllegalAccessException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); return null; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Researcher.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Researcher.java index 17779610e..e891ffd78 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Researcher.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/dmp/Researcher.java @@ -2,11 +2,14 @@ package eu.eudat.models.data.dmp; import eu.eudat.models.DataModel; import eu.eudat.logic.utilities.helpers.LabelGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Date; import java.util.UUID; public class Researcher implements DataModel, LabelGenerator { + private static final Logger logger = LoggerFactory.getLogger(Researcher.class); private String label; private String name; private String id; @@ -104,7 +107,7 @@ public class Researcher implements DataModel { + private static final Logger logger = LoggerFactory.getLogger(ProjectsExternalSourcesModel.class); private static final ObjectMapper mapper = new ObjectMapper(); @Override @@ -61,7 +64,7 @@ public class ProjectsExternalSourcesModel extends ExternalListingItem multiplicityIdToFieldSetId = new HashMap<>(); @@ -165,7 +168,7 @@ public class DatasetRDAExportModel { String jsonResult = mapper.writeValueAsString(datasetManager.getSingle(dataset.getId().toString()).getDatasetProfileDefinition()); datasetDescriptionJson = new JSONObject(jsonResult); } catch (JsonProcessingException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } setMultiplicityIdToFieldSetId(datasetDescriptionJson); @@ -461,7 +464,7 @@ public class DatasetRDAExportModel { valuesList.add(node.getNodeValue()); } } catch (XPathExpressionException e) { - e.printStackTrace(); + logger.error(e.getMessage(), e); } return valuesList; From de4d7049294b3121b4bbb2d245492d29599e67bd Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Fri, 17 Jan 2020 13:36:00 +0200 Subject: [PATCH 084/106] On "My Dataset Descriptions" the Dataset descriptions will also show their DMP Version and can be filtered to show from all DMP Versions or the latest one --- .../eu/eudat/data/dao/criteria/DatasetCriteria.java | 8 ++++++++ .../eu/eudat/data/dao/entities/DatasetDaoImpl.java | 2 ++ .../data/listingmodels/DatasetListingModel.java | 9 +++++++++ .../src/app/core/model/dataset/dataset-listing.ts | 1 + .../src/app/core/query/dataset/dataset-criteria.ts | 3 ++- .../criteria/dataset-criteria.component.html | 9 ++++++++- .../listing/criteria/dataset-criteria.component.ts | 13 +++++++++---- .../ui/dataset/listing/dataset-listing.component.ts | 3 +++ .../dataset-listing-item.component.html | 6 ++++++ 9 files changed, 48 insertions(+), 6 deletions(-) diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DatasetCriteria.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DatasetCriteria.java index 8dac2b30f..7631c4d76 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DatasetCriteria.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DatasetCriteria.java @@ -21,6 +21,7 @@ public class DatasetCriteria extends Criteria { private List grants; private List collaborators; private List datasetTemplates; + private List groupIds; public boolean getAllVersions() { return allVersions; @@ -105,4 +106,11 @@ public class DatasetCriteria extends Criteria { public void setDatasetTemplates(List datasetTemplates) { this.datasetTemplates = datasetTemplates; } + + public List getGroupIds() { + return groupIds; + } + public void setGroupIds(List groupIds) { + this.groupIds = groupIds; + } } diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java index 6c56fe514..c2e703c7d 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetDaoImpl.java @@ -43,6 +43,8 @@ public class DatasetDaoImpl extends DatabaseAccess implements DatasetDa query.where((builder, root) -> builder.greaterThan(root.get("created"), criteria.getPeriodStart())); if (!criteria.getAllVersions()) query.initSubQuery(String.class).where((builder, root) -> builder.equal(root.get("dmp").get("version"), query.subQueryMax((builder1, externalRoot, nestedRoot) -> builder1.equal(externalRoot.get("dmp").get("groupId"), nestedRoot.get("dmp").get("groupId")), Arrays.asList(new SelectionField(FieldSelectionType.COMPOSITE_FIELD, "dmp:version")), String.class))); + if (criteria.getGroupIds() != null && !criteria.getGroupIds().isEmpty()) + query.where((builder, root) -> root.get("dmp").get("groupId").in(criteria.getGroupIds())); if (criteria.getDmpIds() != null && !criteria.getDmpIds().isEmpty()) query.where((builder, root) -> root.get("dmp").get("id").in(criteria.getDmpIds())); /*if (criteria.getRole() != null) { diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DatasetListingModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DatasetListingModel.java index d1cd16647..9906baeb6 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DatasetListingModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DatasetListingModel.java @@ -28,6 +28,7 @@ public class DatasetListingModel implements DataModel new Service().fromDataModel(item.getService())).collect(Collectors.toList())); this.finalizedAt = entity.getFinalizedAt(); this.dmpPublishedAt = entity.getDmp().getPublishedAt(); + this.version = entity.getDmp().getVersion(); return this; } diff --git a/dmp-frontend/src/app/core/model/dataset/dataset-listing.ts b/dmp-frontend/src/app/core/model/dataset/dataset-listing.ts index 1776ab9be..5202636ab 100644 --- a/dmp-frontend/src/app/core/model/dataset/dataset-listing.ts +++ b/dmp-frontend/src/app/core/model/dataset/dataset-listing.ts @@ -16,4 +16,5 @@ export interface DatasetListingModel { modified: Date; finalizedAt: Date; dmpPublishedAt?: Date; + version: number; } diff --git a/dmp-frontend/src/app/core/query/dataset/dataset-criteria.ts b/dmp-frontend/src/app/core/query/dataset/dataset-criteria.ts index 8d876e9b0..964a35c6b 100644 --- a/dmp-frontend/src/app/core/query/dataset/dataset-criteria.ts +++ b/dmp-frontend/src/app/core/query/dataset/dataset-criteria.ts @@ -6,9 +6,10 @@ export class DatasetCriteria extends BaseCriteria { public status?: Number; public dmpIds?: string[] = []; public tags?: ExternalSourceItemModel[] = []; - public allVersions?: boolean; + public allVersions?: boolean = true; public role?: number; public organisations?: string[] = []; public collaborators?: string[] = []; public datasetTemplates?: string[] = []; + public groupIds?: string[] = []; } diff --git a/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.html b/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.html index 674efe80e..a6a8af04e 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.html +++ b/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.html @@ -39,7 +39,7 @@
{{'CRITERIA.DATA-SETS.RELATED-DMP' | translate}}
- @@ -47,6 +47,13 @@
+ +
+
{{'CRITERIA.DATA-SETS.ALL-VERSIONS'| translate}}
+ +
+ +
{{'CRITERIA.DATA-SETS.RELATED-GRANT' | translate}}
diff --git a/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.ts b/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.ts index 21f2ee355..5aacdca71 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.ts +++ b/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria.component.ts @@ -52,14 +52,15 @@ export class DatasetCriteriaComponent extends BaseCriteriaComponent implements O public formGroup = new FormBuilder().group({ like: new FormControl(), - dmpIds: new FormControl(), + groupIds: new FormControl(), grants: new FormControl(), status: new FormControl(), role: new FormControl(), organisations: new FormControl(), collaborators: new FormControl(), datasetTemplates: new FormControl(), - tags: new FormControl() + tags: new FormControl(), + allVersions: new FormControl() }); tagsAutoCompleteConfiguration = { @@ -133,7 +134,7 @@ export class DatasetCriteriaComponent extends BaseCriteriaComponent implements O this.formGroup.get('like').valueChanges .pipe(takeUntil(this._destroyed)) .subscribe(x => this.controlModified()); - this.formGroup.get('dmpIds').valueChanges + this.formGroup.get('groupIds').valueChanges .pipe(takeUntil(this._destroyed)) .subscribe(x => this.controlModified()); this.formGroup.get('grants').valueChanges @@ -154,17 +155,21 @@ export class DatasetCriteriaComponent extends BaseCriteriaComponent implements O this.formGroup.get('datasetTemplates').valueChanges .pipe(takeUntil(this._destroyed)) .subscribe(x => this.controlModified()); + this.formGroup.get('allVersions').valueChanges + .pipe(takeUntil(this._destroyed)) + .subscribe(x => this.controlModified()); // if (this.criteria == null) { this.criteria = {}; } } setCriteria(criteria: DatasetCriteria): void { this.formGroup.get('like').patchValue(criteria.like); - this.formGroup.get('dmpIds').patchValue(criteria.dmpIds); + this.formGroup.get('groupIds').patchValue(criteria.groupIds); this.formGroup.get('grants').patchValue(criteria.grants); this.formGroup.get('status').patchValue(criteria.status); this.formGroup.get('role').patchValue(criteria.role); this.formGroup.get('collaborators').patchValue(criteria.collaborators); this.formGroup.get('datasetTemplates').patchValue(criteria.datasetTemplates); + this.formGroup.get('allVersions').patchValue(criteria.allVersions); // this.criteria = criteria; } diff --git a/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts b/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts index 8a06012ab..af9aceece 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts +++ b/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts @@ -113,6 +113,9 @@ export class DatasetListingComponent extends BaseComponent implements OnInit, IB if (value.dmpIds) { request.criteria.dmpIds = value.dmpIds.map(x => x.id); } + if (value.groupIds) { + request.criteria.groupIds = value.groupIds.map(x => x.groupId); + } if (value.grants) { request.criteria.grants = value.grants.map(x => x.id); } diff --git a/dmp-frontend/src/app/ui/dataset/listing/listing-item/dataset-listing-item.component.html b/dmp-frontend/src/app/ui/dataset/listing/listing-item/dataset-listing-item.component.html index da72a5cb5..012bc584f 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/listing-item/dataset-listing-item.component.html +++ b/dmp-frontend/src/app/ui/dataset/listing/listing-item/dataset-listing-item.component.html @@ -59,6 +59,12 @@
{{ dataset.profile }}
+
+ + history + +

{{ dataset.version }}

+

{{'DATASET-LISTING.COLUMNS.LAST-EDITED' | translate}} {{ dataset.modified | date: "shortDate"}}

From ed5c87d729e6a93f51c0677cd5040bc66210ba1b Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Fri, 17 Jan 2020 15:39:14 +0200 Subject: [PATCH 085/106] Add missing file --- dmp-frontend/src/assets/i18n/en.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 8c5f99ba2..1c78bee79 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -544,7 +544,8 @@ }, "DMP": "DMP", "GRANT": "Grant", - "TEMPLATES-INVOLVED": "Dataset Description Template" + "TEMPLATES-INVOLVED": "Dataset Description Template", + "VERSION": "DMP Version" } }, "DATASET-PUBLIC-LISTING": { @@ -760,7 +761,8 @@ "SELECT-COLLABORATORS": "Select Collaborators", "RELATED-COLLABORATORS": "Related Collaborators", "SELECT-DATASET-TEMPLATES": "Select Dataset Description Templates", - "RELATED-DATASET-TEMPLATES": "Related Dataset Description Templates" + "RELATED-DATASET-TEMPLATES": "Related Dataset Description Templates", + "ALL-VERSIONS": "From All Versions" }, "DMP": { "LIKE": "Search DMPs", From 15c256e7ebad4e2047baebb14a27d77fdc5cf53c Mon Sep 17 00:00:00 2001 From: gkolokythas Date: Fri, 17 Jan 2020 18:14:21 +0200 Subject: [PATCH 086/106] Fixes how "creation time" is displayed on "ADD Dataset Description (Wizard)" view. (Issue #223) --- .../dmp-selector/dataset-dmp-selector.component.ts | 8 +++++--- dmp-frontend/src/assets/i18n/en.json | 7 +++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts b/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts index 619925565..f2600e2e7 100644 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts +++ b/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts @@ -18,6 +18,8 @@ import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadC import { BaseComponent } from '@common/base/base.component'; import { Observable } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; +import { DatePipe } from "@angular/common"; +import { TranslateService } from "@ngx-translate/core"; @Component({ selector: 'dataset-dmp-selector-component', @@ -36,10 +38,10 @@ export class DatasetDmpSelector extends BaseComponent implements OnInit, IBreadC availableProfiles: DatasetProfileModel[] = []; constructor( - private router: Router, - private route: ActivatedRoute, public dmpService: DmpService, private datasetWizardService: DatasetWizardService, + private language: TranslateService, + private datepipe: DatePipe ) { super(); } @@ -50,7 +52,7 @@ export class DatasetDmpSelector extends BaseComponent implements OnInit, IBreadC initialItems: (extraData) => this.searchDmp(''), displayFn: (item) => item['label'], titleFn: (item) => item['label'], - subtitleFn: (item) => new Date(item['creationTime']).toISOString() + subtitleFn: (item) => this.language.instant('QUICKWIZARD.CREATE-ADD.ADD.CREATED') + " " + this.datepipe.transform(item['creationTime'], 'yyyy-MM-dd') }; this.formGroup.get('dmp').valueChanges diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 1c78bee79..5ff1929e7 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -1146,9 +1146,7 @@ "CREATE-NEW-FUNDER": "Add Funder", "EXIST-FUNDER": "Use Existing Funder", "CREATE-NEW-PROJECT": "Add Project", - "EXIST-PROJECT": "Use Existing Project", - "CREATE-NEW-FUNDER": "Add Funder", - "EXIST-FUNDER": "Use Existing Funder" + "EXIST-PROJECT": "Use Existing Project" }, "FIRST-STEP": { "TITLE": "Grant", @@ -1200,7 +1198,8 @@ "TITLE": "Add a Dataset Description into an existing DMP", "DATASET-WIZARD": "Dataset Description Wizard", "POST-SELECTION-INFO": "This wizard simplifies the process of adding new Dataset Descriptions into existing DMPs, guiding you through and requesting only the most essential pieces of information for completing the task. Full access to the attributes of a Dataset Description can be obtained afterwards via the Dataset Description access menus of the System.", - "SUBTITLE": "This wizard allows you to describe additional Dataset Descriptions managed in the context of a DMP providing only the essential information for their description." + "SUBTITLE": "This wizard allows you to describe additional Dataset Descriptions managed in the context of a DMP providing only the essential information for their description.", + "CREATED": "Created on" } }, "SAVE-DIALOG": { From 4e7e2691305a8be3ac19a8d2b33e55f7d5fec4fc Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Mon, 20 Jan 2020 11:00:05 +0200 Subject: [PATCH 087/106] When cloning Datasets with external references properly get the DataRepository id and the ExternalDatatset id and copy the data from the original (ref #226) --- .../eu/eudat/logic/managers/DataManagementPlanManager.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index 0eac9d67f..a299608db 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -788,11 +788,12 @@ public class DataManagementPlanManager { if (newDataset.getDatasetDataRepositories() != null) { newDataset.setDatasetDataRepositories(newDataset.getDatasetDataRepositories().stream().map(item -> { DataRepository dataRepository = new DataRepository(); - dataRepository.setId(item.getId()); + dataRepository.setId(item.getDataRepository().getId()); DatasetDataRepository datasetDataRepository = new DatasetDataRepository(); datasetDataRepository.setDataRepository(dataRepository); datasetDataRepository.setDataset(newDataset); + datasetDataRepository.setData(item.getData()); return datasetDataRepository; }).collect(Collectors.toSet())); } @@ -800,10 +801,11 @@ public class DataManagementPlanManager { if (newDataset.getDatasetExternalDatasets() != null) { newDataset.setDatasetExternalDatasets(newDataset.getDatasetExternalDatasets().stream().map(item -> { ExternalDataset externalDataset = new ExternalDataset(); - externalDataset.setId(item.getId()); + externalDataset.setId(item.getExternalDataset().getId()); DatasetExternalDataset datasetExternalDataset = new DatasetExternalDataset(); datasetExternalDataset.setExternalDataset(externalDataset); datasetExternalDataset.setDataset(newDataset); + datasetExternalDataset.setData(item.getData()); return datasetExternalDataset; }).collect(Collectors.toSet())); } @@ -823,6 +825,7 @@ public class DataManagementPlanManager { DatasetService datasetService = new DatasetService(); datasetService.setService(service); datasetService.setDataset(newDataset); + datasetService.setData(item.getData()); return datasetService; }).collect(Collectors.toSet())); } From 64e326396a51db1e31b8a2a094865b80f2d51a21 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Mon, 20 Jan 2020 11:42:11 +0200 Subject: [PATCH 088/106] Add AuthGuard on the quick-wizard module (ref #227) --- dmp-frontend/src/app/ui/quick-wizard/quick-wizard.routing.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.routing.ts b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.routing.ts index 31456ea00..22f849a67 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.routing.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.routing.ts @@ -2,11 +2,13 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { QuickWizardEditorComponent } from './quick-wizard-editor/quick-wizard-editor.component'; import { CanDeactivateGuard } from '../../library/deactivate/can-deactivate.guard'; +import { AuthGuard } from '@app/core/auth-guard.service'; const routes: Routes = [ { path: '', component: QuickWizardEditorComponent, + canActivate: [AuthGuard], data: { breadcrumb: true }, From 0cc89fd260177e458f1c778787e6a3ee94765812 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Mon, 20 Jan 2020 12:00:46 +0200 Subject: [PATCH 089/106] Added AuthGuard on Dataset create wizard and user profile in order to be prevented from access by users who haven't logged in (ref #227) --- .../ui/dataset-create-wizard/dataset-create-wizard.routing.ts | 3 +++ dmp-frontend/src/app/ui/user-profile/user-profile.routing.ts | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.routing.ts b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.routing.ts index 0eb34454b..97f9a4fb8 100644 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.routing.ts +++ b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.routing.ts @@ -3,11 +3,13 @@ import { RouterModule, Routes } from '@angular/router'; import { DatasetCreateWizard } from './dataset-create-wizard.component'; import { DatasetDmpSelector } from './dmp-selector/dataset-dmp-selector.component'; import { CanDeactivateGuard } from '../../library/deactivate/can-deactivate.guard'; +import { AuthGuard } from '@app/core/auth-guard.service'; const routes: Routes = [ { path: '', component: DatasetCreateWizard, + canActivate: [AuthGuard], data: { breadcrumb: true }, @@ -16,6 +18,7 @@ const routes: Routes = [ { path: '', component: DatasetDmpSelector, + canActivate: [AuthGuard], data: { breadcrumb: true }, diff --git a/dmp-frontend/src/app/ui/user-profile/user-profile.routing.ts b/dmp-frontend/src/app/ui/user-profile/user-profile.routing.ts index 0e55168e8..3e3118a8d 100644 --- a/dmp-frontend/src/app/ui/user-profile/user-profile.routing.ts +++ b/dmp-frontend/src/app/ui/user-profile/user-profile.routing.ts @@ -1,11 +1,13 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { UserProfileComponent } from './user-profile.component'; +import { AuthGuard } from '@app/core/auth-guard.service'; const routes: Routes = [ { path: '', component: UserProfileComponent, + canActivate: [AuthGuard], data: { breadcrumb: true }, @@ -16,4 +18,4 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) -export class UserProfileRoutingModule { } \ No newline at end of file +export class UserProfileRoutingModule { } From 95d713b213040149c31c296bd80ae8665199c44e Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Mon, 20 Jan 2020 18:09:03 +0200 Subject: [PATCH 090/106] Small fix for creating new versions of Dataset Templates --- .../dataset-profile/editor/dataset-profile-editor.component.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts index 3d102781d..e27f94cad 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts @@ -196,6 +196,8 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn this.router.navigate(['/dataset-profiles']); }); } else if (this.newVersionId) { + data.label = this.form.get('label').value; + data.description = this.form.get('description').value; this.datasetProfileService.newVersion(this.newVersionId, data) .pipe(takeUntil(this._destroyed)) .subscribe(() => { From cd1d81c3dd612b5f831822f94766890659d80bed Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Mon, 20 Jan 2020 18:11:35 +0200 Subject: [PATCH 091/106] Only Dataset Description Templates listing will show non-finalized templates (ref #227) --- .../eudat/data/dao/criteria/DatasetProfileCriteria.java | 8 ++++++++ .../eu/eudat/data/dao/entities/DatasetProfileDaoImpl.java | 6 +++++- .../query/dataset-profile/dataset-profile-criteria.ts | 1 + .../listing/dataset-profile-listing.component.ts | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DatasetProfileCriteria.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DatasetProfileCriteria.java index 0bf07564c..b8e2c35c4 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DatasetProfileCriteria.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/criteria/DatasetProfileCriteria.java @@ -32,6 +32,7 @@ public class DatasetProfileCriteria extends Criteria { private List groupIds; private Short filter; private UUID userId; + private boolean finalized; public boolean getAllVersions() { return allVersions; } public void setAllVersions(boolean allVersions) { this.allVersions = allVersions; } @@ -52,4 +53,11 @@ public class DatasetProfileCriteria extends Criteria { public void setUserId(UUID userId) { this.userId = userId; } + + public boolean getFinalized() { + return finalized; + } + public void setFinalized(boolean finalized) { + this.finalized = finalized; + } } diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetProfileDaoImpl.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetProfileDaoImpl.java index 42a7f8082..b06d5d8fd 100644 --- a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetProfileDaoImpl.java +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DatasetProfileDaoImpl.java @@ -52,7 +52,11 @@ public class DatasetProfileDaoImpl extends DatabaseAccess implem builder.notEqual(root.get("id"), criteria.getUserId()))); } } - query.where(((builder, root) -> builder.notEqual(root.get("status"), DatasetProfile.Status.DELETED.getValue()))); + if (criteria.getFinalized()) { + query.where(((builder, root) -> builder.equal(root.get("status"), DatasetProfile.Status.FINALIZED.getValue()))); + } else { + query.where(((builder, root) -> builder.notEqual(root.get("status"), DatasetProfile.Status.DELETED.getValue()))); + } return query; } diff --git a/dmp-frontend/src/app/core/query/dataset-profile/dataset-profile-criteria.ts b/dmp-frontend/src/app/core/query/dataset-profile/dataset-profile-criteria.ts index 313bfb5da..5d73e7c9c 100644 --- a/dmp-frontend/src/app/core/query/dataset-profile/dataset-profile-criteria.ts +++ b/dmp-frontend/src/app/core/query/dataset-profile/dataset-profile-criteria.ts @@ -4,4 +4,5 @@ export class DatasetProfileCriteria extends BaseCriteria { public id: String; public groupIds: string[]; public allVersions: boolean; + public finalized: boolean = true; } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.ts index 8582c490d..8f903dedd 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.ts @@ -148,6 +148,7 @@ export class DatasetDataSource extends DataSource { if (this._sort.active) { fields = this._sort.direction === 'asc' ? ['+' + this._sort.active] : ['-' + this._sort.active]; } const request = new DataTableRequest(startIndex, this._paginator.pageSize, { fields: fields }); request.criteria = this._criteria.criteria; + request.criteria.finalized = false; if (this.itemId) { request.criteria.groupIds = [this.itemId]; request.criteria.allVersions = true; From 4c02fc4c97dcc4095dae482be58b1d6b9fdbdddd Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Tue, 21 Jan 2020 12:40:15 +0200 Subject: [PATCH 092/106] Prevent to map associated Profiles to DMPs when they are loaded ONLY for autocomplete (ref #226) --- .../managers/DataManagementPlanManager.java | 25 +++++++++++++++---- .../DataManagementPlanListingModel.java | 8 ++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index a299608db..1fae98ee0 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -96,6 +96,7 @@ public class DataManagementPlanManager { } public DataTableData getPaged(DataManagementPlanTableRequest dataManagementPlanTableRequest, Principal principal, String fieldsGroup) throws Exception { + long startTime = System.currentTimeMillis(); UUID principalID = principal.getId(); QueryableList items = apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().getWithCriteria(dataManagementPlanTableRequest.getCriteria()); List roles = new LinkedList<>(); @@ -119,16 +120,30 @@ public class DataManagementPlanManager { .collect(Collectors.toSet())); return new DataManagementPlanListingModel().fromDataModelDatasets(item); }) - .whenComplete((resultList, throwable) -> dataTable.setData(resultList)); + .whenComplete((resultList, throwable) -> { + logger.info("Select query took " + (System.currentTimeMillis() - startTime) + " millis"); + dataTable.setData(resultList); + }); + } else if (fieldsGroup.equals("autocomplete")) { + itemsFuture = pagedItems + .selectAsync(item -> new DataManagementPlanListingModel().fromDataModelAutoComplete(item)) + .whenComplete((resultList, throwable) -> { + logger.info("Select query took " + (System.currentTimeMillis() - startTime) + " millis"); + dataTable.setData(resultList); + }); } else { itemsFuture = pagedItems .selectAsync(item -> new DataManagementPlanListingModel().fromDataModelAssociatedProfiles(item)) - .whenComplete((resultList, throwable) -> dataTable.setData(resultList)); + .whenComplete((resultList, throwable) -> { + logger.info("Select query took " + (System.currentTimeMillis() - startTime) + " millis"); + dataTable.setData(resultList); + }); } - CompletableFuture countFuture = authItems.countAsync().whenComplete((count, throwable) -> - dataTable.setTotalCount(count) - ); + CompletableFuture countFuture = authItems.countAsync().whenComplete((count, throwable) -> { + logger.info("Count query took " + (System.currentTimeMillis() - startTime) + " millis"); + dataTable.setTotalCount(count); + }); CompletableFuture.allOf(itemsFuture, countFuture).join(); return dataTable; } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DataManagementPlanListingModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DataManagementPlanListingModel.java index a942eb67d..1a2483314 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DataManagementPlanListingModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DataManagementPlanListingModel.java @@ -192,6 +192,14 @@ public class DataManagementPlanListingModel implements DataModel Date: Tue, 21 Jan 2020 12:48:19 +0200 Subject: [PATCH 093/106] Removed Unnecessary time counters --- .../managers/DataManagementPlanManager.java | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index 1fae98ee0..d4aef39e0 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -96,7 +96,6 @@ public class DataManagementPlanManager { } public DataTableData getPaged(DataManagementPlanTableRequest dataManagementPlanTableRequest, Principal principal, String fieldsGroup) throws Exception { - long startTime = System.currentTimeMillis(); UUID principalID = principal.getId(); QueryableList items = apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().getWithCriteria(dataManagementPlanTableRequest.getCriteria()); List roles = new LinkedList<>(); @@ -120,30 +119,18 @@ public class DataManagementPlanManager { .collect(Collectors.toSet())); return new DataManagementPlanListingModel().fromDataModelDatasets(item); }) - .whenComplete((resultList, throwable) -> { - logger.info("Select query took " + (System.currentTimeMillis() - startTime) + " millis"); - dataTable.setData(resultList); - }); + .whenComplete((resultList, throwable) -> dataTable.setData(resultList)); } else if (fieldsGroup.equals("autocomplete")) { itemsFuture = pagedItems .selectAsync(item -> new DataManagementPlanListingModel().fromDataModelAutoComplete(item)) - .whenComplete((resultList, throwable) -> { - logger.info("Select query took " + (System.currentTimeMillis() - startTime) + " millis"); - dataTable.setData(resultList); - }); + .whenComplete((resultList, throwable) -> dataTable.setData(resultList)); } else { itemsFuture = pagedItems .selectAsync(item -> new DataManagementPlanListingModel().fromDataModelAssociatedProfiles(item)) - .whenComplete((resultList, throwable) -> { - logger.info("Select query took " + (System.currentTimeMillis() - startTime) + " millis"); - dataTable.setData(resultList); - }); + .whenComplete((resultList, throwable) -> dataTable.setData(resultList)); } - CompletableFuture countFuture = authItems.countAsync().whenComplete((count, throwable) -> { - logger.info("Count query took " + (System.currentTimeMillis() - startTime) + " millis"); - dataTable.setTotalCount(count); - }); + CompletableFuture countFuture = authItems.countAsync().whenComplete((count, throwable) -> dataTable.setTotalCount(count)); CompletableFuture.allOf(itemsFuture, countFuture).join(); return dataTable; } From 63ac6df2ab8ff60973fdc2f5d0cb35bb24326ee1 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Thu, 23 Jan 2020 18:35:11 +0200 Subject: [PATCH 094/106] Vastly improved Internationalization support (ref #228) --- .../eudat/controllers/LanguageController.java | 45 + .../resources/application-devel.properties | 2 + dmp-frontend/src/app/app.component.ts | 5 +- dmp-frontend/src/app/app.module.ts | 5 +- .../src/app/core/core-service.module.ts | 4 +- .../services/language/language.service.ts | 22 + .../core/services/language/server.loader.ts | 15 + .../auth/admin-login/admin-login.component.ts | 12 +- .../ui/auth/login/utilities/login.service.ts | 12 +- .../src/app/ui/navbar/navbar.component.html | 25 + .../src/app/ui/navbar/navbar.component.ts | 16 +- .../ui/user-profile/user-profile.component.ts | 7 +- dmp-frontend/src/assets/i18n/es.json | 1214 +++++++++++++++++ dmp-frontend/src/assets/i18n/gr.json | 5 +- .../src/assets/resources/language.json | 4 + 15 files changed, 1377 insertions(+), 16 deletions(-) create mode 100644 dmp-backend/web/src/main/java/eu/eudat/controllers/LanguageController.java create mode 100644 dmp-frontend/src/app/core/services/language/language.service.ts create mode 100644 dmp-frontend/src/app/core/services/language/server.loader.ts create mode 100644 dmp-frontend/src/assets/i18n/es.json diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/LanguageController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/LanguageController.java new file mode 100644 index 000000000..0abc43925 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/LanguageController.java @@ -0,0 +1,45 @@ +package eu.eudat.controllers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.io.InputStream; + +@RestController +@CrossOrigin +@RequestMapping(value = {"/api/language/"}) +public class LanguageController { + + Environment environment; + + @Autowired + public LanguageController(Environment environment) { + this.environment = environment; + } + + @RequestMapping(value = "{lang}", method = RequestMethod.GET) + public ResponseEntity getLanguage(@PathVariable String lang) throws IOException { + + String fileName = this.environment.getProperty("language.path") + lang + ".json"; + InputStream is = getClass().getClassLoader().getResource(fileName).openStream(); + + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.setContentLength(is.available()); + responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); + responseHeaders.set("Content-Disposition", "attachment;filename=" + fileName); + responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); + responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); + + byte[] content = new byte[is.available()]; + is.read(content); + is.close(); + + return new ResponseEntity<>(content, responseHeaders, HttpStatus.OK); + } +} diff --git a/dmp-backend/web/src/main/resources/application-devel.properties b/dmp-backend/web/src/main/resources/application-devel.properties index e1c0f7883..581a79c7e 100644 --- a/dmp-backend/web/src/main/resources/application-devel.properties +++ b/dmp-backend/web/src/main/resources/application-devel.properties @@ -67,3 +67,5 @@ zenodo.access_token= #############CONTACT EMAIL CONFIGURATIONS######### contact_email.mail= + +language.path=/tempLang/i18n/ \ No newline at end of file diff --git a/dmp-frontend/src/app/app.component.ts b/dmp-frontend/src/app/app.component.ts index 013a2c0f5..3dceca965 100644 --- a/dmp-frontend/src/app/app.component.ts +++ b/dmp-frontend/src/app/app.component.ts @@ -12,6 +12,7 @@ import { BreadCrumbResolverService } from './ui/misc/breadcrumb/service/breadcru import { Title } from '@angular/platform-browser'; import { NgcCookieConsentService, NgcStatusChangeEvent } from "ngx-cookieconsent"; import { CookieService } from "ngx-cookie-service"; +import { LanguageService } from './core/services/language/language.service'; declare const gapi: any; @@ -38,7 +39,8 @@ export class AppComponent implements OnInit { private titleService: Title, private cultureService: CultureService, private cookieService: CookieService, - private ccService: NgcCookieConsentService + private ccService: NgcCookieConsentService, + private language: LanguageService ) { this.initializeServices(); } @@ -145,6 +147,7 @@ export class AppComponent implements OnInit { initializeServices() { this.translate.setDefaultLang('en'); this.authentication.current() && this.authentication.current().culture ? this.cultureService.cultureSelected(this.authentication.current().culture) : this.cultureService.cultureSelected(environment.defaultCulture); + this.authentication.current() && this.authentication.current().language ? this.language.changeLanguage(this.authentication.current().language) : this.language.changeLanguage('en'); } } diff --git a/dmp-frontend/src/app/app.module.ts b/dmp-frontend/src/app/app.module.ts index 5f0014ec1..a480eeb31 100644 --- a/dmp-frontend/src/app/app.module.ts +++ b/dmp-frontend/src/app/app.module.ts @@ -27,10 +27,13 @@ import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { environment } from 'environments/environment'; import { CookieService } from 'ngx-cookie-service'; import { NgcCookieConsentConfig, NgcCookieConsentModule } from 'ngx-cookieconsent'; +import { TranslateServerLoader } from './core/services/language/server.loader'; +import { BaseHttpService } from './core/services/http/base-http.service'; // AoT requires an exported function for factories export function HttpLoaderFactory(http: HttpClient) { - return new TranslateHttpLoader(http, 'assets/i18n/', '.json'); + return new TranslateServerLoader(http); + //return new TranslateHttpLoader(http, 'assets/i18n/', '.json'); } const cookieConfig: NgcCookieConsentConfig = { diff --git a/dmp-frontend/src/app/core/core-service.module.ts b/dmp-frontend/src/app/core/core-service.module.ts index 285f3c347..2c397567f 100644 --- a/dmp-frontend/src/app/core/core-service.module.ts +++ b/dmp-frontend/src/app/core/core-service.module.ts @@ -35,6 +35,7 @@ import { OrganisationService } from './services/organisation/organisation.servic import { EmailConfirmationService } from './services/email-confirmation/email-confirmation.service'; import { FunderService } from './services/funder/funder.service'; import { ContactSupportService } from './services/contact-support/contact-support.service'; +import { LanguageService } from './services/language/language.service'; // // // This is shared module that provides all the services. Its imported only once on the AppModule. @@ -89,7 +90,8 @@ export class CoreServiceModule { QuickWizardService, OrganisationService, EmailConfirmationService, - ContactSupportService + ContactSupportService, + LanguageService ], }; } diff --git a/dmp-frontend/src/app/core/services/language/language.service.ts b/dmp-frontend/src/app/core/services/language/language.service.ts new file mode 100644 index 000000000..3b1054f4d --- /dev/null +++ b/dmp-frontend/src/app/core/services/language/language.service.ts @@ -0,0 +1,22 @@ +import { Injectable } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { isNullOrUndefined } from 'util'; + +@Injectable() +export class LanguageService { + private currentLanguage: string = 'en'; + + constructor( + private translate: TranslateService + ) {} + + public changeLanguage(lang: string) { + this.currentLanguage = lang; + this.translate.use(lang); + } + + public getCurrentLanguage() { + return this.currentLanguage; + } + +} diff --git a/dmp-frontend/src/app/core/services/language/server.loader.ts b/dmp-frontend/src/app/core/services/language/server.loader.ts new file mode 100644 index 000000000..a9030e633 --- /dev/null +++ b/dmp-frontend/src/app/core/services/language/server.loader.ts @@ -0,0 +1,15 @@ +import { TranslateLoader } from '@ngx-translate/core'; +import { Observable } from 'rxjs'; +import { environment } from 'environments/environment'; +import { HttpClient } from '@angular/common/http'; + +export class TranslateServerLoader implements TranslateLoader{ + private languageUrl = `${environment.Server}language`; + + constructor( + private http: HttpClient + ) {} + getTranslation(lang: string): Observable { + return this.http.get(`${this.languageUrl}/${lang}`); + } +} diff --git a/dmp-frontend/src/app/ui/auth/admin-login/admin-login.component.ts b/dmp-frontend/src/app/ui/auth/admin-login/admin-login.component.ts index 589b8a41c..3619d9897 100644 --- a/dmp-frontend/src/app/ui/auth/admin-login/admin-login.component.ts +++ b/dmp-frontend/src/app/ui/auth/admin-login/admin-login.component.ts @@ -7,6 +7,8 @@ import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/serv import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; +import { TranslateServerLoader } from '@app/core/services/language/server.loader'; +import { LanguageService } from '@app/core/services/language/language.service'; @Component({ selector: 'app-admin-login', templateUrl: './admin-login.component.html', @@ -24,9 +26,10 @@ export class AdminLoginComponent extends BaseComponent implements OnInit { constructor( private authService: AuthService, private uiNotificationService: UiNotificationService, - private language: TranslateService, + private translate: TranslateService, private cultureService: CultureService, - private router: Router + private router: Router, + private language: LanguageService ) { super(); } @@ -48,12 +51,13 @@ export class AdminLoginComponent extends BaseComponent implements OnInit { } public onLogInSuccess(loginResponse: any) { - this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-LOGIN'), SnackBarNotificationLevel.Success); + this.uiNotificationService.snackBarNotification(this.translate.instant('GENERAL.SNACK-BAR.SUCCESSFUL-LOGIN'), SnackBarNotificationLevel.Success); if (this.authService.current().culture) { this.cultureService.cultureSelected(this.authService.current().culture); } + if (this.authService.current().language) { this.language.changeLanguage(this.authService.current().language); } this.router.navigate(['/']); } public onLogInError(errorMessage: string) { - this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-LOGIN'), SnackBarNotificationLevel.Error); + this.uiNotificationService.snackBarNotification(this.translate.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-LOGIN'), SnackBarNotificationLevel.Error); } } diff --git a/dmp-frontend/src/app/ui/auth/login/utilities/login.service.ts b/dmp-frontend/src/app/ui/auth/login/utilities/login.service.ts index 121f54bb1..9e66b278e 100644 --- a/dmp-frontend/src/app/ui/auth/login/utilities/login.service.ts +++ b/dmp-frontend/src/app/ui/auth/login/utilities/login.service.ts @@ -5,6 +5,8 @@ import { CultureService } from '@app/core/services/culture/culture-service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { BaseService } from '@common/base/base.service'; import { TranslateService } from '@ngx-translate/core'; +import { TranslateServerLoader } from '@app/core/services/language/server.loader'; +import { LanguageService } from '@app/core/services/language/language.service'; @Injectable() export class LoginService extends BaseService { @@ -12,10 +14,11 @@ export class LoginService extends BaseService { constructor( private router: Router, private authService: AuthService, - private language: TranslateService, + private translate: TranslateService, private zone: NgZone, private cultureService: CultureService, - private uiNotificationService: UiNotificationService + private uiNotificationService: UiNotificationService, + private language: LanguageService ) { super(); } @@ -44,14 +47,15 @@ export class LoginService extends BaseService { public onLogInSuccess(loginResponse: any, returnUrl: string) { this.zone.run(() => { - this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-LOGIN'), SnackBarNotificationLevel.Success); + this.uiNotificationService.snackBarNotification(this.translate.instant('GENERAL.SNACK-BAR.SUCCESSFUL-LOGIN'), SnackBarNotificationLevel.Success); if (this.authService.current().culture) { this.cultureService.cultureSelected(this.authService.current().culture); } + if (this.authService.current().language) { this.language.changeLanguage(this.authService.current().language); } const redirectUrl = returnUrl || '/'; this.router.navigate([redirectUrl]); }); } public onLogInError(errorMessage: string) { - this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-LOGIN'), SnackBarNotificationLevel.Error); + this.uiNotificationService.snackBarNotification(this.translate.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-LOGIN'), SnackBarNotificationLevel.Error); } } diff --git a/dmp-frontend/src/app/ui/navbar/navbar.component.html b/dmp-frontend/src/app/ui/navbar/navbar.component.html index 023476217..e4c998706 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.component.html +++ b/dmp-frontend/src/app/ui/navbar/navbar.component.html @@ -22,6 +22,31 @@
--> + + +
+ + + + +
+
diff --git a/dmp-frontend/src/app/ui/user-profile/user-profile.component.html b/dmp-frontend/src/app/ui/user-profile/user-profile.component.html index 057c922a6..71e4d086e 100644 --- a/dmp-frontend/src/app/ui/user-profile/user-profile.component.html +++ b/dmp-frontend/src/app/ui/user-profile/user-profile.component.html @@ -91,7 +91,7 @@ - {{ language.label }} + {{ language.label | translate }} diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 5ff1929e7..a9c709c60 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -126,6 +126,11 @@ "XML": "XML", "JSON": "JSON", "DOC": "Document" + }, + "LANGUAGES": { + "ENGLISH": "English", + "GREEK": "Greek", + "SPANISH": "Spanish" } }, "COOKIE": { diff --git a/dmp-frontend/src/assets/i18n/es.json b/dmp-frontend/src/assets/i18n/es.json index 769819426..f8df10b16 100644 --- a/dmp-frontend/src/assets/i18n/es.json +++ b/dmp-frontend/src/assets/i18n/es.json @@ -126,6 +126,11 @@ "XML": "XML", "JSON": "JSON", "DOC": "Document" + }, + "LANGUAGES": { + "ENGLISH": "Inglés", + "GREEK": "Griego", + "SPANISH": "Espanol" } }, "COOKIE": { diff --git a/dmp-frontend/src/assets/i18n/gr.json b/dmp-frontend/src/assets/i18n/gr.json index eb902d685..8004fbc3d 100644 --- a/dmp-frontend/src/assets/i18n/gr.json +++ b/dmp-frontend/src/assets/i18n/gr.json @@ -5,6 +5,11 @@ }, "ACTIONS": { "LOG-IN": "Είσοδος" + }, + "LANGUAGES": { + "ENGLISH": "Αγγλικά", + "GREEK": "Ελληνικά", + "SPANISH": "Ισπανικά" } }, "USER-PROFILE": { diff --git a/dmp-frontend/src/assets/resources/language.json b/dmp-frontend/src/assets/resources/language.json index f174bcbb0..e337c2308 100644 --- a/dmp-frontend/src/assets/resources/language.json +++ b/dmp-frontend/src/assets/resources/language.json @@ -1,14 +1,14 @@ [ { - "label": "English", + "label": "GENERAL.LANGUAGES.ENGLISH", "value": "en" }, { - "label": "Greek", + "label": "GENERAL.LANGUAGES.GREEK", "value": "gr" }, { - "label": "Spanish", + "label": "GENERAL.LANGUAGES.SPANISH", "value": "es" } ] From cb9509ee4f07a1ecf08a5ceec757fe718843a764 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Mon, 27 Jan 2020 18:38:24 +0200 Subject: [PATCH 096/106] Added a functional Language Editor --- .../eudat/controllers/LanguageController.java | 18 +++++++++-- dmp-frontend/src/app/app-routing.module.ts | 8 +++++ .../services/language/language.service.ts | 31 +++++++++++++++++-- .../src/app/ui/navbar/navbar.component.html | 2 +- .../src/app/ui/navbar/navbar.component.ts | 7 +++++ .../src/app/ui/sidebar/sidebar.component.ts | 3 +- 6 files changed, 62 insertions(+), 7 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/LanguageController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/LanguageController.java index 11e46900c..440922b11 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/LanguageController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/LanguageController.java @@ -1,5 +1,8 @@ package eu.eudat.controllers; +import eu.eudat.models.data.helpers.responses.ResponseItem; +import eu.eudat.models.data.security.Principal; +import eu.eudat.types.ApiMessageCode; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.http.HttpHeaders; @@ -8,9 +11,8 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; +import java.util.UUID; @RestController @CrossOrigin @@ -43,4 +45,14 @@ public class LanguageController { return new ResponseEntity<>(content, responseHeaders, HttpStatus.OK); } + + @RequestMapping(value = "update/{lang}", method = RequestMethod.POST) + public @ResponseBody + ResponseEntity> updateLang(@PathVariable String lang, @RequestBody String json) throws Exception { + String fileName = this.environment.getProperty("language.path") + lang + ".json"; + OutputStream os = new FileOutputStream(fileName); + os.write(json.getBytes()); + os.close(); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE).message("Updated").payload("Updated")); + } } diff --git a/dmp-frontend/src/app/app-routing.module.ts b/dmp-frontend/src/app/app-routing.module.ts index 9b56a04b2..5a03dbf02 100644 --- a/dmp-frontend/src/app/app-routing.module.ts +++ b/dmp-frontend/src/app/app-routing.module.ts @@ -164,6 +164,14 @@ const appRoutes: Routes = [ title: 'GENERAL.TITLES.PROFILE' }, }, + { + path: 'language-editor', + loadChildren: () => import('./ui/language-editor/language-editor.module').then(m => m.LanguageEditorModule), + data: { + breadcrumb: true, + title: 'Language Editor' + }, + }, { path: 'login/admin', loadChildren: () => import('./ui/auth/admin-login/admin-login.module').then(m => m.AdminLoginModule), diff --git a/dmp-frontend/src/app/core/services/language/language.service.ts b/dmp-frontend/src/app/core/services/language/language.service.ts index 3b1054f4d..4999d6f8a 100644 --- a/dmp-frontend/src/app/core/services/language/language.service.ts +++ b/dmp-frontend/src/app/core/services/language/language.service.ts @@ -1,13 +1,22 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { isNullOrUndefined } from 'util'; +import { environment } from 'environments/environment'; +import { Observable } from 'rxjs'; +import { HttpResponse, HttpClient } from '@angular/common/http'; +import { BaseHttpService } from '../http/base-http.service'; +import { Language } from '@app/models/language/Language'; + +const availableLanguages: any[] = require('../../../../assets/resources/language.json'); @Injectable() export class LanguageService { private currentLanguage: string = 'en'; + private languageUrl = `${environment.Server}language`; constructor( - private translate: TranslateService + private translate: TranslateService, + private http: HttpClient, + private baseHttp: BaseHttpService ) {} public changeLanguage(lang: string) { @@ -19,4 +28,22 @@ export class LanguageService { return this.currentLanguage; } + public getCurrentLanguageJSON(): Observable> { + return this.http.get(`${this.languageUrl}/${this.currentLanguage}`, { responseType: 'blob', observe: 'response' }); + } + + public updateLanguage(json: string): Observable { + return this.baseHttp.post(`${this.languageUrl}/update/${this.currentLanguage}`, json); + } + + public getCurrentLanguageName() { + let result: string = ''; + availableLanguages.forEach(language => { + if (language.value === this.currentLanguage) { + result = this.translate.instant(language.label); + } + }); + return result; + } + } diff --git a/dmp-frontend/src/app/ui/navbar/navbar.component.html b/dmp-frontend/src/app/ui/navbar/navbar.component.html index 76412ed28..7d8bcc749 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.component.html +++ b/dmp-frontend/src/app/ui/navbar/navbar.component.html @@ -36,7 +36,7 @@
--> -
+
diff --git a/dmp-frontend/src/app/ui/navbar/navbar.component.ts b/dmp-frontend/src/app/ui/navbar/navbar.component.ts index 23849a7ce..862d7fe69 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.component.ts +++ b/dmp-frontend/src/app/ui/navbar/navbar.component.ts @@ -29,6 +29,7 @@ export class NavbarComponent extends BaseComponent implements OnInit { private sidebarVisible: boolean; languages = availableLanguages; language = this.languages[0]; + currentRoute: string; constructor(location: Location, @@ -45,6 +46,7 @@ export class NavbarComponent extends BaseComponent implements OnInit { } ngOnInit() { + this.currentRoute = this.router.url; this.listTitles = GENERAL_ROUTES.filter(listTitle => listTitle); this.listTitles.push(DMP_ROUTES.filter(listTitle => listTitle)); // this.listTitles.push(HISTORY_ROUTES.filter(listTitle => listTitle)); @@ -54,6 +56,7 @@ export class NavbarComponent extends BaseComponent implements OnInit { this.router.events.subscribe((event) => { this.sidebarClose(); var $layer: any = document.getElementsByClassName('close-layer')[0]; + this.currentRoute = this.router.url; if ($layer) { $layer.remove(); this.mobile_menu_visible = 0; @@ -69,6 +72,10 @@ export class NavbarComponent extends BaseComponent implements OnInit { return !(!this.authentication.current()); } + public onLanguageEditor(): boolean { + return this.currentRoute === '/language-editor'; + } + sidebarOpen() { const toggleButton = this.toggleButton; const body = document.getElementsByTagName('body')[0]; diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts b/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts index f456542fe..1ddc24a89 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts +++ b/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts @@ -50,7 +50,8 @@ export const PUBLIC_ROUTES: RouteInfo[] = [ export const ADMIN_ROUTES: RouteInfo[] = [ { path: '/dmp-profiles', title: 'SIDE-BAR.DMP-TEMPLATES', icon: 'library_books' }, { path: '/dataset-profiles', title: 'SIDE-BAR.DATASET-TEMPLATES', icon: 'library_books' }, - { path: '/users', title: 'SIDE-BAR.USERS', icon: 'people' } + { path: '/users', title: 'SIDE-BAR.USERS', icon: 'people' }, + { path: '/language-editor', title: 'Language Editor', icon: 'language'} ]; // export const HISTORY_ROUTES: RouteInfo[] = [ // { path: '/typography', title: 'SIDE-BAR.HISTORY-VISITED', icon: 'visibility'}, From c3b16b1fa8865c933df4e1326eb584f38878690e Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Tue, 28 Jan 2020 10:13:26 +0200 Subject: [PATCH 097/106] Add language editor component --- .../language-editor.component.html | 26 ++++++ .../language-editor.component.scss | 17 ++++ .../language-editor.component.ts | 91 +++++++++++++++++++ .../language-editor/language-editor.module.ts | 19 ++++ .../language-editor.routing.ts | 14 +++ 5 files changed, 167 insertions(+) create mode 100644 dmp-frontend/src/app/ui/language-editor/language-editor.component.html create mode 100644 dmp-frontend/src/app/ui/language-editor/language-editor.component.scss create mode 100644 dmp-frontend/src/app/ui/language-editor/language-editor.component.ts create mode 100644 dmp-frontend/src/app/ui/language-editor/language-editor.module.ts create mode 100644 dmp-frontend/src/app/ui/language-editor/language-editor.routing.ts diff --git a/dmp-frontend/src/app/ui/language-editor/language-editor.component.html b/dmp-frontend/src/app/ui/language-editor/language-editor.component.html new file mode 100644 index 000000000..b9eaa1621 --- /dev/null +++ b/dmp-frontend/src/app/ui/language-editor/language-editor.component.html @@ -0,0 +1,26 @@ +
+
+
+ +
+ +
+ + {{key}} : + + +
+
+
+ +
+ +
+
diff --git a/dmp-frontend/src/app/ui/language-editor/language-editor.component.scss b/dmp-frontend/src/app/ui/language-editor/language-editor.component.scss new file mode 100644 index 000000000..39e04d644 --- /dev/null +++ b/dmp-frontend/src/app/ui/language-editor/language-editor.component.scss @@ -0,0 +1,17 @@ +.language-editor { + padding-top: 5em; + padding-bottom: 2em; + + .language-area { + box-sizing: content-box; + } + + .save-btn { + padding-top: inherit !important; + top: auto !important; + width: 56px !important; + bottom: 10px; + position: fixed; + right: 10px; + } +} diff --git a/dmp-frontend/src/app/ui/language-editor/language-editor.component.ts b/dmp-frontend/src/app/ui/language-editor/language-editor.component.ts new file mode 100644 index 000000000..68050e652 --- /dev/null +++ b/dmp-frontend/src/app/ui/language-editor/language-editor.component.ts @@ -0,0 +1,91 @@ +import { Component, OnInit } from '@angular/core'; +import { LanguageService } from '@app/core/services/language/language.service'; +import { BaseComponent } from '@common/base/base.component'; +import { takeUntil } from 'rxjs/operators'; +import { FormGroup, FormBuilder } from '@angular/forms'; +import { TranslateService } from '@ngx-translate/core'; +import { UiNotificationService, SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'app-language-editor', + templateUrl: './language-editor.component.html', + styleUrls: ['./language-editor.component.scss'] +}) +export class LanguageEditorComponent extends BaseComponent implements OnInit { + keys = []; + parseFinished = false; + currentLang: string; + formGroup: FormGroup; + formBuilder: FormBuilder; + + constructor( + private language: LanguageService, + private uiNotificationService: UiNotificationService, + private translate: TranslateService, + private router: Router, + ) { super(); } + + ngOnInit() { + this.formBuilder = new FormBuilder(); + this.formGroup = this.formBuilder.group({}); + this.language.getCurrentLanguageJSON() + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/json' }); + this.convertBlobToJSON(blob); + + }); + } + + convertBlobToJSON(blob: Blob) { + const fr = new FileReader(); + fr.onload = ev => { + const langObj = JSON.parse(fr.result as string); + this.convertObjectToForm(langObj, '', this.formGroup); + this.currentLang = this.language.getCurrentLanguageName(); + this.parseFinished = true; + }; + fr.readAsText(blob); + } + + convertObjectToForm(obj: any, parentKey: string, form: FormGroup) { + for (let prop in obj) { + const key = parentKey !== '' ? `${parentKey}.${prop}` : prop; + if (typeof obj[prop] === 'object') { + form.addControl(prop, this.formBuilder.group({})); + this.convertObjectToForm(obj[prop], key, form.get(prop) as FormGroup); + continue; + } else { + form.addControl(prop, this.formBuilder.control(obj[prop])); + this.keys.push(key); + } + } + return; + } + + updateLang() { + const json = JSON.stringify(this.formGroup.value); + this.language.updateLanguage(json).pipe(takeUntil(this._destroyed)) + .subscribe( + complete => { + this.onCallbackSuccess(complete); + }, + error => { + this.onCallbackError(error); + } + ); + + } + + onCallbackSuccess(id?: String): void { + this.uiNotificationService.snackBarNotification( this.translate.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); + this.router.navigate(['/reload']).then(() => this.router.navigate(['/language-editor'])); +} + +onCallbackError(error: any) { + this.uiNotificationService.snackBarNotification( error, SnackBarNotificationLevel.Error); + //this.validateAllFormFields(this.formGroup); +} + +} diff --git a/dmp-frontend/src/app/ui/language-editor/language-editor.module.ts b/dmp-frontend/src/app/ui/language-editor/language-editor.module.ts new file mode 100644 index 000000000..ff38b4929 --- /dev/null +++ b/dmp-frontend/src/app/ui/language-editor/language-editor.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { LanguageEditorComponent } from './language-editor.component'; +import { LanguageEditorRoutingModule } from './language-editor.routing'; +import { CommonUiModule } from '@common/ui/common-ui.module'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; + + + +@NgModule({ + declarations: [LanguageEditorComponent], + imports: [ + CommonUiModule, + CommonFormsModule, + ConfirmationDialogModule, + LanguageEditorRoutingModule + ] +}) +export class LanguageEditorModule { } diff --git a/dmp-frontend/src/app/ui/language-editor/language-editor.routing.ts b/dmp-frontend/src/app/ui/language-editor/language-editor.routing.ts new file mode 100644 index 000000000..423d8dd32 --- /dev/null +++ b/dmp-frontend/src/app/ui/language-editor/language-editor.routing.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { LanguageEditorComponent } from './language-editor.component'; + +const routes: Routes = [ + { path: '', component: LanguageEditorComponent }, + // { path: ':id', component: UserProfileComponent } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class LanguageEditorRoutingModule { } From 0bebdae163f79e63eae30d2286ef30f80d66cdf7 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Tue, 28 Jan 2020 18:28:01 +0200 Subject: [PATCH 098/106] Fixed environment.ts double declaration of the linkedin redirect Url --- dmp-frontend/src/environments/environment.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/dmp-frontend/src/environments/environment.ts b/dmp-frontend/src/environments/environment.ts index 193d09ace..7fb7fa113 100644 --- a/dmp-frontend/src/environments/environment.ts +++ b/dmp-frontend/src/environments/environment.ts @@ -14,7 +14,6 @@ export const environment = { linkedInConfiguration: { clientId: '', oauthUrl: 'https://www.linkedin.com/oauth/v2/authorization', - redirectUri: 'http://localhost:4200/login/linkedin' redirectUri: 'http://localhost:4200/login/linkedin', state: '987654321' }, From 781be460312cb63573811f279d9ee9bf8fa45366 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Tue, 28 Jan 2020 18:31:21 +0200 Subject: [PATCH 099/106] Nav Bar Language selector can properly be stored to the user's settings and is hidden on the User's profile page (ref #228) --- .../logger/remote/http/HttpRemoteLogger.java | 4 +-- .../src/app/ui/navbar/navbar.component.html | 2 +- .../src/app/ui/navbar/navbar.component.ts | 31 ++++++++++++++----- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/dmp-backend/logging/src/main/java/eu/eudat/core/logger/remote/http/HttpRemoteLogger.java b/dmp-backend/logging/src/main/java/eu/eudat/core/logger/remote/http/HttpRemoteLogger.java index 774fdff9a..d3f8e088e 100644 --- a/dmp-backend/logging/src/main/java/eu/eudat/core/logger/remote/http/HttpRemoteLogger.java +++ b/dmp-backend/logging/src/main/java/eu/eudat/core/logger/remote/http/HttpRemoteLogger.java @@ -28,14 +28,14 @@ import java.util.Map; * Created by ikalyvas on 5/30/2018. */ -@Service("logger") +//@Service("logger") public class HttpRemoteLogger extends AbstractBatchLogger implements Logger { private RestTemplate rest; private HttpHeaders headers; private Environment environment; - @Autowired + //@Autowired public HttpRemoteLogger(Environment environment) { super(environment); this.rest = new RestTemplate(); diff --git a/dmp-frontend/src/app/ui/navbar/navbar.component.html b/dmp-frontend/src/app/ui/navbar/navbar.component.html index 7d8bcc749..aaff6823d 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.component.html +++ b/dmp-frontend/src/app/ui/navbar/navbar.component.html @@ -36,7 +36,7 @@
--> -
+
diff --git a/dmp-frontend/src/app/ui/navbar/navbar.component.ts b/dmp-frontend/src/app/ui/navbar/navbar.component.ts index 862d7fe69..261aa8ecd 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.component.ts +++ b/dmp-frontend/src/app/ui/navbar/navbar.component.ts @@ -9,9 +9,8 @@ import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; import { UserDialogComponent } from '../misc/navigation/user-dialog/user-dialog.component'; import { DATASETS_ROUTES, DMP_ROUTES, GENERAL_ROUTES } from '../sidebar/sidebar.component'; -import { TranslateService } from '@ngx-translate/core'; -import { Language } from '@app/models/language/Language'; import { LanguageService } from '@app/core/services/language/language.service'; +import { UserService } from '@app/core/services/user/user.service'; const availableLanguages: any[] = require('../../../assets/resources/language.json'); @@ -38,7 +37,8 @@ export class NavbarComponent extends BaseComponent implements OnInit { private authentication: AuthService, private dialog: MatDialog, private progressIndicationService: ProgressIndicationService, - private languageService: LanguageService + private languageService: LanguageService, + private userService: UserService ) { super(); this.location = location; @@ -72,8 +72,8 @@ export class NavbarComponent extends BaseComponent implements OnInit { return !(!this.authentication.current()); } - public onLanguageEditor(): boolean { - return this.currentRoute === '/language-editor'; + public onInvalidUrl(): boolean { + return this.currentRoute === '/language-editor' || this.currentRoute === '/profile'; } sidebarOpen() { @@ -200,7 +200,24 @@ export class NavbarComponent extends BaseComponent implements OnInit { } onLanguageSelected(selectedLanguage: any) { - this.languageService.changeLanguage(selectedLanguage.value); - this.router.navigate([this.router.url]); + if (this.isAuthenticated()) { + const langMap = new Map(); + langMap.set('language', selectedLanguage.value); + this.userService.updateUserSettings({language: selectedLanguage}) + .pipe(takeUntil(this._destroyed)) + .subscribe((response) => { + this.languageService.changeLanguage(selectedLanguage.value); + this.authentication.me() + .pipe(takeUntil(this._destroyed)) + .subscribe ( innerResponse => + {this.router.navigate([this.router.url]);}); + }, + error => { + console.log(error); + }); + } else { + this.languageService.changeLanguage(selectedLanguage.value); + this.router.navigate([this.router.url]); + } } } From 69fde5f35315d0253d3e05a04d5576d626fbd508 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Tue, 28 Jan 2020 18:33:50 +0200 Subject: [PATCH 100/106] Even more Replacements of the HttpRemoteLogger with the sl4j Logger (ref #223) --- .../configurations/WebMVCConfiguration.java | 2 +- .../main/java/eu/eudat/controllers/Admin.java | 2 +- .../eu/eudat/controllers/BaseController.java | 6 +++--- .../main/java/eu/eudat/controllers/Login.java | 19 +++++++++++-------- .../ControllerUnauthorisedHandler.java | 13 +++++++------ .../interceptors/RequestInterceptor.java | 12 +++++++----- .../services/helpers/HelpersService.java | 2 +- .../services/helpers/HelpersServiceImpl.java | 10 +++++----- .../services/helpers/LoggerServiceImpl.java | 4 ++-- 9 files changed, 38 insertions(+), 32 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/configurations/WebMVCConfiguration.java b/dmp-backend/web/src/main/java/eu/eudat/configurations/WebMVCConfiguration.java index d1136aba9..89a330cd2 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/configurations/WebMVCConfiguration.java +++ b/dmp-backend/web/src/main/java/eu/eudat/configurations/WebMVCConfiguration.java @@ -37,6 +37,6 @@ public class WebMVCConfiguration extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(new RequestInterceptor(this.apiContext.getHelpersService().getLoggerService())); +// registry.addInterceptor(new RequestInterceptor(this.apiContext.getHelpersService().getLoggerService())); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/Admin.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/Admin.java index 11760957b..c461906b6 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/Admin.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/Admin.java @@ -42,7 +42,7 @@ public class Admin extends BaseController { private ConfigLoader configLoader; @Autowired - public Admin(ApiContext apiContext, DatasetProfileManager datasetProfileManager, UserManager userManager, Logger logger, ConfigLoader configLoader) { + public Admin(ApiContext apiContext, DatasetProfileManager datasetProfileManager, UserManager userManager/*, Logger logger*/, ConfigLoader configLoader) { super(apiContext); this.datasetProfileManager = datasetProfileManager; this.userManager = userManager; diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/BaseController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/BaseController.java index 147f91f22..c9bddab50 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/BaseController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/BaseController.java @@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.InitBinder; public abstract class BaseController { - private Logger logger; + /*private Logger logger;*/ private ApiContext apiContext; @@ -17,9 +17,9 @@ public abstract class BaseController { return apiContext; } - public Logger getLoggerService() { + /*public Logger getLoggerService() { return logger; - } + }*/ public BaseController(ApiContext apiContext) { diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/Login.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/Login.java index 954ab00e2..78304aa20 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/Login.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/Login.java @@ -1,6 +1,6 @@ package eu.eudat.controllers; -import eu.eudat.core.logger.Logger; + import eu.eudat.exceptions.security.NullEmailException; import eu.eudat.logic.managers.UserManager; import eu.eudat.logic.proxy.config.configloaders.ConfigLoader; @@ -28,6 +28,8 @@ import eu.eudat.models.data.login.Credentials; import eu.eudat.models.data.login.LoginInfo; import eu.eudat.models.data.security.Principal; import eu.eudat.types.ApiMessageCode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -42,6 +44,7 @@ import java.security.GeneralSecurityException; @CrossOrigin @RequestMapping(value = "api/auth") public class Login { + private static final Logger logger = LoggerFactory.getLogger(Login.class); private CustomAuthenticationProvider customAuthenticationProvider; private AuthenticationService nonVerifiedUserAuthenticationService; @@ -53,13 +56,13 @@ public class Login { private ConfigurableProviderTokenValidator configurableProviderTokenValidator; private ConfigLoader configLoader; - private Logger logger; +// private Logger logger; private UserManager userManager; @Autowired public Login(CustomAuthenticationProvider customAuthenticationProvider, AuthenticationService nonVerifiedUserAuthenticationService, TwitterTokenValidator twitterTokenValidator, LinkedInTokenValidator linkedInTokenValidator, B2AccessTokenValidator b2AccessTokenValidator, - ORCIDTokenValidator orcidTokenValidator, OpenAIRETokenValidator openAIRETokenValidator, ConfigurableProviderTokenValidator configurableProviderTokenValidator, ConfigLoader configLoader, UserManager userManager, Logger logger) { + ORCIDTokenValidator orcidTokenValidator, OpenAIRETokenValidator openAIRETokenValidator, ConfigurableProviderTokenValidator configurableProviderTokenValidator, ConfigLoader configLoader, UserManager userManager/*, Logger logger*/) { this.customAuthenticationProvider = customAuthenticationProvider; this.nonVerifiedUserAuthenticationService = nonVerifiedUserAuthenticationService; this.twitterTokenValidator = twitterTokenValidator; @@ -69,7 +72,7 @@ public class Login { this.openAIRETokenValidator = openAIRETokenValidator; this.configurableProviderTokenValidator = configurableProviderTokenValidator; this.configLoader = configLoader; - this.logger = logger; +// this.logger = logger; this.userManager = userManager; } @@ -77,7 +80,7 @@ public class Login { @RequestMapping(method = RequestMethod.POST, value = {"/externallogin"}, consumes = "application/json", produces = "application/json") public @ResponseBody ResponseEntity> externallogin(@RequestBody LoginInfo credentials) throws GeneralSecurityException, NullEmailException { - this.logger.info(credentials, "Trying To Login With " + credentials.getProvider()); + logger.info("Trying To Login With " + credentials.getProvider()); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(customAuthenticationProvider.authenticate(credentials)).status(ApiMessageCode.SUCCESS_MESSAGE)); } @@ -85,7 +88,7 @@ public class Login { @RequestMapping(method = RequestMethod.POST, value = {"/nativelogin"}, consumes = "application/json", produces = "application/json") public @ResponseBody ResponseEntity> nativelogin(@RequestBody Credentials credentials) throws NullEmailException { - this.logger.info(credentials.getUsername(), "Trying To Login"); + logger.info(credentials.getUsername() + " Trying To Login"); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(userManager.authenticate(this.nonVerifiedUserAuthenticationService, credentials)).status(ApiMessageCode.SUCCESS_MESSAGE)); } @@ -128,7 +131,7 @@ public class Login { @RequestMapping(method = RequestMethod.POST, value = {"/me"}, consumes = "application/json", produces = "application/json") public @ResponseBody ResponseEntity> authMe(Principal principal) throws NullEmailException { - this.logger.info(principal, "Getting Me"); + logger.info(principal + " Getting Me"); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(this.nonVerifiedUserAuthenticationService.Touch(principal.getToken())).status(ApiMessageCode.NO_MESSAGE)); } @@ -137,7 +140,7 @@ public class Login { public @ResponseBody ResponseEntity> logout(Principal principal) { this.nonVerifiedUserAuthenticationService.Logout(principal.getToken()); - this.logger.info(principal, "Logged Out"); + logger.info(principal + " Logged Out"); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE)); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/controllerhandler/ControllerUnauthorisedHandler.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/controllerhandler/ControllerUnauthorisedHandler.java index 72e02ad89..0a8599265 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/controllerhandler/ControllerUnauthorisedHandler.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/controllerhandler/ControllerUnauthorisedHandler.java @@ -1,7 +1,8 @@ package eu.eudat.controllers.controllerhandler; -import eu.eudat.core.logger.Logger; import eu.eudat.exceptions.security.UnauthorisedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; @@ -18,19 +19,19 @@ import javax.annotation.Priority; @ControllerAdvice @Priority(4) public class ControllerUnauthorisedHandler { - - private Logger logger; + private static final Logger logger = LoggerFactory.getLogger(ControllerUnauthorisedHandler.class); +// private Logger logger; @Autowired - public ControllerUnauthorisedHandler(Logger logger) { - this.logger = logger; + public ControllerUnauthorisedHandler(/*Logger logger*/) { +// this.logger = logger; } @ExceptionHandler(UnauthorisedException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) @ResponseBody public void processValidationError(UnauthorisedException ex) { - this.logger.error(ex, ex.getMessage()); + logger.error(ex.getMessage(), ex); return; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/interceptors/RequestInterceptor.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/interceptors/RequestInterceptor.java index 7bf712829..24d0278e3 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/interceptors/RequestInterceptor.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/interceptors/RequestInterceptor.java @@ -2,6 +2,8 @@ package eu.eudat.controllers.interceptors; import eu.eudat.logic.services.helpers.LoggerService; import eu.eudat.types.WarningLevel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; @@ -15,19 +17,19 @@ import java.util.Date; */ @Component public class RequestInterceptor extends HandlerInterceptorAdapter { - - private LoggerService loggerService; + private static final Logger logger = LoggerFactory.getLogger(RequestInterceptor.class); +// private LoggerService loggerService; @Autowired - public RequestInterceptor(LoggerService loggerService) { - this.loggerService = loggerService; + public RequestInterceptor(/*LoggerService loggerService*/) { +// this.loggerService = loggerService; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String reqUri = request.getRequestURI(); - this.loggerService.log("Call to " + reqUri + " method: " + request.getMethod() + " at: " + new Date(), WarningLevel.INFO); + logger.info("Call to " + reqUri + " method: " + request.getMethod() + " at: " + new Date(), WarningLevel.INFO); return super.preHandle(request, response, handler); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/HelpersService.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/HelpersService.java index e8f2954b0..df4fdaa64 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/HelpersService.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/HelpersService.java @@ -9,5 +9,5 @@ public interface HelpersService { MessageSource getMessageSource(); - LoggerService getLoggerService(); +// LoggerService getLoggerService(); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/HelpersServiceImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/HelpersServiceImpl.java index e6f6806bc..c09003c23 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/HelpersServiceImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/HelpersServiceImpl.java @@ -11,12 +11,12 @@ import org.springframework.stereotype.Service; public class HelpersServiceImpl implements HelpersService { private MessageSource messageSource; - private LoggerService loggerService; +// private LoggerService loggerService; @Autowired - public HelpersServiceImpl(MessageSource messageSource, LoggerService loggerService) { + public HelpersServiceImpl(MessageSource messageSource/*, LoggerService loggerService*/) { this.messageSource = messageSource; - this.loggerService = loggerService; +// this.loggerService = loggerService; } @Override @@ -24,8 +24,8 @@ public class HelpersServiceImpl implements HelpersService { return messageSource; } - @Override + /*@Override public LoggerService getLoggerService() { return loggerService; - } + }*/ } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/LoggerServiceImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/LoggerServiceImpl.java index d0fff2fee..7e4533707 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/LoggerServiceImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/helpers/LoggerServiceImpl.java @@ -12,7 +12,7 @@ import java.util.Map; /** * Created by ikalyvas on 3/1/2018. */ -@Service("loggerService") +//@Service("loggerService") public class LoggerServiceImpl implements LoggerService { private Logger logger; private WarningLevel level; @@ -22,7 +22,7 @@ public class LoggerServiceImpl implements LoggerService { this.level = level; } - @Autowired +// @Autowired public LoggerServiceImpl(Logger logger) { this.logger = logger; this.options.put(WarningLevel.DEBUG, (log, message) -> log.debug(message)); From 894b358f9a8125bcf154492f54d662c2abcd5cc6 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Wed, 29 Jan 2020 12:38:16 +0200 Subject: [PATCH 101/106] When deleting the first fieldset all the values from the second fieldset will be moved to the first fieldset instead of just the first value (ref #156) --- .../components/form-section/form-section.component.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.ts index 17bcc6596..123801f1a 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.ts @@ -61,8 +61,11 @@ export class FormSectionComponent implements OnInit, OnChanges { } deleteCompositeFieldFormGroup(compositeFildIndex: number) { - const firstMultiplicityItem = this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems').get('' + 0).get('fields').get('' + 0).value; - this.form.get('compositeFields').get('' + compositeFildIndex).get('fields').get('' + 0).patchValue(firstMultiplicityItem); + const numberOfItems = this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems').get('' + 0).get('fields').value.length; + for (let i = 0; i < numberOfItems; i++) { + const multiplicityItem = this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems').get('' + 0).get('fields').get('' + i).value; + this.form.get('compositeFields').get('' + compositeFildIndex).get('fields').get('' + i).patchValue(multiplicityItem); + } ((this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems'))).removeAt(0); } From f72f734ed4e6eac6dc0ca8e56052cf96301eb03b Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Wed, 29 Jan 2020 13:24:06 +0200 Subject: [PATCH 102/106] Form's auto resizable text area will no longer show the scrollbar --- .../components/form-field/form-field.component.html | 2 +- .../components/form-field/form-field.component.scss | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.html b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.html index 6f5d30659..9db8790c0 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.html +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.html @@ -98,7 +98,7 @@
-
- -
+
{{dmp.label}}
diff --git a/dmp-frontend/src/app/ui/user-profile/user-profile.component.scss b/dmp-frontend/src/app/ui/user-profile/user-profile.component.scss index 70be43784..8c566320d 100644 --- a/dmp-frontend/src/app/ui/user-profile/user-profile.component.scss +++ b/dmp-frontend/src/app/ui/user-profile/user-profile.component.scss @@ -1,6 +1,6 @@ -// .clickable{ -// cursor: pointer; -// } +.clickable{ + cursor: pointer; +} // .two-line-mat-option { // height: 3.5em; // line-height: 1.2em; From 8b1d285ff4c87abf8295c345f1bde885a4309bc5 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Wed, 29 Jan 2020 18:28:46 +0200 Subject: [PATCH 104/106] Replace the DMP creator with the user roles on the User's profile (ref #224) --- .../src/app/ui/user-profile/user-profile.component.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dmp-frontend/src/app/ui/user-profile/user-profile.component.ts b/dmp-frontend/src/app/ui/user-profile/user-profile.component.ts index 00fd630a8..de33e2857 100644 --- a/dmp-frontend/src/app/ui/user-profile/user-profile.component.ts +++ b/dmp-frontend/src/app/ui/user-profile/user-profile.component.ts @@ -77,7 +77,13 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes } getUserRole(dmp: DmpModel) { - if (dmp.creator.id === this.currentUserId) { return this.language.instant('USER-PROFILE.DMPS.CREATOR'); } else if (dmp.associatedUsers.map(x => x.id).indexOf(this.currentUserId) !== -1) { return this.language.instant('USER-PROFILE.DMPS.MEMBER'); } + let role = -1; + dmp.users.forEach(user => { + if (user.id === this.currentUserId) { + role = user.role; + } + }); + if (role === 0) { return this.language.instant('USER-PROFILE.DMPS.CREATOR'); } else if (role === 1) { return this.language.instant('USER-PROFILE.DMPS.MEMBER'); } return ''; } From 6c73ed51318ac069cd9f616645820cef978dce98 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Thu, 30 Jan 2020 11:34:59 +0200 Subject: [PATCH 105/106] Fixed issue when trying to retrieve non-existing user during e-mail confirmation and when the e-mail is confirmed it will show proper message on the frontend (ref #233) --- .../java/eu/eudat/controllers/EmailConfirmation.java | 9 ++++++++- .../logic/managers/EmailConfirmationManager.java | 11 ++++++----- .../email-confirmation.component.ts | 5 +++++ dmp-frontend/src/assets/i18n/en.json | 3 ++- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/EmailConfirmation.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/EmailConfirmation.java index 7a6f11416..d1c9582aa 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/EmailConfirmation.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/EmailConfirmation.java @@ -36,7 +36,11 @@ public class EmailConfirmation { return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE)); } catch (HasConfirmedEmailException | TokenExpiredException ex) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE)); + if (ex instanceof TokenExpiredException) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE)); + } else { + return ResponseEntity.status(HttpStatus.FOUND).body(new ResponseItem().status(ApiMessageCode.WARN_MESSAGE)); + } } } @@ -48,6 +52,9 @@ public class EmailConfirmation { this.emailConfirmationManager.sendConfirmationEmail(email, principal); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE)); } catch (Exception ex) { + if (ex instanceof HasConfirmedEmailException) { + return ResponseEntity.status(HttpStatus.FOUND).body(new ResponseItem().status(ApiMessageCode.WARN_MESSAGE)); + } return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE)); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/EmailConfirmationManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/EmailConfirmationManager.java index 907ceac18..bf26fa3e4 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/EmailConfirmationManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/EmailConfirmationManager.java @@ -34,20 +34,21 @@ public class EmailConfirmationManager { .getDatabaseRepository().getLoginConfirmationEmailDao().asQueryable() .where((builder, root) -> builder.equal(root.get("token"), UUID.fromString(token))).getSingle(); - if (loginConfirmationEmail.getExpiresAt().compareTo(new Date()) < 0) - throw new TokenExpiredException("Token has expired."); - UserInfo user = databaseRepository.getUserInfoDao().asQueryable() .where((builder, root) -> builder.equal(root.get("id"), loginConfirmationEmail.getUserId())).getSingle(); if (user.getEmail() != null) throw new HasConfirmedEmailException("User already has confirmed his Email."); + if (loginConfirmationEmail.getExpiresAt().compareTo(new Date()) < 0) + throw new TokenExpiredException("Token has expired."); + loginConfirmationEmail.setIsConfirmed(true); // Checks if mail is used by another user. If it is, merges the new the old. - UserInfo oldUser = databaseRepository.getUserInfoDao().asQueryable().where((builder, root) -> builder.equal(root.get("email"), loginConfirmationEmail.getEmail())).getSingle(); - if (oldUser != null) { + Long existingUsers = databaseRepository.getUserInfoDao().asQueryable().where((builder, root) -> builder.equal(root.get("email"), loginConfirmationEmail.getEmail())).count(); + if (existingUsers > 0) { + UserInfo oldUser = databaseRepository.getUserInfoDao().asQueryable().where((builder, root) -> builder.equal(root.get("email"), loginConfirmationEmail.getEmail())).getSingle(); mergeNewUserToOld(user, oldUser); expireUserToken(user); databaseRepository.getLoginConfirmationEmailDao().createOrUpdate(loginConfirmationEmail); diff --git a/dmp-frontend/src/app/ui/auth/login/email-confirmation/email-confirmation.component.ts b/dmp-frontend/src/app/ui/auth/login/email-confirmation/email-confirmation.component.ts index fb12bf926..317f563fb 100644 --- a/dmp-frontend/src/app/ui/auth/login/email-confirmation/email-confirmation.component.ts +++ b/dmp-frontend/src/app/ui/auth/login/email-confirmation/email-confirmation.component.ts @@ -62,7 +62,12 @@ export class EmailConfirmation extends BaseComponent implements OnInit { } onCallbackError(error: any) { + if (error.status === 302) { + this.uiNotificationService.snackBarNotification(this.language.instant('EMAIL-CONFIRMATION.EMAIL-FOUND'), SnackBarNotificationLevel.Warning); + this.router.navigate(['home']); + } else { this.uiNotificationService.snackBarNotification(this.language.instant('EMAIL-CONFIRMATION.EXPIRED-EMAIL'), SnackBarNotificationLevel.Error); this.router.navigate(['login']); + } } } diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index a9c709c60..cdad8fbd4 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -146,7 +146,8 @@ "REQUEST-EMAIL-HEADER": "We are almost done! Please fill your e-mail.", "REQUEST-EMAIL-TEXT": "You will need to confirm it to use the application.", "SUBMIT": "Submit", - "SENT-EMAIL-HEADER": "Email was send!" + "SENT-EMAIL-HEADER": "Email was send!", + "EMAIL-FOUND": "Email is already confirmed" }, "HOME": { "DMPS": "DMPs", From f5de71d0ad0bfe4d5db26d6f6c271d74b064c745 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Thu, 30 Jan 2020 12:51:01 +0200 Subject: [PATCH 106/106] Improve the styling of related DPMs on user profile --- .../src/app/ui/user-profile/user-profile.component.html | 5 ++--- .../src/app/ui/user-profile/user-profile.component.scss | 4 ++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dmp-frontend/src/app/ui/user-profile/user-profile.component.html b/dmp-frontend/src/app/ui/user-profile/user-profile.component.html index 66b164950..2a61dc7f6 100644 --- a/dmp-frontend/src/app/ui/user-profile/user-profile.component.html +++ b/dmp-frontend/src/app/ui/user-profile/user-profile.component.html @@ -32,9 +32,8 @@
- -
+ +
{{dmp.label}}
diff --git a/dmp-frontend/src/app/ui/user-profile/user-profile.component.scss b/dmp-frontend/src/app/ui/user-profile/user-profile.component.scss index 8c566320d..36426b892 100644 --- a/dmp-frontend/src/app/ui/user-profile/user-profile.component.scss +++ b/dmp-frontend/src/app/ui/user-profile/user-profile.component.scss @@ -1,6 +1,10 @@ .clickable{ cursor: pointer; } +.clickable:hover { + //text-decoration: underline; //Alternative + color: #00b29f !important; +} // .two-line-mat-option { // height: 3.5em; // line-height: 1.2em;