diff --git a/src/main/java/de/tudresden/inf/verdatas/xapitools/dave/dashboards/DaveDashboardService.java b/src/main/java/de/tudresden/inf/verdatas/xapitools/dave/dashboards/DaveDashboardService.java index 7e12b33..09c3ab4 100644 --- a/src/main/java/de/tudresden/inf/verdatas/xapitools/dave/dashboards/DaveDashboardService.java +++ b/src/main/java/de/tudresden/inf/verdatas/xapitools/dave/dashboards/DaveDashboardService.java @@ -18,6 +18,7 @@ import java.util.*; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -268,28 +269,64 @@ public void cleanCaches() { } /** - * Request all activities of the given LRS and save them in a cache + * Request all activities of the given LRS and save them in a cache. + * Has to request the activities' IDs and Types with separate queries because the query's result will be empty, if an activity type is not given for a single activity in the dataset * * @param connection {@link LrsConnection} to use - * @return {@link List} of IDs of LRS' activities + * @return {@link Map} with activity types as keys and IDs of the corresponding activities in a {@link List} */ @Cacheable( cacheNames = "lrsActivities", key = "#connection.connectionId" ) - public List getActivitiesOfLrs(LrsConnection connection) { - DaveVis getActivities = this.prepareGetActivitiesOfLRS(); - List activities = this.daveConnectorLifecycleManager.getConnector(connection) + public Map> getActivitiesOfLrs(LrsConnection connection) { + List allActivities = getActivities(connection); + Map> activitiesByType = getActivitiesByType(connection); + List activitiesWithKnownType = activitiesByType.values().stream().flatMap(List::stream).toList(); + List activitiesWithUnknownType = allActivities.stream() + .filter((activity) -> !(activitiesWithKnownType.contains(activity))) + .toList(); + if (!activitiesWithUnknownType.isEmpty()) { + activitiesByType.put("unknown", activitiesWithUnknownType); + } + return activitiesByType; + } + + private List getActivities(LrsConnection connection) { + DaveVis getActivities = this.prepareGetActivitiesOfLRS(false); + List activityList = this.daveConnectorLifecycleManager.getConnector(connection) .getAnalysisResult(this.fileManagementService.prepareQuery(getActivities, "all").getAbsolutePath(), this.fileManagementService.prepareVisualisation(getActivities).getAbsolutePath()); - return activities.stream() + return activityList.stream() .map((s) -> s.replace("\n", "")) .map((s) -> s.substring(1, s.length() - 1)) - .map((s) -> s.split(" +")[1]) .map((s) -> s.replace("\"", "")) + .map((s) -> s.split(" +")[1]) .toList(); } + private Map> getActivitiesByType(LrsConnection connection) { + DaveVis getActivitiesType = this.prepareGetActivitiesOfLRS(true); + List activitiesWithType = this.daveConnectorLifecycleManager.getConnector(connection) + .getAnalysisResult(this.fileManagementService.prepareQuery(getActivitiesType, "all").getAbsolutePath(), + this.fileManagementService.prepareVisualisation(getActivitiesType).getAbsolutePath()); + return activitiesWithType.stream() + .map((s) -> s.replace("\n", "")) + .map((s) -> s.substring(1, s.length() - 1)) + .map((s) -> s.replace("\"", "")) + .map((s) -> s.split(" +")) + .map((sarr) -> Pair.of(sarr[1], sarr[2])) + .collect( + Collectors.groupingBy( + Pair::getSecond, + Collectors.collectingAndThen( + Collectors.toList(), + (list) -> list.stream().map(Pair::getFirst).toList() + ) + ) + ); + } + /** * Add an Analysis to an existing Dashboard description * @@ -398,11 +435,12 @@ public String getNameOfAnalysis(UUID analysisId) { /** * Helper function to create Analysis for requesting the Activities of an LRS. * Must not be deleted or modified and is therefore not seeded like the predefined analyses + * + * @param withType indicates if Activities' type should also be requested */ - public DaveVis prepareGetActivitiesOfLRS() { - return new DaveVis("Activities of LRS", - new DaveQuery("Activities of LRS", """ - [:find (count ?s) ?c :where [?s :statement/object ?o][?o :activity/id ?c]]"""), + public DaveVis prepareGetActivitiesOfLRS(Boolean withType) { + DaveVis analysis = new DaveVis("Activities of LRS", + new DaveQuery("Activities of LRS", ""), new DaveGraphDescription("Top 10", """ { @@ -484,6 +522,14 @@ public DaveVis prepareGetActivitiesOfLRS() { } ] }"""), true); + if (withType) { + analysis.setQuery(new DaveQuery("Activities of LRS", """ + [:find (count ?s) ?c ?t :where [?s :statement/object ?o][?o :activity/id ?c][?o :activity.definition/type ?t]]""")); + } else { + analysis.setQuery(new DaveQuery("Activities of LRS", """ + [:find (count ?s) ?c :where [?s :statement/object ?o][?o :activity/id ?c]]""")); + } + return analysis; } /** diff --git a/src/main/java/de/tudresden/inf/verdatas/xapitools/dave/dashboards/controllers/VisualisationsSettingFlowController.java b/src/main/java/de/tudresden/inf/verdatas/xapitools/dave/dashboards/controllers/VisualisationsSettingFlowController.java index 35a53b9..b9b6616 100644 --- a/src/main/java/de/tudresden/inf/verdatas/xapitools/dave/dashboards/controllers/VisualisationsSettingFlowController.java +++ b/src/main/java/de/tudresden/inf/verdatas/xapitools/dave/dashboards/controllers/VisualisationsSettingFlowController.java @@ -1,5 +1,6 @@ package de.tudresden.inf.verdatas.xapitools.dave.dashboards.controllers; +import com.google.common.base.Supplier; import de.tudresden.inf.verdatas.xapitools.dave.dashboards.DaveDashboardService; import de.tudresden.inf.verdatas.xapitools.dave.persistence.DaveDashboard; import de.tudresden.inf.verdatas.xapitools.dave.persistence.DaveVis; @@ -7,6 +8,7 @@ import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import org.springframework.core.annotation.Order; +import org.springframework.data.util.Pair; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -15,10 +17,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springframework.web.servlet.view.RedirectView; -import java.util.Comparator; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -68,18 +67,37 @@ public ModelAndView showSelectAnalysis(@RequestParam(name = "flow") UUID dashboa if (!cache.orElse(true)) this.daveDashboardService.cleanCaches(); DaveDashboard dashboard = this.daveDashboardService.getDashboard(dashboardId); LrsConnection lrsConnection = dashboard.getLrsConnection(); - List activities = this.daveDashboardService.getActivitiesOfLrs(lrsConnection) + Map> activitiesByType = this.daveDashboardService.getActivitiesOfLrs(lrsConnection) + .entrySet() .stream() - .sorted(Comparator.naturalOrder()) - .collect(Collectors.toList()); - + .map((entry) -> Map.entry( + Arrays.stream(entry.getKey().split("/")) + .reduce((acc, s) -> s) + .orElse(entry.getKey()), + entry.getValue() + .stream() + .sorted() + .collect(Collectors.toList()) + )) + .collect( + Collectors.groupingBy( + Map.Entry::getKey, + Collectors.collectingAndThen(Collectors.toList(), + (entries) -> entries.stream().map(Map.Entry::getValue).flatMap(List::stream).toList() + ) + ) + ); + + Map activityToType = new HashMap<>(); + activitiesByType.forEach((key, value) -> value.forEach((activity) -> activityToType.put(activity, key))); ModelAndView mav = new ModelAndView("bootstrap/dave/dashboard/analysis"); mav.addObject("flow", dashboardId.toString()); - mav.addObject("possibleActivities", activities); + mav.addObject("possibleActivities", activitiesByType); mav.addObject("possibleAnalysis", this.daveDashboardService.getAllAnalysis(true) .sorted(Comparator.comparing(DaveVis::getName)) .toList()); mav.addObject("dashboardVisualisations", this.daveDashboardService.getVisualisationsOfDashboard(dashboard)); + mav.addObject("activityTypes", activityToType); mav.addObject("mode", DaveDashboardMavController.Mode.CREATING); return mav; } @@ -121,7 +139,6 @@ public RedirectView addVisualisationToDashboard(@RequestParam(name = "flow") UUI UUID analysisIdentifier = analysis.getId(); this.daveDashboardService.addVisualisationToDashboard(dashboard, activityId, analysisIdentifier); - return new RedirectView(DaveDashboardMavController.Mode.CREATING.equals(mode) ? "../visualisations" : "../../edit/visualisations"); } diff --git a/src/main/resources/templates/bootstrap/dave/dashboard/analysis.html b/src/main/resources/templates/bootstrap/dave/dashboard/analysis.html index 10b7242..eaca33a 100644 --- a/src/main/resources/templates/bootstrap/dave/dashboard/analysis.html +++ b/src/main/resources/templates/bootstrap/dave/dashboard/analysis.html @@ -14,9 +14,10 @@