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 dcb99e942..5b375c49b 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 @@ -4,6 +4,7 @@ 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.recent.model.RecentActivityModel; import eu.eudat.models.data.dashboard.searchbar.SearchBarItem; import eu.eudat.models.data.dashboard.statistics.DashBoardStatistics; import eu.eudat.models.data.helpers.responses.ResponseItem; @@ -15,6 +16,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import javax.transaction.Transactional; import java.io.IOException; import java.util.List; @@ -42,6 +44,14 @@ public class DashBoardController extends BaseController { return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).payload(statistics)); } + @RequestMapping(method = RequestMethod.GET, value = {"/dashboard/recentActivity"}, produces = "application/json") + @Transactional + public ResponseEntity>> getNewRecentActivity(@RequestParam(name = "numOfActivities", required = false, defaultValue = "5") Integer numberOfActivities, + @ClaimedAuthorities(claims = {Authorities.ADMIN, Authorities.MANAGER, Authorities.USER, Authorities.ANONYMOUS}) Principal principal) { + List statistics = dashBoardManager.getNewRecentActivity(principal, numberOfActivities); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem>().status(ApiMessageCode.NO_MESSAGE).payload(statistics)); + } + @RequestMapping(method = RequestMethod.GET, value = {"/user/recentActivity"}, produces = "application/json") public ResponseEntity> getRecentActivity(@RequestParam(name = "numOfActivities", required = false, defaultValue = "5") Integer numberOfActivities, Principal principal) { RecentActivity statistics = dashBoardManager.getRecentActivity(principal, numberOfActivities); 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 50e45f103..eba7e1a58 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 @@ -11,21 +11,27 @@ import eu.eudat.elastic.entities.Dmp; import eu.eudat.logic.builders.model.models.RecentActivityDataBuilder; import eu.eudat.logic.services.ApiContext; import eu.eudat.logic.services.operations.DatabaseRepository; +import eu.eudat.models.HintedModelFactory; import eu.eudat.models.data.dashboard.recent.RecentActivity; import eu.eudat.models.data.dashboard.recent.RecentActivityData; +import eu.eudat.models.data.dashboard.recent.model.RecentActivityModel; +import eu.eudat.models.data.dashboard.recent.model.RecentDatasetModel; +import eu.eudat.models.data.dashboard.recent.model.RecentDmpModel; import eu.eudat.models.data.dashboard.searchbar.SearchBarItem; import eu.eudat.models.data.dashboard.statistics.DashBoardStatistics; +import eu.eudat.models.data.listingmodels.DataManagementPlanListingModel; +import eu.eudat.models.data.listingmodels.DatasetListingModel; import eu.eudat.models.data.security.Principal; +import eu.eudat.queryable.QueryableList; import eu.eudat.types.searchbar.SearchBarItemType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import javax.transaction.Transactional; import java.io.IOException; -import java.util.LinkedList; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -175,6 +181,55 @@ public class DashBoardManager { return activity; } + @Transactional + public List getNewRecentActivity(Principal principal, Integer numberofactivities) { + List recentActivityModels = new ArrayList<>(); + DMPDao dataManagementPlanRepository = databaseRepository.getDmpDao(); + DatasetDao datasetRepository = databaseRepository.getDatasetDao(); + UserInfo user = new UserInfo(); + user.setId(principal.getId()); + DatasetCriteria datasetCriteria = new DatasetCriteria(); + datasetCriteria.setAllVersions(false); + DataManagementPlanCriteria dataManagementPlanCriteria = new DataManagementPlanCriteria(); + dataManagementPlanCriteria.setAllVersions(false); + + QueryableList dmpList; + QueryableList datasetList; + + if (principal.getId() != null) { + List roles = new LinkedList<>(); + dmpList = dataManagementPlanRepository.getAuthenticated(dataManagementPlanRepository.getWithCriteria(dataManagementPlanCriteria), principal.getId(), roles); + datasetList = datasetRepository.getAuthenticated(datasetRepository.getWithCriteria(datasetCriteria), user, roles); + } else { + dataManagementPlanCriteria.setIsPublic(true); + dataManagementPlanCriteria.setOnlyPublic(true); + datasetCriteria.setIsPublic(true); + dmpList = dataManagementPlanRepository.getWithCriteria(dataManagementPlanCriteria); + datasetList = datasetRepository.getWithCriteria(datasetCriteria); + } + + CompletableFuture> dmps = dmpList + .withHint(HintedModelFactory.getHint(DataManagementPlanListingModel.class)) + .orderBy((builder, root) -> builder.desc(root.get("modified"))) + .take(numberofactivities) + .selectAsync(item -> { + return new RecentDmpModel().fromEntity(item); + }) + .whenComplete((dmpActivities, throwable) -> recentActivityModels.addAll(dmpActivities)); + + CompletableFuture> datasets = datasetList + .withHint(HintedModelFactory.getHint(DatasetListingModel.class)) + .orderBy((builder, root) -> builder.desc(root.get("modified"))) + .take(numberofactivities) + .selectAsync(item -> { + return new RecentDatasetModel().fromEntity(item); + }) + .whenComplete((datasetActivities, throwable) -> recentActivityModels.addAll(datasetActivities)); + + CompletableFuture.allOf(dmps, datasets).join(); + return recentActivityModels.stream().sorted(Comparator.comparing(RecentActivityModel::getModified)).collect(Collectors.toList()); + } + public List searchUserData(String like, Principal principal) { UserInfo user = new UserInfo(); user.setId(principal.getId()); 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 feff5dda3..caaba293d 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 @@ -186,7 +186,7 @@ public class DatasetManager { CompletableFuture> itemsFuture = pagedItems. - selectAsync(item -> new DatasetListingModel().fromDataModel(item)).whenComplete((resultList, throwable) -> { + selectAsync(this::mapModel).whenComplete((resultList, throwable) -> { dataTable.setData(resultList); }); @@ -240,7 +240,7 @@ public class DatasetManager { DataTableData dataTable = new DataTableData<>(); CompletableFuture> itemsFuture = pagedItems. - selectAsync(item -> new DatasetListingModel().fromDataModel(item)).whenComplete((resultList, throwable) -> { + selectAsync(this::mapModel).whenComplete((resultList, throwable) -> { dataTable.setData(resultList); }); @@ -1024,4 +1024,16 @@ public class DatasetManager { dstTags.add(tag); } } + + private DatasetListingModel mapModel(Dataset item) { + DatasetListingModel listingModel = new DatasetListingModel().fromDataModel(item); + DatasetProfileCriteria criteria = new DatasetProfileCriteria(); + criteria.setGroupIds(Collections.singletonList(item.getProfile().getGroupId())); + List profiles = apiContext.getOperationsContext().getDatabaseRepository().getDatasetProfileDao().getWithCriteria(criteria).toList(); + boolean islast = false; + profiles = profiles.stream().sorted(Comparator.comparing(DatasetProfile::getVersion)).collect(Collectors.toList()); + islast = profiles.get(0).getId().equals(item.getProfile().getId()); + listingModel.setProfileLatestVersion(islast); + return listingModel; + } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/recent/model/RecentActivityModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/recent/model/RecentActivityModel.java new file mode 100644 index 000000000..015c76af3 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/recent/model/RecentActivityModel.java @@ -0,0 +1,125 @@ +package eu.eudat.models.data.dashboard.recent.model; + +import java.util.Date; + +public abstract class RecentActivityModel { + private String id; + private String title; + private String description; + private Date created; + private Date modified; + private int status; + private int version; + private String grant; + private String grantAbbreviation; + private String grantId; + private Date finalizedAt; + private Date publishedAt; + private String profile; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getModified() { + return modified; + } + + public void setModified(Date modified) { + this.modified = modified; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public String getGrant() { + return grant; + } + + public void setGrant(String grant) { + this.grant = grant; + } + + public String getGrantAbbreviation() { + return grantAbbreviation; + } + + public void setGrantAbbreviation(String grantAbbreviation) { + this.grantAbbreviation = grantAbbreviation; + } + + public String getGrantId() { + return grantId; + } + + public void setGrantId(String grantId) { + this.grantId = grantId; + } + + public Date getFinalizedAt() { + return finalizedAt; + } + + public void setFinalizedAt(Date finalizedAt) { + this.finalizedAt = finalizedAt; + } + + public Date getPublishedAt() { + return publishedAt; + } + + public void setPublishedAt(Date publishedAt) { + this.publishedAt = publishedAt; + } + + public String getProfile() { + return profile; + } + + public void setProfile(String profile) { + this.profile = profile; + } + + public abstract RecentActivityModel fromEntity(T entity); +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/recent/model/RecentDatasetModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/recent/model/RecentDatasetModel.java new file mode 100644 index 000000000..58156453c --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/recent/model/RecentDatasetModel.java @@ -0,0 +1,100 @@ +package eu.eudat.models.data.dashboard.recent.model; + +import eu.eudat.data.entities.Dataset; +import eu.eudat.logic.utilities.helpers.LabelBuilder; +import eu.eudat.models.data.dataset.DataRepository; +import eu.eudat.models.data.dataset.Service; +import eu.eudat.models.data.listingmodels.DatasetListingModel; + +import java.util.Date; +import java.util.stream.Collectors; + +public class RecentDatasetModel extends RecentActivityModel { + private String dmp; + private String dmpId; + private String dataRepositories; + private String registries; + private String services; + + public String getDmp() { + return dmp; + } + + public void setDmp(String dmp) { + this.dmp = dmp; + } + + public String getDmpId() { + return dmpId; + } + + public void setDmpId(String dmpId) { + this.dmpId = dmpId; + } + + public String getDataRepositories() { + return dataRepositories; + } + + public void setDataRepositories(String dataRepositories) { + this.dataRepositories = dataRepositories; + } + + public String getRegistries() { + return registries; + } + + public void setRegistries(String registries) { + this.registries = registries; + } + + public String getServices() { + return services; + } + + public void setServices(String services) { + this.services = services; + } + + @Override + public RecentActivityModel fromEntity(Dataset entity) { + this.setId(entity.getId().toString()); + this.setTitle(entity.getLabel()); + this.setDescription(entity.getDescription()); + this.setCreated(entity.getCreated()); + this.setModified(entity.getModified()); + this.setStatus(entity.getStatus()); + this.setVersion(entity.getDmp() != null ? entity.getDmp().getVersion(): 0); + this.setFinalizedAt(entity.getFinalizedAt()); + this.setGrantAbbreviation(entity.getDmp() != null ? entity.getDmp().getGrant().getAbbreviation() : ""); + this.setPublishedAt(entity.getDmp() != null ? entity.getDmp().getPublishedAt() : new Date()); + this.setGrantId(entity.getDmp() != null ? entity.getDmp().getGrant().getId().toString() : ""); + this.setProfile(entity.getProfile() != null ? entity.getProfile().getLabel() : ""); + this.setGrant(entity.getDmp() != null ? entity.getDmp().getGrant().getLabel() : ""); + this.setDataRepositories(entity.getDatasetDataRepositories() != null && !entity.getDatasetDataRepositories().isEmpty()? LabelBuilder.getLabel(entity.getDatasetDataRepositories().stream().map(item -> new DataRepository().fromDataModel(item.getDataRepository())).collect(Collectors.toList())) : ""); + this.setDmp( entity.getDmp() != null ? entity.getDmp().getLabel() : ""); + this.setDmpId(entity.getDmp() != null ? entity.getDmp().getId().toString() : ""); + this.setRegistries(LabelBuilder.getLabel(entity.getRegistries().stream().map(item -> new eu.eudat.models.data.dataset.Registry().fromDataModel(item)).collect(Collectors.toList()))); + this.setServices(LabelBuilder.getLabel(entity.getServices().stream().map(item -> new Service().fromDataModel(item.getService())).collect(Collectors.toList()))); + return this; + } + + public RecentDatasetModel fromDmpEntity(Dataset entity) { + this.setId(entity.getId().toString()); + this.setTitle(entity.getLabel()); + this.setDescription(entity.getDescription()); + this.setCreated(entity.getCreated()); + this.setModified(entity.getModified()); + this.setStatus(entity.getStatus()); + this.setVersion(entity.getDmp() != null ? entity.getDmp().getVersion(): 0); + this.setFinalizedAt(entity.getFinalizedAt()); + this.setGrantAbbreviation(entity.getDmp() != null ? entity.getDmp().getGrant().getAbbreviation() : ""); + this.setPublishedAt(entity.getDmp() != null ? entity.getDmp().getPublishedAt() : new Date()); + this.setGrantId(entity.getDmp() != null ? entity.getDmp().getGrant().getId().toString() : ""); + this.setProfile(entity.getProfile() != null ? entity.getProfile().getLabel() : ""); + this.setGrant(entity.getDmp() != null ? entity.getDmp().getGrant().getLabel() : ""); + this.setDmp( entity.getDmp() != null ? entity.getDmp().getLabel() : ""); + this.setDmpId(entity.getDmp() != null ? entity.getDmp().getId().toString() : ""); + return this; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/recent/model/RecentDmpModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/recent/model/RecentDmpModel.java new file mode 100644 index 000000000..9c28bdec2 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/dashboard/recent/model/RecentDmpModel.java @@ -0,0 +1,114 @@ +package eu.eudat.models.data.dashboard.recent.model; + +import eu.eudat.data.entities.DMP; +import eu.eudat.logic.utilities.helpers.LabelBuilder; +import eu.eudat.models.data.dmp.AssociatedProfile; +import eu.eudat.models.data.dmp.Organisation; +import eu.eudat.models.data.listingmodels.UserInfoListingModel; + +import javax.transaction.Transactional; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +public class RecentDmpModel extends RecentActivityModel { + private String doi; + private Map extraProperties; + private List datasets; + private List associatedProfiles; + private String organisations; + private UUID groupId; + private List users; + private Boolean isPublic; + + + public String getDoi() { + return doi; + } + + public void setDoi(String doi) { + this.doi = doi; + } + + public Map getExtraProperties() { + return extraProperties; + } + + public void setExtraProperties(Map extraProperties) { + this.extraProperties = extraProperties; + } + + public List getDatasets() { + return datasets; + } + + public void setDatasets(List datasets) { + this.datasets = datasets; + } + + public List getAssociatedProfiles() { + return associatedProfiles; + } + + public void setAssociatedProfiles(List associatedProfiles) { + this.associatedProfiles = associatedProfiles; + } + + public String getOrganisations() { + return organisations; + } + + public void setOrganisations(String organisations) { + this.organisations = organisations; + } + + public UUID getGroupId() { + return groupId; + } + + public void setGroupId(UUID groupId) { + this.groupId = groupId; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } + + public Boolean getPublic() { + return isPublic; + } + + public void setPublic(Boolean aPublic) { + isPublic = aPublic; + } + + @Override + @Transactional + public RecentActivityModel fromEntity(DMP entity) { + this.setId(entity.getId().toString()); + this.setTitle(entity.getLabel()); + this.setDescription(entity.getDescription()); + this.setCreated(entity.getCreated()); + this.setModified(entity.getModified()); + this.setStatus(entity.getStatus()); + this.setVersion(entity.getVersion()); + this.datasets = entity.getDataset().stream().map(dataset -> new RecentDatasetModel().fromDmpEntity(dataset)).collect(Collectors.toList()); + this.associatedProfiles = entity.getAssociatedDmps().stream().map(item -> new AssociatedProfile().fromData(item)).collect(Collectors.toList()); + this.setFinalizedAt(entity.getFinalizedAt()); + this.setGrant(entity.getGrant().getLabel()); + this.setGrantAbbreviation(entity.getGrant().getAbbreviation()); + this.setGrantId(entity.getGrant().getId().toString()); + this.groupId = entity.getGroupId(); + this.isPublic = entity.isPublic(); + this.organisations = LabelBuilder.getLabel(entity.getOrganisations().stream().map(item -> new Organisation().fromDataModel(item)).collect(Collectors.toList())); + if (entity.getProfile() != null) this.setProfile(entity.getProfile().getLabel()); + this.setPublishedAt(entity.getPublishedAt()); + this.users = entity.getUsers().stream().map(x -> new UserInfoListingModel().fromDataModel(x)).collect(Collectors.toList()); + return this; + } +} 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 3e3e52b40..fab2747d7 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 @@ -6,7 +6,9 @@ import eu.eudat.models.data.dataset.DataRepository; import eu.eudat.models.data.dataset.Service; import eu.eudat.logic.utilities.helpers.LabelBuilder; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.stream.Collectors; @@ -29,6 +31,9 @@ public class DatasetListingModel implements DataModel users; + private Boolean isPublic; + private Boolean isProfileLatestVersion; public String getId() { return id; @@ -156,6 +161,30 @@ public class DatasetListingModel implements DataModel getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } + + public Boolean getPublic() { + return isPublic; + } + + public void setPublic(Boolean aPublic) { + isPublic = aPublic; + } + + public Boolean getProfileLatestVersion() { + return isProfileLatestVersion; + } + + public void setProfileLatestVersion(Boolean profileLatestVersion) { + isProfileLatestVersion = profileLatestVersion; + } + @Override public DatasetListingModel fromDataModel(Dataset entity) { this.id = entity.getId() != null ? entity.getId().toString() : ""; @@ -176,6 +205,8 @@ public class DatasetListingModel implements DataModel new UserInfoListingModel().fromDataModel(x)).collect(Collectors.toList()) : new ArrayList<>(); + this.isPublic = entity.getDmp() != null ? entity.getDmp().isPublic() : false; return this; } diff --git a/dmp-frontend/src/app/app.component.html b/dmp-frontend/src/app/app.component.html index 4da74d4e8..6db7d1e40 100644 --- a/dmp-frontend/src/app/app.component.html +++ b/dmp-frontend/src/app/app.component.html @@ -4,7 +4,7 @@ - +
diff --git a/dmp-frontend/src/app/app.component.scss b/dmp-frontend/src/app/app.component.scss index 68549ddb0..f0b0cde9c 100644 --- a/dmp-frontend/src/app/app.component.scss +++ b/dmp-frontend/src/app/app.component.scss @@ -28,6 +28,10 @@ opacity: 1; } +.sidenav-content { + background-color: whitesmoke; +} + .sidebar-shadow { box-shadow: 0 4px 18px 0px rgba(0, 0, 0, 0.12), 0 7px 10px -5px rgba(0, 0, 0, 0.15); z-index: 100; 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 5202636ab..78fbb8596 100644 --- a/dmp-frontend/src/app/core/model/dataset/dataset-listing.ts +++ b/dmp-frontend/src/app/core/model/dataset/dataset-listing.ts @@ -11,10 +11,13 @@ export interface DatasetListingModel { registries: String; services: String; description: String; - status: Number; + status: number; created: Date; modified: Date; finalizedAt: Date; dmpPublishedAt?: Date; version: number; + users: any[]; + public: boolean; + isProfileLatestVersion: boolean; } diff --git a/dmp-frontend/src/app/core/model/dmp/dmp-listing.ts b/dmp-frontend/src/app/core/model/dmp/dmp-listing.ts index 93b02558d..b2811228c 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp-listing.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp-listing.ts @@ -1,4 +1,5 @@ import { DmpStatus } from "../../common/enum/dmp-status"; +import { DmpAssociatedProfileModel } from '../dmp-profile/dmp-associated-profile'; export interface DmpListingModel { id: string; @@ -17,7 +18,7 @@ export interface DmpListingModel { groupId: string; version: number; datasets: any[]; - associatedProfiles: any[]; + associatedProfiles: DmpAssociatedProfileModel[]; users: any[]; public: boolean; } diff --git a/dmp-frontend/src/app/core/model/dmp/dmp-overview.ts b/dmp-frontend/src/app/core/model/dmp/dmp-overview.ts index d6ac742cf..da5802817 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp-overview.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp-overview.ts @@ -1,5 +1,4 @@ import { OrganizationModel } from "../organisation/organization"; -import { DatasetUrlListing } from "../dataset/dataset-url-listing"; import { UserInfoListingModel } from "../user/user-info-listing"; import { DmpAssociatedProfileModel } from "../dmp-profile/dmp-associated-profile"; import { ResearcherModel } from "../researcher/researcher"; diff --git a/dmp-frontend/src/app/core/model/recent-activity/recent-activity.model.ts b/dmp-frontend/src/app/core/model/recent-activity/recent-activity.model.ts new file mode 100644 index 000000000..b195e63b2 --- /dev/null +++ b/dmp-frontend/src/app/core/model/recent-activity/recent-activity.model.ts @@ -0,0 +1,16 @@ +export class RecentActivityModel { + id: String; + title: String; + description: String; + created: Date; + modified: Date; + status: number; + version: number; + grant: String; + grantAbbreviation: String; + grantId: String; + finalizedAt: Date; + publishedAt: Date; + profile: String; +} + diff --git a/dmp-frontend/src/app/core/model/recent-activity/recent-dataset-activity.model.ts b/dmp-frontend/src/app/core/model/recent-activity/recent-dataset-activity.model.ts new file mode 100644 index 000000000..5fb6bca2b --- /dev/null +++ b/dmp-frontend/src/app/core/model/recent-activity/recent-dataset-activity.model.ts @@ -0,0 +1,9 @@ +import { RecentActivityModel } from "./recent-activity.model"; + +export class RecentDatasetModel extends RecentActivityModel { + dmp: String; + dmpId: String; + dataRepositories: String; + registries: String; + services: String; +} diff --git a/dmp-frontend/src/app/core/model/recent-activity/recent-dmp-activity.model.ts b/dmp-frontend/src/app/core/model/recent-activity/recent-dmp-activity.model.ts new file mode 100644 index 000000000..88045ace9 --- /dev/null +++ b/dmp-frontend/src/app/core/model/recent-activity/recent-dmp-activity.model.ts @@ -0,0 +1,15 @@ +import { RecentActivityModel } from './recent-activity.model'; +import { RecentDatasetModel } from './recent-dataset-activity.model'; +import { DmpAssociatedProfileModel } from '../dmp-profile/dmp-associated-profile'; +import { UserInfoListingModel } from '../user/user-info-listing'; + +export class RecentDmpModel extends RecentActivityModel { + doi: String; + extraProperties: Map; + datasets: RecentDatasetModel[]; + associatedProfiles: DmpAssociatedProfileModel[]; + organisations: String; + groupId: string; + users: UserInfoListingModel[]; + isPublic: boolean; +} diff --git a/dmp-frontend/src/app/core/services/dashboard/dashboard.service.ts b/dmp-frontend/src/app/core/services/dashboard/dashboard.service.ts index 2046a1b20..5c138a638 100644 --- a/dmp-frontend/src/app/core/services/dashboard/dashboard.service.ts +++ b/dmp-frontend/src/app/core/services/dashboard/dashboard.service.ts @@ -5,6 +5,7 @@ import { environment } from '../../../../environments/environment'; import { DashboardStatisticsModel } from '../../model/dashboard/dashboard-statistics-model'; import { BaseHttpService } from '../http/base-http.service'; import { ConfigurationService } from '../configuration/configuration.service'; +import { RecentActivityModel } from '@app/core/model/recent-activity/recent-activity.model'; @Injectable() export class DashboardService { @@ -24,4 +25,8 @@ export class DashboardService { getUserStatistics(): Observable { return this.http.get(this.actionUrl + 'me/getStatistics', { headers: this.headers }); } + + getRecentAcitvity(): Observable { + return this.http.get(this.actionUrl + 'recentActivity', {headers: this.headers}); + } } diff --git a/dmp-frontend/src/app/ui/dashboard/dashboard.component.html b/dmp-frontend/src/app/ui/dashboard/dashboard.component.html index 4eb1246b5..601ccf0bd 100644 --- a/dmp-frontend/src/app/ui/dashboard/dashboard.component.html +++ b/dmp-frontend/src/app/ui/dashboard/dashboard.component.html @@ -1,4 +1,4 @@ -
+
- clear -

What is a DMP in ARGOS

-

A Data Management Plan (DMP) is a living document describing the datasets that are generated and/ or re-used - during and after a research lifetime. DMPs aim to provide researchers with essential information to re-produce, - re-distribute and re-purpose research results thus assuring for their validity and exploitation.

-

- New with DMPs? Visit OpenAIRE’s Guide for Researchers to learn more about how to create one! -

-
- - -
+ +

What is a DMP in ARGOS

+

A Data Management Plan (DMP) is a living document describing the datasets that are generated and/ or re-used + during and after a research lifetime. DMPs aim to provide researchers with essential information to re-produce, + re-distribute and re-purpose research results thus assuring for their validity and exploitation.

+

+ New with DMPs? Visit OpenAIRE’s Guide for Researchers to learn more about how to create one! +

+
+ + +
-
-
+
+
Personal usage
0
DMP's @@ -31,7 +31,7 @@ Grants
0
Related organizations -
+
- clear -

A DMP in Argos consists of key information about research, - such as purpose, - objectives and researchers involved, but also about documentation of research datasets, - namely Dataset - Descriptions, that highlight the steps followed and the means used across data - management activities.

+ clear +

+ {{'DASHBOARD.DMP-ABOUT-BEG' | translate}} + {{'DASHBOARD.DATASET-DESCRIPTIONS' | translate}} + {{'DASHBOARD.DMP-ABOUT-END' | translate}}

- +
Latest activity
- -
+
- - - + +
+ +
+ +
+ +
+ +
+ +
-
- -
-
Personal usage
+
{{'DASHBOARD.PERSONAL-USAGE' | translate}}
{{dashboardStatisticsData?.totalDataManagementPlanCount}}
- DMP's + {{'DASHBOARD.DMPS' | translate}}
{{dashboardStatisticsData?.totalDataSetCount}}
- Dataset Descriptions + {{'DASHBOARD.DATASET-DESCRIPTIONS' | translate}}
{{dashboardStatisticsData?.totalGrantCount}}
- Grants + {{'DASHBOARD.GRANTS' | translate}}
{{dashboardStatisticsData?.totalOrganisationCount}}
- Related organizations + {{'DASHBOARD.RELATED-ORGANISATIONS' | translate}}
diff --git a/dmp-frontend/src/app/ui/dashboard/dashboard.component.scss b/dmp-frontend/src/app/ui/dashboard/dashboard.component.scss index 0f1cf98cc..914d21664 100644 --- a/dmp-frontend/src/app/ui/dashboard/dashboard.component.scss +++ b/dmp-frontend/src/app/ui/dashboard/dashboard.component.scss @@ -1,7 +1,7 @@ .main-content { background-color: #f5f5f5; padding-top: 3.68rem; - padding-bottom: 10rem; + padding-bottom: 3rem; // padding-left: 3.31rem; padding-left: 1rem; margin: 0; diff --git a/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts b/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts index 88ac33dac..06a3f2939 100644 --- a/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts @@ -8,8 +8,6 @@ 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'; @@ -55,6 +53,11 @@ export class DashboardComponent extends BaseComponent implements OnInit, IBreadC dmpListingItems: DmpListingModel[] = []; datasetListingItems: DatasetListingModel[] = []; + totalDatasets: number; + totalDmps: number; + totalDraftDatasets: number; + + constructor( private router: Router, private route: ActivatedRoute, @@ -187,6 +190,18 @@ export class DashboardComponent extends BaseComponent implements OnInit, IBreadC this.isVisible = false; } + onCountDmps(event): void { + this.totalDmps = event; + } + + onCountDatasets(event): void { + this.totalDatasets = event; + } + + onCountDraftDatasets(event): void { + this.totalDraftDatasets = event; + } + // viewAllPublicDmpsClicked() { // this.router.navigate(['/explore-plans']); // } diff --git a/dmp-frontend/src/app/ui/dashboard/dashboard.module.ts b/dmp-frontend/src/app/ui/dashboard/dashboard.module.ts index e8f39241c..0d5b845a2 100644 --- a/dmp-frontend/src/app/ui/dashboard/dashboard.module.ts +++ b/dmp-frontend/src/app/ui/dashboard/dashboard.module.ts @@ -14,15 +14,17 @@ import { RecentVisitedActivityComponent } from '@app/ui/dashboard/recent-visited 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'; -import { GuestModule } from '../guest/guest.module'; -import { GuestComponent } from '../guest/guest.component'; +import { RecentEditedDatasetActivityComponent } from './recent-edited-dataset-activity/recent-edited-dataset-activity.component'; +import { DatasetCopyDialogModule } from '../dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.module'; +import { RecentEditedDmpActivityComponent } from './recent-edited-dmp-activity/recent-edited-dmp-activity.component'; @NgModule({ imports: [ CommonUiModule, DashboardRoutingModule, ExportMethodDialogModule, - ConfirmationDialogModule + ConfirmationDialogModule, + DatasetCopyDialogModule ], declarations: [ DashboardComponent, @@ -35,7 +37,9 @@ import { GuestComponent } from '../guest/guest.component'; RecentEditedActivityComponent, DraftsComponent, DmpInfoCounterComponent, - DatasetInfoCounterComponent + DatasetInfoCounterComponent, + RecentEditedDatasetActivityComponent, + RecentEditedDmpActivityComponent ], entryComponents: [ QuickWizardCreateAdd diff --git a/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.css b/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.css index fd3281a27..893d3700c 100644 --- a/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.css +++ b/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.css @@ -1,4 +1,181 @@ -.grey { +.latest-activity-title { + text-align: left; + font-weight: 300; + font-family: "Roboto", sans-serif; + font-size: 1.25rem; + letter-spacing: 0px; + color: #212121; + opacity: 0.6; + padding-bottom: 1.2rem; +} + +.dmp-card, +.dataset-card { + min-width: 712px; + /* min-height: 308px; */ + background: #ffffff 0% 0% no-repeat padding-box; + box-shadow: 0px 3px 6px #0000001a; + border-radius: 4px; + opacity: 1; + margin-top: 2.43rem; + margin-bottom: 1rem; +} + +.remove-border-bottom ::ng-deep .mat-tab-header { + border-bottom: none; +} + +input[type="text"] { + background: #fafafa 0% 0% no-repeat padding-box; + border: 1px solid #d1d1d1; + border-radius: 4px; + opacity: 1; + width: 347px; + height: 56px; + font-family: Arial, FontAwesome; + padding-left: 15px; +} + +.edited-date { + text-align: left; + font-weight: 300; + font-family: "Roboto", sans-serif; + line-height: 2.4; + letter-spacing: 0px; + color: #212121; + opacity: 0.6; +} + +.dmp-label { + background: #129d99 0% 0% no-repeat padding-box; + border-radius: 4px 0px; + opacity: 1; + width: 67px; + height: 37px; + color: #ffffff; + line-height: 2.4; + opacity: 0.75; +} + +.dataset-label { + width: 158px; + height: 37px; + background: #f7dd72 0% 0% no-repeat padding-box; + border-radius: 4px 0px; + text-align: left; + line-height: 2.8; + font-size: 0.875rem; + letter-spacing: 0px; + color: #212121; + opacity: 0.75; +} + +.dmp-title, +.dataset-title { + text-align: left; + font-weight: 500; + font-family: "Roboto", sans-serif; + font-size: 1rem; + opacity: 0.81; + padding-top: 0.75rem; + padding-bottom: 0.55rem; + color: #212121; +} + +.dataset-subtitle, +.dmp-subtitle { + display: flex; + flex-direction: row; + text-align: left; + font-weight: 400; + font-family: "Roboto", sans-serif; + font-size: 0.875rem; + opacity: 1; + align-items: center; + color: #848484; +} + +.dmp-title-draft { + text-align: left; + font-weight: 500; + font-family: "Roboto", sans-serif; + font-size: 1rem; + opacity: 0.81; + padding-top: 0.75rem; + padding-bottom: 0.55rem; + color: #f16868; +} + +.icon-align { + display: inline-flex; + vertical-align: middle; + padding-bottom: 0.4rem; +} + +.dataset-card-actions, +.dmp-card-actions { + display: flex; + flex-direction: row; + border-top: 1px solid #dbdbdb; + line-height: 4; + color: #848484; +} + +.dataset-card-actions a, +.dmp-card-actions a { + color: #848484 !important; + text-decoration: none !important; +} + +.dataset-card-actions a:hover, +.dmp-card-actions a:hover { + color: #129d99 !important; +} + +.dmp-dataset-descriptions-title { + color: #000000; + opacity: 0.6; + padding-top: 1.5rem; + padding-bottom: 0.8rem; +} + +.dmp-dataset-descriptions-name { + color: #000000; + opacity: 0.6; + font-weight: 700; +} + +.show-more { + color: black !important; +} + +.show-more:hover { + color: #129d99 !important; +} + +.btn-load-more { + border: 2px solid #212121; + border-radius: 30px; + opacity: 1; + width: 132px; + height: 40px; + margin-top: 4.125rem; +} + +.btn-load-more:hover { + background-color: black; + color: white; +} + +.draft { + color: #f16868; +} + +.pointer { + cursor: pointer; +} + +/* .grey { color: rgb(162, 162, 162); } @@ -66,4 +243,4 @@ td:hover .draft-desc:after { .view-all:hover { color: rgb(46, 117, 182) !important; -} +} */ diff --git a/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.html b/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.html index cca60626e..767a57fb7 100644 --- a/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.html +++ b/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.html @@ -1,4 +1,69 @@ -
+
+
+
+ +
+
{{'DATASET-LISTING.DATASET-DESCRIPTION' | translate}}
+
{{'DATASET-LISTING.STATES.EDITED' | translate}}: {{activity.modified | date:"longDate"}}
+
+
{{'DATASET-LISTING.DATASET-DESCRIPTION' | translate}}: {{activity.label}}
+
+ {{ roleDisplay(activity.users) }} + . + public{{'DATASET-LISTING.STATES.PUBLIC' | translate}} + done{{ enumUtils.toDmpStatusString(activity.status) }} + create{{ enumUtils.toDmpStatusString(activity.status) }} + . + {{'DATASET-LISTING.COLUMNS.GRANT' | translate}}: {{activity.grant}} +
+
+
{{'DATASET-LISTING.TOOLTIP.PART-OF' | translate}} +
{{'DATASET-LISTING.TOOLTIP.DMP' | translate}}
+
+ +
{{'DATASET-LISTING.TOOLTIP.DMP-FOR' | translate}}: {{activity.dmp}}
+
+
+ + + + + + + + + + + + +
+
+
+ +
+ +
{{'GENERAL.NAMES.DATASET' | translate}}: {{ dataset.label }} {{'DRAFTS.FOR-DMP' | translate}} {{ dataset.dmp }} {{'DRAFTS.FOR-GRANT' | translate}} {{ dataset.grant }}
@@ -35,4 +97,4 @@
-
+ --> 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 1d18f127a..0d3a63409 100644 --- a/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, Input } from '@angular/core'; +import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core'; import { DatasetService } from '../../../core/services/dataset/dataset.service'; import { DataTableRequest } from '../../../core/model/data-table/data-table-request'; import { DatasetCriteria } from '../../../core/query/dataset/dataset-criteria'; @@ -7,32 +7,61 @@ import { AuthService } from '../../../core/services/auth/auth.service'; import { RecentActivityType } from '../../../core/common/enum/recent-activity-type'; import { Router} from '@angular/router'; import { DmpStatus } from '../../../core/common/enum/dmp-status'; +import { Principal } from '@app/core/model/auth/principal'; +import { TranslateService } from '@ngx-translate/core'; +import { takeUntil } from 'rxjs/operators'; +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 { FormControl } from '@angular/forms'; +import { BaseComponent } from '@common/base/base.component'; +import { MatDialog } from '@angular/material'; +import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; +import { SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service'; +import * as FileSaver from 'file-saver'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { UiNotificationService } from '@app/core/services/notification/ui-notification-service'; @Component({ selector: 'app-drafts', templateUrl: './drafts.component.html', styleUrls: ['./drafts.component.css'] }) -export class DraftsComponent implements OnInit { +export class DraftsComponent extends BaseComponent implements OnInit { + + @Input() routerLink: string; + @Output() totalCountDraftDatasets: EventEmitter = new EventEmitter(); + datasetDrafts: DatasetListingModel[]; datasetDraftsTypeEnum = RecentActivityType; - @Input() routerLink: string; status: number; + totalCount: number; + startIndex: number = 4; + pageSize: number = 5; + constructor( private router: Router, private datasetService: DatasetService, - private authentication: AuthService - ) { } + private authentication: AuthService, + private language: TranslateService, + public dialog: MatDialog, + private datasetWizardService: DatasetWizardService, + public enumUtils: EnumUtils, + private uiNotificationService: UiNotificationService + ) { + super(); + } ngOnInit() { const fields: Array = []; fields.push('-modified'); - const dmpDataTableRequest: DataTableRequest = new DataTableRequest(0, 2, { fields: fields }); + const dmpDataTableRequest: DataTableRequest = new DataTableRequest(0, 5, { fields: fields }); dmpDataTableRequest.criteria = new DatasetCriteria(); dmpDataTableRequest.criteria.status = DmpStatus.Draft; this.datasetService.getPaged(dmpDataTableRequest).subscribe(response => { this.datasetDrafts = response.data; + this.totalCount = response.totalCount; + this.totalCountDraftDatasets.emit(this.totalCount); }); } @@ -63,4 +92,147 @@ export class DraftsComponent implements OnInit { if (!this.isAuthenticated()) { return; } this.router.navigate(['/datasets'], { queryParams: { status: 0 } }); } + + roleDisplay(value: any) { + const principal: Principal = this.authentication.current(); + let role: number; + if (principal) { + value.forEach(element => { + if (principal.id === element.id) { + role = element.role; + } + }); + } + if (role === 0) { + return this.language.instant('DMP-LISTING.OWNER'); + } + else if (role === 1) { + return this.language.instant('DMP-LISTING.MEMBER'); + } + else { + return this.language.instant('DMP-LISTING.OWNER'); + } + } + + openDmpSearchDialogue(dataset: DatasetListingModel) { + const formControl = new FormControl(); + const dialogRef = this.dialog.open(DatasetCopyDialogueComponent, { + width: '500px', + restoreFocus: false, + data: { + formControl: formControl, + datasetId: dataset.id, + datasetProfileId: dataset.profile, + datasetProfileExist: false, + confirmButton: this.language.instant('DATASET-WIZARD.DIALOGUE.COPY'), + cancelButton: this.language.instant('DATASET-WIZARD.DIALOGUE.CANCEL') + } + }); + + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)) + .subscribe(result => { + if (result && result.datasetProfileExist) { + const newDmpId = result.formControl.value.id + this.router.navigate(['/datasets/copy/' + result.datasetId], { queryParams: { newDmpId: newDmpId } }); + } + }); + } + + openConfirm(id: string): void { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + maxWidth: '300px', + restoreFocus: false, + data: { + message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), + confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.DELETE'), + cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), + isDeleteConfirmation: true + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + this.datasetWizardService.delete(id) + .pipe(takeUntil(this._destroyed)) + .subscribe( + complete => this.onCallbackSuccess(), + error => this.onCallbackError(error) + ); + } + }); + } + + onCallbackSuccess(id?: String): void { + this.uiNotificationService.snackBarNotification(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) { + // this.setErrorModel(error.error); + } + + downloadPDF(dataset: DatasetListingModel): void { + this.datasetWizardService.downloadPDF(dataset.id as string) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/pdf' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + FileSaver.saveAs(blob, filename); + }); + } + + downloadDOCX(dataset: DatasetListingModel): void { + this.datasetWizardService.downloadDOCX(dataset.id as string) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/msword' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + FileSaver.saveAs(blob, filename); + }); + + } + + downloadXML(dataset: DatasetListingModel): void { + this.datasetWizardService.downloadXML(dataset.id as string) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/xml' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + FileSaver.saveAs(blob, filename); + }); + } + + getFilenameFromContentDispositionHeader(header: string): string { + const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g); + + const matches = header.match(regex); + let filename: string; + for (let i = 0; i < matches.length; i++) { + const match = matches[i]; + if (match.includes('filename="')) { + filename = match.substring(10, match.length - 1); + break; + } else if (match.includes('filename=')) { + filename = match.substring(9); + break; + } + } + return filename; + } + + public loadMore() { + const fields: Array = ["-modified"]; + const request = new DataTableRequest(this.startIndex, this.pageSize, { fields: fields }); + + request.criteria = new DatasetCriteria(); + request.criteria.like = ""; + + this.datasetService.getPaged(request).pipe(takeUntil(this._destroyed)).subscribe(result => { + if (!result) { return []; } + this.datasetDrafts = this.datasetDrafts.concat(result.data); + }); + this.startIndex = this.startIndex + this.pageSize; + } } diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.css b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.css index 89fa66950..c2ce5bb3c 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.css +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.css @@ -171,6 +171,9 @@ input[type="text"] { color: #f16868; } +.pointer { + cursor: pointer; +} /* th { text-transform: uppercase; diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.html b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.html index cba011c2f..0cf7f52f4 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.html +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.html @@ -1,51 +1,80 @@
-
-
-
{{ 'DMP-LISTING.DMP' | translate }}
-
{{ 'DMP-LISTING.EDITED' | translate }}: {{ activity.modifiedTime | date: "longDate" }}
+
+
+
+
{{ 'DMP-LISTING.DMP' | translate }}
+
{{ 'DMP-LISTING.EDITED' | translate }}: {{ activity.modifiedTime | date: "longDate" }}
+
+
{{activity.label}}
+
+ {{ roleDisplay(activity.users) }} + . + public{{'TYPES.DMP-VISIBILITY.PUBLIC' | translate}} + done{{ enumUtils.toDmpStatusString(activity.status) }} + create{{ enumUtils.toDmpStatusString(activity.status) }} + . + {{'DMP-LISTING.VERSION' | translate}} {{activity.version}} + . + {{ 'DMP-LISTING.GRANT' | translate }}: {{activity.grant}} +
+
{{'DMP-LISTING.CONTAINED-DATASETS' | translate}}: ({{activity.datasets.length}}) +
+
+
+
{{dataset.label}},
+
{{dataset.label}}
+
+
+ {{'GENERAL.ACTIONS.SHOW-MORE' | translate}}
-
{{activity.label}}
-
- Owner - . - public{{'TYPES.DMP-VISIBILITY.PUBLIC' | translate}} - done{{ enumUtils.toDmpStatusString(activity.status) }} - create{{ enumUtils.toDmpStatusString(activity.status) }} - . - Version 1 - . - {{ 'DMP-LISTING.GRANT' | translate }}: {{activity.grant}} -
-
Contained Dataset Descriptions (5) -
- - -
Dataset description: Horizon 2020 - for Grant DMP of Dataset description
- - Show - more + + + + + + + + + + + +
+
+ +
-
+ . Grant: NEANIAS Project
@@ -67,16 +95,15 @@ DMP plan
- + --> + + +
+
{{'DATASET-LISTING.DATASET-DESCRIPTION' | translate}}
+
{{'DATASET-LISTING.STATES.EDITED' | translate}}: {{activity.modified | date:"longDate"}}
+
+
{{'DATASET-LISTING.DATASET-DESCRIPTION' | translate}}: {{activity.label}}
+
+ {{ roleDisplay(activity.users) }} + . + public{{'DATASET-LISTING.STATES.PUBLIC' | translate}} + done{{ enumUtils.toDmpStatusString(activity.status) }} + create{{ enumUtils.toDmpStatusString(activity.status) }} + . + {{'DATASET-LISTING.COLUMNS.GRANT' | translate}}: {{activity.grant}} +
+
+
{{'DATASET-LISTING.TOOLTIP.PART-OF' | translate}} +
{{'DATASET-LISTING.TOOLTIP.DMP' | translate}}
+
+ +
{{'DATASET-LISTING.TOOLTIP.DMP-FOR' | translate}}: {{activity.dmp}}
+
+ + + + + + + + + + + + + + + +
+ +
+ + diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-dataset-activity/recent-edited-dataset-activity.component.scss b/dmp-frontend/src/app/ui/dashboard/recent-edited-dataset-activity/recent-edited-dataset-activity.component.scss new file mode 100644 index 000000000..e7c8878da --- /dev/null +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-dataset-activity/recent-edited-dataset-activity.component.scss @@ -0,0 +1,176 @@ +.latest-activity-title { + text-align: left; + font-weight: 300; + font-family: "Roboto", sans-serif; + font-size: 1.25rem; + letter-spacing: 0px; + color: #212121; + opacity: 0.6; + padding-bottom: 1.2rem; +} + +.dmp-card, +.dataset-card { + min-width: 712px; + /* min-height: 308px; */ + background: #ffffff 0% 0% no-repeat padding-box; + box-shadow: 0px 3px 6px #0000001a; + border-radius: 4px; + opacity: 1; + margin-top: 2.43rem; + margin-bottom: 1rem; +} + +.remove-border-bottom ::ng-deep .mat-tab-header { + border-bottom: none; +} + +input[type="text"] { + background: #fafafa 0% 0% no-repeat padding-box; + border: 1px solid #d1d1d1; + border-radius: 4px; + opacity: 1; + width: 347px; + height: 56px; + font-family: Arial, FontAwesome; + padding-left: 15px; +} + +.edited-date { + text-align: left; + font-weight: 300; + font-family: "Roboto", sans-serif; + line-height: 2.4; + letter-spacing: 0px; + color: #212121; + opacity: 0.6; +} + +.dmp-label { + background: #129d99 0% 0% no-repeat padding-box; + border-radius: 4px 0px; + opacity: 1; + width: 67px; + height: 37px; + color: #ffffff; + line-height: 2.4; + opacity: 0.75; +} + +.dataset-label { + width: 158px; + height: 37px; + background: #f7dd72 0% 0% no-repeat padding-box; + border-radius: 4px 0px; + text-align: left; + line-height: 2.8; + font-size: 0.875rem; + letter-spacing: 0px; + color: #212121; + opacity: 0.75; +} + +.dmp-title, +.dataset-title { + text-align: left; + font-weight: 500; + font-family: "Roboto", sans-serif; + font-size: 1rem; + opacity: 0.81; + padding-top: 0.75rem; + padding-bottom: 0.55rem; + color: #212121; +} + +.dataset-subtitle, +.dmp-subtitle { + display: flex; + flex-direction: row; + text-align: left; + font-weight: 400; + font-family: "Roboto", sans-serif; + font-size: 0.875rem; + opacity: 1; + align-items: center; + color: #848484; +} + +.dmp-title-draft { + text-align: left; + font-weight: 500; + font-family: "Roboto", sans-serif; + font-size: 1rem; + opacity: 0.81; + padding-top: 0.75rem; + padding-bottom: 0.55rem; + color: #f16868; +} + +.icon-align { + display: inline-flex; + vertical-align: middle; + padding-bottom: 0.4rem; +} + +.dataset-card-actions, +.dmp-card-actions { + display: flex; + flex-direction: row; + border-top: 1px solid #dbdbdb; + line-height: 4; + color: #848484; +} + +.dataset-card-actions a, +.dmp-card-actions a { + color: #848484 !important; + text-decoration: none !important; +} + +.dataset-card-actions a:hover, +.dmp-card-actions a:hover { + color: #129d99 !important; +} + +.dmp-dataset-descriptions-title { + color: #000000; + opacity: 0.6; + padding-top: 1.5rem; + padding-bottom: 0.8rem; +} + +.dmp-dataset-descriptions-name { + color: #000000; + opacity: 0.6; + font-weight: 700; +} + +.show-more { + color: black !important; +} + +.show-more:hover { + color: #129d99 !important; +} + +.btn-load-more { + border: 2px solid #212121; + border-radius: 30px; + opacity: 1; + width: 132px; + height: 40px; + margin-top: 4.125rem; +} + +.btn-load-more:hover { + background-color: black; + color: white; +} + +.draft { + color: #f16868; +} + +.pointer { + cursor: pointer; +} diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-dataset-activity/recent-edited-dataset-activity.component.ts b/dmp-frontend/src/app/ui/dashboard/recent-edited-dataset-activity/recent-edited-dataset-activity.component.ts new file mode 100644 index 000000000..769780f85 --- /dev/null +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-dataset-activity/recent-edited-dataset-activity.component.ts @@ -0,0 +1,245 @@ +import { Component, OnInit, Output, EventEmitter } from '@angular/core'; +import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { BaseComponent } from '@common/base/base.component'; +import { Principal } from '@app/core/model/auth/principal'; +import { TranslateService } from '@ngx-translate/core'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { FormControl } from '@angular/forms'; +import { DatasetCopyDialogueComponent } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; +import { MatDialog } from '@angular/material'; +import { takeUntil } from 'rxjs/operators'; +import { Router } from '@angular/router'; +import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; +import * as FileSaver from 'file-saver'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { SnackBarNotificationLevel } from '@common/modules/notification/ui-notification-service'; +import { DatasetStatus } from '@app/core/common/enum/dataset-status'; + +@Component({ + selector: 'app-recent-edited-dataset-activity', + templateUrl: './recent-edited-dataset-activity.component.html', + styleUrls: ['./recent-edited-dataset-activity.component.scss'] +}) +export class RecentEditedDatasetActivityComponent extends BaseComponent implements OnInit { + + @Output() totalCountDatasets: EventEmitter = new EventEmitter(); + + datasetActivities: DatasetListingModel[]; + totalCount: number; + startIndex: number = 4; + pageSize: number = 5; + // publicMode = false; + + constructor( + private authentication: AuthService, + private datasetService: DatasetService, + private language: TranslateService, + public enumUtils: EnumUtils, + public dialog: MatDialog, + public router: Router, + private datasetWizardService: DatasetWizardService, + private uiNotificationService: UiNotificationService + ) { + super(); + } + + ngOnInit() { + if (this.isAuthenticated()) { + const fields: Array = ["-modified"]; + const datasetDataTableRequest: DataTableRequest = new DataTableRequest(0, this.pageSize, { fields: fields }); + datasetDataTableRequest.criteria = new DatasetCriteria(); + datasetDataTableRequest.criteria.like = ""; + this.datasetService + .getPaged(datasetDataTableRequest) + .subscribe(response => { + this.datasetActivities = response.data; + this.totalCount = response.totalCount; + this.totalCountDatasets.emit(this.totalCount); + }); + } + } + + public loadMore() { + const fields: Array = ["-modified"]; + const request = new DataTableRequest(this.startIndex, this.pageSize, { fields: fields }); + + request.criteria = new DatasetCriteria(); + request.criteria.like = ""; + + this.datasetService.getPaged(request).pipe(takeUntil(this._destroyed)).subscribe(result => { + if (!result) { return []; } + this.datasetActivities = this.datasetActivities.concat(result.data); + }); + this.startIndex = this.startIndex + this.pageSize; + } + + public isAuthenticated(): boolean { + return !!this.authentication.current(); + } + + roleDisplay(value: any) { + const principal: Principal = this.authentication.current(); + let role: number; + if (principal) { + value.forEach(element => { + if (principal.id === element.id) { + role = element.role; + } + }); + } + if (role === 0) { + return this.language.instant('DMP-LISTING.OWNER'); + } + else if (role === 1) { + return this.language.instant('DMP-LISTING.MEMBER'); + } + else { + return this.language.instant('DMP-LISTING.OWNER'); + } + } + + openDmpSearchDialogue(dataset: DatasetListingModel) { + const formControl = new FormControl(); + const dialogRef = this.dialog.open(DatasetCopyDialogueComponent, { + width: '500px', + restoreFocus: false, + data: { + formControl: formControl, + datasetId: dataset.id, + datasetProfileId: dataset.profile, + datasetProfileExist: false, + confirmButton: this.language.instant('DATASET-WIZARD.DIALOGUE.COPY'), + cancelButton: this.language.instant('DATASET-WIZARD.DIALOGUE.CANCEL') + } + }); + + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)) + .subscribe(result => { + if (result && result.datasetProfileExist) { + const newDmpId = result.formControl.value.id + this.router.navigate(['/datasets/copy/' + result.datasetId], { queryParams: { newDmpId: newDmpId } }); + } + }); + } + + openConfirm(id: string): void { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + maxWidth: '300px', + restoreFocus: false, + data: { + message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), + confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.DELETE'), + cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), + isDeleteConfirmation: true + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + this.datasetWizardService.delete(id) + .pipe(takeUntil(this._destroyed)) + .subscribe( + complete => this.onCallbackSuccess(), + error => this.onCallbackError(error) + ); + } + }); + } + + getFilenameFromContentDispositionHeader(header: string): string { + const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g); + + const matches = header.match(regex); + let filename: string; + for (let i = 0; i < matches.length; i++) { + const match = matches[i]; + if (match.includes('filename="')) { + filename = match.substring(10, match.length - 1); + break; + } else if (match.includes('filename=')) { + filename = match.substring(9); + break; + } + } + return filename; + } + + downloadPDF(dataset: DatasetListingModel): void { + this.datasetWizardService.downloadPDF(dataset.id as string) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/pdf' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + FileSaver.saveAs(blob, filename); + }); + } + + downloadDOCX(dataset: DatasetListingModel): void { + this.datasetWizardService.downloadDOCX(dataset.id as string) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/msword' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + FileSaver.saveAs(blob, filename); + }); + + } + + downloadXML(dataset: DatasetListingModel): void { + this.datasetWizardService.downloadXML(dataset.id as string) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/xml' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + FileSaver.saveAs(blob, filename); + }); + } + + onCallbackSuccess(id?: String): void { + this.uiNotificationService.snackBarNotification(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) { + this.setErrorModel(error.error); + } + + openUpdateDatasetProfileDialogue(id: string) { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + restoreFocus: false, + data: { + message: this.language.instant('DATASET-EDITOR.VERSION-DIALOG.QUESTION'), + confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'), + cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), + isDeleteConfirmation: false + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.SUCCESS-UPDATE-DATASET-PROFILE'), SnackBarNotificationLevel.Success); + this.router.navigate(['/datasets/profileupdate/' + id]); + } + }); + } + + public setErrorModel(validationErrorModel: ValidationErrorModel) { + } + + needsUpdate(activity: DatasetListingModel) { + if (activity.isProfileLatestVersion || (activity.status === DatasetStatus.Finalized) + || (activity.isProfileLatestVersion == undefined && activity.status == undefined)) { + return false; + } + else { + return true; + } + } +} diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.css b/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.css new file mode 100644 index 000000000..c2ce5bb3c --- /dev/null +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.css @@ -0,0 +1,243 @@ +.latest-activity-title { + text-align: left; + font-weight: 300; + font-family: "Roboto", sans-serif; + font-size: 1.25rem; + letter-spacing: 0px; + color: #212121; + opacity: 0.6; + padding-bottom: 1.2rem; +} + +.dmp-card, +.dataset-card { + min-width: 712px; + /* min-height: 308px; */ + background: #ffffff 0% 0% no-repeat padding-box; + box-shadow: 0px 3px 6px #0000001a; + border-radius: 4px; + opacity: 1; + margin-top: 2.43rem; + margin-bottom: 1rem; +} + +.remove-border-bottom ::ng-deep .mat-tab-header { + border-bottom: none; +} + +input[type="text"] { + background: #fafafa 0% 0% no-repeat padding-box; + border: 1px solid #d1d1d1; + border-radius: 4px; + opacity: 1; + width: 347px; + height: 56px; + font-family: Arial, FontAwesome; + padding-left: 15px; +} + +.edited-date { + text-align: left; + font-weight: 300; + font-family: "Roboto", sans-serif; + line-height: 2.4; + letter-spacing: 0px; + color: #212121; + opacity: 0.6; +} + +.dmp-label { + background: #129d99 0% 0% no-repeat padding-box; + border-radius: 4px 0px; + opacity: 1; + width: 67px; + height: 37px; + color: #ffffff; + line-height: 2.4; + opacity: 0.75; +} + +.dataset-label { + width: 158px; + height: 37px; + background: #f7dd72 0% 0% no-repeat padding-box; + border-radius: 4px 0px; + text-align: left; + line-height: 2.8; + font-size: 0.875rem; + letter-spacing: 0px; + color: #212121; + opacity: 0.75; +} + +.dmp-title, +.dataset-title { + text-align: left; + font-weight: 500; + font-family: "Roboto", sans-serif; + font-size: 1rem; + opacity: 0.81; + padding-top: 0.75rem; + padding-bottom: 0.55rem; + color: #212121; +} + +.dataset-subtitle, +.dmp-subtitle { + display: flex; + flex-direction: row; + text-align: left; + font-weight: 400; + font-family: "Roboto", sans-serif; + font-size: 0.875rem; + opacity: 1; + align-items: center; + color: #848484; +} + +.dmp-title-draft { + text-align: left; + font-weight: 500; + font-family: "Roboto", sans-serif; + font-size: 1rem; + opacity: 0.81; + padding-top: 0.75rem; + padding-bottom: 0.55rem; + color: #f16868; +} + +.icon-align { + display: inline-flex; + vertical-align: middle; + padding-bottom: 0.4rem; +} + +.dataset-card-actions, +.dmp-card-actions { + display: flex; + flex-direction: row; + border-top: 1px solid #dbdbdb; + line-height: 4; + color: #848484; +} + +.dataset-card-actions a, +.dmp-card-actions a { + color: #848484 !important; + text-decoration: none !important; +} + +.dataset-card-actions a:hover, +.dmp-card-actions a:hover { + color: #129d99 !important; +} + +.dmp-dataset-descriptions-title { + color: #000000; + opacity: 0.6; + padding-top: 1.5rem; + padding-bottom: 0.8rem; +} + +.dmp-dataset-descriptions-name { + color: #000000; + opacity: 0.6; + font-weight: 700; +} + +.show-more { + color: black !important; +} + +.show-more:hover { + color: #129d99 !important; +} + +.btn-load-more { + border: 2px solid #212121; + border-radius: 30px; + opacity: 1; + width: 132px; + height: 40px; + margin-top: 4.125rem; +} + +.btn-load-more:hover { + background-color: black; + color: white; +} + +.draft { + color: #f16868; +} + +.pointer { + cursor: pointer; +} + +/* th { + text-transform: uppercase; +} + +a { + color: #212529; +} + +.table-row { + cursor: pointer; + display: table-row; +} + +.is-public { + padding-left: 5px; + padding-right: 5px; + border: 1px solid #00b29f3b; + color: #00b29f; + background-color: #00b29f0f; + border-radius: 10em; + text-align: center; +} + +.template-name { + padding-left: 0.5em; + border: 1px solid rgb(218, 227, 243); + color: rgb(43, 104, 209); + background-color: rgb(236, 241, 249); + border-radius: 10em; + text-align: center; + max-width: 160px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.chip { + padding: 0.1em 1em; + margin-bottom: 1em; + margin-left: 2.5em; + margin-right: 2.5em; + border-radius: 10em; + background-color: #0d7489; + color: #fff; + text-transform: uppercase; + text-align: center; + font-weight: 500; + max-width: 160px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.mat-icon-button :hover { + color: rgb(120, 173, 220); +} + +.view-all { + margin-left: auto; + margin-bottom: 0px !important; + color: #6aa4d9; +} + +.view-all:hover { + color: rgb(46, 117, 182) !important; +} */ diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.html b/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.html new file mode 100644 index 000000000..76973f33e --- /dev/null +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.html @@ -0,0 +1,208 @@ +
+
+ +
+
+
+
{{ 'DMP-LISTING.DMP' | translate }}
+
{{ 'DMP-LISTING.EDITED' | translate }}: {{ activity.modifiedTime | date: "longDate" }}
+
+
{{activity.label}}
+
+ {{ roleDisplay(activity.users) }} + . + public{{'TYPES.DMP-VISIBILITY.PUBLIC' | translate}} + done{{ enumUtils.toDmpStatusString(activity.status) }} + create{{ enumUtils.toDmpStatusString(activity.status) }} + . + {{'DMP-LISTING.VERSION' | translate}} {{activity.version}} + . + {{ 'DMP-LISTING.GRANT' | translate }}: {{activity.grant}} +
+
{{'DMP-LISTING.CONTAINED-DATASETS' | translate}}: ({{activity.datasets.length}}) +
+
+
+
{{dataset.label}},
+
{{dataset.label}}
+
+
+ {{'GENERAL.ACTIONS.SHOW-MORE' | translate}} +
+ + + + + + + + + + + + + +
+
+
+ +
+
+ + + + + + + diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.ts b/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.ts new file mode 100644 index 000000000..7cc18c095 --- /dev/null +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.ts @@ -0,0 +1,328 @@ +import { Component, OnInit, Output, EventEmitter } from '@angular/core'; +import { MatDialog } from '@angular/material'; +import { Router } from '@angular/router'; +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 * as FileSaver from 'file-saver'; +import { takeUntil } from 'rxjs/operators'; +import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation.component'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing'; +import { Role } from '@app/core/common/enum/role'; + +@Component({ + selector: 'app-recent-edited-dmp-activity', + templateUrl: './recent-edited-dmp-activity.component.html', + styleUrls: ['./recent-edited-dmp-activity.component.css'] +}) +export class RecentEditedDmpActivityComponent extends BaseComponent implements OnInit { + + @Output() totalCountDmps: EventEmitter = new EventEmitter(); + + dmpActivities: DmpListingModel[]; + datasetActivities: DatasetListingModel[]; + // allRecentActivities: RecentActivity[] = []; + recentActivityTypeEnum = RecentActivityType; + isDraft: boolean; + + totalCount: number; + startIndex: number = 4; + pageSize: number = 5; + + constructor( + private router: Router, + public enumUtils: EnumUtils, + private authentication: AuthService, + private dmpService: DmpService, + private datasetService: DatasetService, + private language: TranslateService, + private dialog: MatDialog, + private uiNotificationService: UiNotificationService + ) { + super(); + } + + ngOnInit() { + if (this.isAuthenticated()) { + const fields: Array = ["-modified"]; + const dmpDataTableRequest: DataTableRequest = new DataTableRequest(0, 5, { fields: fields }); + dmpDataTableRequest.criteria = new DmpCriteria(); + dmpDataTableRequest.criteria.like = ""; + this.dmpService + .getPaged(dmpDataTableRequest, "listing") + .subscribe(response => { + this.dmpActivities = response.data; + this.totalCount = response.totalCount; + this.totalCountDmps.emit(this.totalCount); + // this.dmpActivities.forEach(dmpActivity => { + // const recentActivity: RecentActivity = { + // activityData: dmpActivity, + // activityType: RecentActivityType.Dmp + // }; + // this.allRecentActivities.push(recentActivity) + // }) + }); + + // const datasetDataTableRequest: DataTableRequest = new DataTableRequest(0, 5, { fields: fields }); + // datasetDataTableRequest.criteria = new DatasetCriteria(); + // datasetDataTableRequest.criteria.like = ""; + // this.datasetService + // .getPaged(datasetDataTableRequest) + // .subscribe(response => { + // this.datasetActivities = response.data; + // this.datasetActivities.forEach(datasetActivity => { + // const recentActivity: RecentActivity = { + // activityData: datasetActivity, + // activityType: RecentActivityType.Dataset + // }; + // this.allRecentActivities.push(recentActivity) + // }) + // }); + } + } + + public isAuthenticated(): boolean { + return !!this.authentication.current(); + } + + isUserOwner(activity: DmpListingModel): boolean { + const principal: Principal = this.authentication.current(); + if (principal) return principal.id === activity.users.find(x => x.role === Role.Owner).id; + } + + editClicked(dmp: DmpListingModel) { + this.router.navigate(['/plans/edit/' + dmp.id]); + } + + cloneClicked(dmp: DmpListingModel) { + this.router.navigate(['/plans/clone/' + dmp.id]); + } + + deleteClicked(dmp: DmpListingModel) { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + maxWidth: '300px', + restoreFocus: false, + data: { + message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), + confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.DELETE'), + cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), + isDeleteConfirmation: true + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + this.dmpService.delete(dmp.id) + .pipe(takeUntil(this._destroyed)) + .subscribe( + complete => { this.onCallbackSuccess() }, + error => this.onDeleteCallbackError(error) + ); + } + }); + } + + openShareDialog(rowId: any, rowName: any) { + const dialogRef = this.dialog.open(DmpInvitationDialogComponent, { + // height: '250px', + // width: '700px', + restoreFocus: false, + data: { + dmpId: rowId, + dmpName: rowName + } + }); + } + + isDraftDmp(activity: DmpListingModel) { + return activity.status == DmpStatus.Draft; + } + + onCallbackSuccess(): void { + this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); + this.router.navigate(['/plans']); + } + + onDeleteCallbackError(error) { + this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error); + } + + redirect(id: string, type: RecentActivityType) { + switch (type) { + case RecentActivityType.Grant: { + this.router.navigate(["grants/edit/" + id]); + return; + } + case RecentActivityType.Dataset: { + this.router.navigate(["datasets/edit/" + id]); + return; + } + case RecentActivityType.Dmp: { + this.router.navigate(["plans/overview/" + id]); + return; + } + default: + throw new Error("Unsupported Activity Type "); + } + } + + // navigateToUrl() { + // this.router.navigate(["plans/"]); + // } + + roleDisplay(value: any) { + const principal: Principal = this.authentication.current(); + let role: number; + if (principal) { + value.forEach(element => { + if (principal.id === element.id) { + role = element.role; + } + }); + } + if (role === 0) { + return this.language.instant('DMP-LISTING.OWNER'); + } + else if (role === 1) { + return this.language.instant('DMP-LISTING.MEMBER'); + } + else { + return this.language.instant('DMP-LISTING.OWNER'); + } + } + + // dmpProfileDisplay(value: any) { + // if (value != null) { + // return value; + // } + // else { + // return "--"; + // } + // } + + downloadXml(id: string) { + this.dmpService.downloadXML(id) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/xml' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + FileSaver.saveAs(blob, filename); + }); + } + + downloadDocx(id: string) { + this.dmpService.downloadDocx(id) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/msword' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + FileSaver.saveAs(blob, filename); + }); + } + + downloadPDF(id: string) { + this.dmpService.downloadPDF(id) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/pdf' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + FileSaver.saveAs(blob, filename); + }); + } + + downloadJson(id: string) { + this.dmpService.downloadJson(id) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/json' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + FileSaver.saveAs(blob, filename); + }) + } + + getFilenameFromContentDispositionHeader(header: string): string { + const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g); + + const matches = header.match(regex); + let filename: string; + for (let i = 0; i < matches.length; i++) { + const match = matches[i]; + if (match.includes('filename="')) { + filename = match.substring(10, match.length - 1); + break; + } else if (match.includes('filename=')) { + filename = match.substring(9); + break; + } + } + return filename; + } + + addDataset(activityId: String) { + this.router.navigate(['/datasets/new/' + activityId]); + } + + newVersion(id: String, label: String) { + this.router.navigate(['/plans/new_version/' + id, { dmpLabel: label }]); + } + + viewVersions(rowId: String, rowLabel: String, activity: DmpListingModel) { + if (activity.public && !this.isUserOwner) { + this.router.navigate(['/explore-plans/versions/' + rowId], { queryParams: { groupLabel: rowLabel } }); + } else { + this.router.navigate(['/plans/versions/' + rowId], { queryParams: { groupLabel: rowLabel } }); + } + } + + public loadMore() { + const fields: Array = ["-modified"]; + const request = new DataTableRequest(this.startIndex, this.pageSize, { fields: fields }); + + request.criteria = new DmpCriteria(); + request.criteria.like = ""; + + this.dmpService.getPaged(request, "listing").pipe(takeUntil(this._destroyed)).subscribe(result => { + if (!result) { return []; } + this.dmpActivities = this.dmpActivities.concat(result.data); + }); + this.startIndex = this.startIndex + this.pageSize; + } + + // advancedClicked(dmp: DmpListingModel) { + // const dialogRef = this.dialog.open(ExportMethodDialogComponent, { + // maxWidth: '500px', + // data: { + // message: "Download as:", + // XMLButton: "XML", + // documentButton: "Document", + // pdfButton: "PDF", + // jsonButton: "JSON" + + // } + // }); + // dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + // if (result == "pdf") { + // this.downloadPDF(dmp.id); + // } else if (result == "xml") { + // this.downloadXml(dmp.id); + // } else if (result == "doc") { + // this.downloadDocx(dmp.id); + // } else if (result == "json") { + // this.downloadJson(dmp.id) + // } + // }); + // } +} diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.module.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.module.ts new file mode 100644 index 000000000..8c2094b8f --- /dev/null +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { CommonUiModule } from '@common/ui/common-ui.module'; + +import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { DatasetCopyDialogueComponent } from './dataset-copy-dialogue.component'; + +@NgModule({ + imports: [ + CommonUiModule, + CommonFormsModule, + AutoCompleteModule + ], + declarations: [ + DatasetCopyDialogueComponent + ], + entryComponents: [ + DatasetCopyDialogueComponent + ] +}) +export class DatasetCopyDialogModule { } diff --git a/dmp-frontend/src/app/ui/dataset/dataset.module.ts b/dmp-frontend/src/app/ui/dataset/dataset.module.ts index 5a7900993..804bb64ae 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset.module.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset.module.ts @@ -2,7 +2,6 @@ import { NgModule } from '@angular/core'; import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.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'; @@ -23,6 +22,7 @@ import { FormValidationErrorsDialogModule } from '@common/forms/form-validation- 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'; +import { DatasetCopyDialogModule } from './dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.module'; @NgModule({ imports: [ @@ -37,7 +37,8 @@ import { AngularStickyThingsModule } from '@w11k/angular-sticky-things'; TableOfContentsModule, AngularStickyThingsModule, DatasetRoutingModule, - FormValidationErrorsDialogModule + FormValidationErrorsDialogModule, + DatasetCopyDialogModule ], declarations: [ DatasetListingComponent, @@ -49,7 +50,6 @@ import { AngularStickyThingsModule } from '@w11k/angular-sticky-things'; DatasetExternalDatasetDialogEditorComponent, DatasetExternalRegistryDialogEditorComponent, DatasetExternalServiceDialogEditorComponent, - DatasetCopyDialogueComponent, DatasetUploadDialogue, DatasetListingItemComponent ], @@ -58,7 +58,6 @@ import { AngularStickyThingsModule } from '@w11k/angular-sticky-things'; DatasetExternalDatasetDialogEditorComponent, DatasetExternalRegistryDialogEditorComponent, DatasetExternalServiceDialogEditorComponent, - DatasetCopyDialogueComponent, DatasetUploadDialogue ] }) 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 34acb8049..58ccae56c 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 @@ -62,7 +62,6 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread } ngOnInit() { - console.log(this.router.url); this.isPublic = this.router.url.startsWith('/explore-plans'); if (!this.isPublic && isNullOrUndefined(this.authService.current())) { this.router.navigateByUrl("/explore-plans"); diff --git a/dmp-frontend/src/app/ui/grant/listing/criteria/grant-criteria.component.html b/dmp-frontend/src/app/ui/grant/listing/criteria/grant-criteria.component.html index 6449d06f1..526b7d5d0 100644 --- a/dmp-frontend/src/app/ui/grant/listing/criteria/grant-criteria.component.html +++ b/dmp-frontend/src/app/ui/grant/listing/criteria/grant-criteria.component.html @@ -20,10 +20,8 @@ {{'GENERAL.VALIDATION.GRANT-START-AFTER-END' | translate}} - - - + {{ 'CRITERIA.GRANTS.TYPES.NONE' | translate}} diff --git a/dmp-frontend/src/app/ui/guest/guest.component.ts b/dmp-frontend/src/app/ui/guest/guest.component.ts index 08dc66cb3..461cae13f 100644 --- a/dmp-frontend/src/app/ui/guest/guest.component.ts +++ b/dmp-frontend/src/app/ui/guest/guest.component.ts @@ -54,7 +54,6 @@ export class GuestComponent implements OnInit { const dialogRef = this.dialog.open(SignInDialogComponent); dialogRef.afterClosed().subscribe(result => { - console.log(`Dialog result: ${result}`); }); } diff --git a/dmp-frontend/src/app/ui/navbar/navbar.component.html b/dmp-frontend/src/app/ui/navbar/navbar.component.html index 62e765002..a815836d1 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.component.html +++ b/dmp-frontend/src/app/ui/navbar/navbar.component.html @@ -20,7 +20,7 @@ - +