From 2ea1f40c0cb43b9134998f2d12f976014b0f0624 Mon Sep 17 00:00:00 2001 From: Charl Smit Date: Tue, 7 Nov 2023 12:34:16 +0200 Subject: [PATCH 1/9] Allow manual group allocation --- .../static/geospatial/js/case_grouping_map.js | 171 +++++++++++++----- .../templates/case_grouping_map.html | 17 +- 2 files changed, 141 insertions(+), 47 deletions(-) diff --git a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js index d0de4cec807b..fbfb309763c4 100644 --- a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js +++ b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js @@ -22,8 +22,8 @@ hqDefine("geospatial/js/case_grouping_map",[ let map; const clusterStatsInstance = new clusterStatsModel(); let exportModelInstance; - let groupLockModelInstance = new groupLockModel() - let caseGroupsInstance = new caseGroupSelectModel() + let groupLockModelInstance = new groupLockModel(); + let caseGroupsInstance = new caseGroupSelectModel(); let mapMarkers = []; function caseModel(caseId, coordinates, caseLink) { @@ -102,17 +102,26 @@ hqDefine("geospatial/js/case_grouping_map",[ hiddenElement.remove(); }; - self.addGroupsToCases = function(caseGroups) { - clearCaseGroups(); + self.addGroupDataToCases = function(caseGroups, groupsData) { self.casesToExport().forEach(caseItem => { - const groupData = caseGroups[caseItem.caseId]; - if (groupData !== undefined) { - caseItem.groupId = groupData.groupId; - caseItem.groupCoordinates = groupData.groupCoordinates; + const groupId = caseGroups[caseItem.caseId]; + if (groupId !== undefined) { + const group = groupsData.find((group) => {return group.groupId === groupId}); + self.setItemGroup(caseItem, groupId, group.coordinates); } }); } + self.setItemGroup = function(item, groupId, groupCoordinates) { + item.groupId = groupId; + item.groupCoordinates = groupCoordinates; + } + + self.updateCaseGroup = function(itemId, groupData) { + var item = self.casesToExport().find((caseItem) => {return caseItem.caseId == itemId}); + self.setItemGroup(item, groupData.groupId, groupData.coordinates); + } + self.clearCaseGroups = function() { self.casesToExport().forEach(caseItem => { if (caseItem.groupId) { @@ -306,7 +315,40 @@ hqDefine("geospatial/js/case_grouping_map",[ return `rgba(${r},${g},${b},${DEFAULT_MARKER_OPACITY})`; } - function collapseGroupsOnMap() { + function mapMarkerModel(itemId, itemData, marker, markerColors) { + 'use strict'; + var self = {}; + self.itemId = itemId; + self.itemData = itemData; + self.marker = marker; + self.selectCssId = "select" + itemId; + self.isSelected = ko.observable(false); + self.markerColors = markerColors; + + self.groupsOptions = ko.observable(caseGroupsInstance.allGroups()); + self.selectedGroup = ko.observable(itemData.groupId); + + self.updateGroup = ko.computed(function () { + caseGroupsInstance.updateCaseGroup(self.itemId, self.selectedGroup()); + const newGroup = caseGroupsInstance.getGroupByID(self.selectedGroup()); + if (newGroup) { + changeMarkerColor(self, newGroup.color); + exportModelInstance.updateCaseGroup(self.itemId, newGroup); + } + }); + + function changeMarkerColor(selectedCase, newColor) { + let marker = selectedCase.marker; + let element = marker.getElement(); + let svg = element.getElementsByTagName("svg")[0]; + let path = svg.getElementsByTagName("path")[0]; + path.setAttribute("fill", newColor); + } + + return self; + } + + function revealGroupsOnMap() { setMapLayersVisibility(MAPBOX_LAYER_VISIBILITY.None); mapMarkers.forEach((marker) => marker.remove()); mapMarkers = []; @@ -320,11 +362,44 @@ hqDefine("geospatial/js/case_grouping_map",[ let caseGroup = caseGroupsInstance.getGroupByID(caseGroupID); color = caseGroup.color; const marker = new mapboxgl.Marker({ color: color, draggable: false }); // eslint-disable-line no-undef - marker.setLngLat([caseItem.coordinates.lng, caseItem.coordinates.lat]); + + const coordinates = [caseItem.coordinates.lng, caseItem.coordinates.lat]; + marker.setLngLat(coordinates); // Add the marker to the map marker.addTo(map); mapMarkers.push(marker); + + let popupDiv = document.createElement("div"); + popupDiv.setAttribute("data-bind", "template: 'select-case'"); + + let popup = new mapboxgl.Popup({ offset: 25, anchor: "bottom" }) // eslint-disable-line no-undef + .setLngLat(coordinates) + .setDOMContent(popupDiv); + + marker.setPopup(popup); + + const markerDiv = marker.getElement(); + // Show popup on hover + markerDiv.addEventListener('mouseenter', () => marker.togglePopup()); + + // Hide popup if mouse leaves marker and popup + var addLeaveEvent = function (fromDiv, toDiv) { + fromDiv.addEventListener('mouseleave', function () { + setTimeout(function () { + if (!$(toDiv).is(':hover')) { + // mouse left toDiv as well + marker.togglePopup(); + } + }, 100); + }); + }; + addLeaveEvent(markerDiv, popupDiv); + addLeaveEvent(popupDiv, markerDiv); + const colors = {default: color, selected: color}; + + const mapMarkerInstance = new mapMarkerModel(caseItem.caseId, caseItem, marker, colors); + $(popupDiv).koApplyBindings(mapMarkerInstance); } }); } @@ -350,26 +425,19 @@ hqDefine("geospatial/js/case_grouping_map",[ }; self.getGroupByID = function(groupID) { - return self.allGroups().find((group) => group.groupID === groupID); + return self.allGroups().find((group) => group.groupId === groupID); }; - self.loadCaseGroups = function(caseGroups) { - self.allCaseGroups = caseGroups; - // Add groups to the cases being exported - - let groupIds = []; - for (let caseID in caseGroups) { - let caseItem = caseGroups[caseID]; - groupIds.push(caseItem.groupId); - } - - new Set(groupIds).forEach(id => self.allGroups.push( - {groupID: id, color: getRandomRGBColor()} - )); + self.updateCaseGroup = function(itemId, newGroupId) { + self.allCaseGroups[itemId] = newGroupId; + }; - let visibleIDs = _.map(self.allGroups(), function(group) {return group.groupID}); + self.loadCaseGroups = function(caseGroups, groups) { + self.allCaseGroups = caseGroups; + self.allGroups(groups); + let visibleIDs = _.map(self.allGroups(), function(group) {return group.groupId}); self.visibleGroupIDs(visibleIDs); - self.showAllGroups() + self.showAllGroups(); }; self.clear = function() { @@ -385,7 +453,7 @@ hqDefine("geospatial/js/case_grouping_map",[ self.highlightGroup = function(group) { exportModelInstance.casesToExport().forEach(caseItem => { - let caseIsInGroup = caseItem.groupId === group.groupID; + let caseIsInGroup = caseItem.groupId === group.groupId; let opacity = DEFAULT_MARKER_OPACITY if (!caseIsInGroup) { opacity = 0.2; @@ -419,18 +487,16 @@ hqDefine("geospatial/js/case_grouping_map",[ filteredCaseGroups[caseID] = self.allCaseGroups[caseID]; } } - exportModelInstance.addGroupsToCases(filteredCaseGroups); - collapseGroupsOnMap(); + exportModelInstance.addGroupDataToCases(filteredCaseGroups, self.allGroups()); + revealGroupsOnMap(); }; self.showAllGroups = function() { if (!self.allCaseGroups) { return; } - exportModelInstance.addGroupsToCases(self.allCaseGroups); - self.visibleGroupIDs(_.map(self.allGroups(), function(group) {return group.groupID})); - collapseGroupsOnMap(); - + self.visibleGroupIDs(_.map(self.allGroups(), function(group) {return group.groupId})); + revealGroupsOnMap(); }; return self; } @@ -441,30 +507,45 @@ hqDefine("geospatial/js/case_grouping_map",[ filter: ['==', 'cluster', true], }); const clusterSource = map.getSource('caseWithGPS'); - let caseGroups = {}; + let caseGroups = {}; // e.g. {: } let failedClustersCount = 0; - processedCluster = {} + processedCluster = {}; + + var groupCount = 1; + var groups = []; for (const cluster of sourceFeatures) { const clusterId = cluster.properties.cluster_id; - if (!processedCluster[clusterId]) { + if (processedCluster[clusterId] == undefined) { processedCluster[clusterId] = true; } + else { + continue; + } const pointCount = cluster.properties.point_count; try { const casePoints = await getClusterLeavesAsync(clusterSource, clusterId, pointCount); const groupUUID = uuidv4(); - for (const casePoint of casePoints) { - const caseId = casePoint.properties.id; - caseGroups[caseId] = { + + if (casePoints.length > 0) { + groupName = "Group " + groupCount; + groupCount += 1; + groups.push({ + name: groupName, groupId: groupUUID, - groupCoordinates: { + color: getRandomRGBColor(), + coordinates: { lng: cluster.geometry.coordinates[0], lat: cluster.geometry.coordinates[1], - }, - }; + } + }); + + for (const casePoint of casePoints) { + const caseId = casePoint.properties.id; + caseGroups[caseId] = groupUUID; + } } } catch (error) { failedClustersCount += 1; @@ -476,14 +557,15 @@ hqDefine("geospatial/js/case_grouping_map",[ }); alertUser.alert_user(message, 'danger'); } - - caseGroupsInstance.loadCaseGroups(caseGroups); + exportModelInstance.addGroupDataToCases(caseGroups, groups); + caseGroupsInstance.loadCaseGroups(caseGroups, groups); } function clearCaseGroups() { setMapLayersVisibility(MAPBOX_LAYER_VISIBILITY.Visible); mapMarkers.forEach((marker) => marker.remove()); mapMarkers = []; + caseGroupsInstance.clear(); exportModelInstance.clearCaseGroups(); } @@ -502,7 +584,6 @@ hqDefine("geospatial/js/case_grouping_map",[ } else { map.scrollZoom.enable(); clearCaseGroups(); - caseGroupsInstance.clear(); } }; return self; diff --git a/corehq/apps/geospatial/templates/case_grouping_map.html b/corehq/apps/geospatial/templates/case_grouping_map.html index 2240eed5e513..66250c380e90 100644 --- a/corehq/apps/geospatial/templates/case_grouping_map.html +++ b/corehq/apps/geospatial/templates/case_grouping_map.html @@ -76,8 +76,8 @@
@@ -101,4 +101,17 @@ + + + {% endblock %} From 218e536003b64cd2dbb4901456f232d26bb47590 Mon Sep 17 00:00:00 2001 From: Charl Smit Date: Wed, 8 Nov 2023 13:21:48 +0200 Subject: [PATCH 2/9] Show group color on table and refactor a little --- .../static/geospatial/js/case_grouping_map.js | 30 ++++++++++++++----- .../templates/case_grouping_map.html | 3 +- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js index fbfb309763c4..0428a38609e7 100644 --- a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js +++ b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js @@ -18,6 +18,14 @@ hqDefine("geospatial/js/case_grouping_map",[ }; const DEFAULT_MARKER_OPACITY = 1.0; + const OBSCURING_OPACITY = 0.2; + const DEFAULT_GROUP_ID = "unassigned-group-id"; + const DEFAULT_GROUP = { + groupId: DEFAULT_GROUP_ID, + name: gettext("No group"), + color: `rgba(128,128,128,${OBSCURING_OPACITY})`, + } + const MAP_CONTAINER_ID = 'case-grouping-map'; let map; const clusterStatsInstance = new clusterStatsModel(); @@ -70,7 +78,7 @@ hqDefine("geospatial/js/case_grouping_map",[ // Only cases with belonging to groups should be exported let exportableCases = self.casesToExport().filter(function(caseItem) { - return caseItem.groupId; + return caseItem.groupId !== DEFAULT_GROUP_ID; }); if (!exportableCases.length) { @@ -102,12 +110,16 @@ hqDefine("geospatial/js/case_grouping_map",[ hiddenElement.remove(); }; - self.addGroupDataToCases = function(caseGroups, groupsData) { + self.addGroupDataToCases = function(caseGroups, groupsData, assignDefaultGroup) { + const defaultGroup = groupsData[0]; + self.casesToExport().forEach(caseItem => { const groupId = caseGroups[caseItem.caseId]; if (groupId !== undefined) { const group = groupsData.find((group) => {return group.groupId === groupId}); self.setItemGroup(caseItem, groupId, group.coordinates); + } else if (assignDefaultGroup) { + self.setItemGroup(caseItem, defaultGroup.groupId, {}); } }); } @@ -352,7 +364,6 @@ hqDefine("geospatial/js/case_grouping_map",[ setMapLayersVisibility(MAPBOX_LAYER_VISIBILITY.None); mapMarkers.forEach((marker) => marker.remove()); mapMarkers = []; - exportModelInstance.casesToExport().forEach(function (caseItem) { if (!caseItem.coordinates) { return; @@ -456,7 +467,7 @@ hqDefine("geospatial/js/case_grouping_map",[ let caseIsInGroup = caseItem.groupId === group.groupId; let opacity = DEFAULT_MARKER_OPACITY if (!caseIsInGroup) { - opacity = 0.2; + opacity = OBSCURING_OPACITY; } let marker = mapMarkers.find((marker) => { let markerCoordinates = marker.getLngLat(); @@ -483,7 +494,7 @@ hqDefine("geospatial/js/case_grouping_map",[ let filteredCaseGroups = {}; for (const caseID in self.allCaseGroups) { - if (self.groupIDInVisibleGroupIds(self.allCaseGroups[caseID].groupId)) { + if (self.groupIDInVisibleGroupIds(self.allCaseGroups[caseID])) { filteredCaseGroups[caseID] = self.allCaseGroups[caseID]; } } @@ -512,7 +523,7 @@ hqDefine("geospatial/js/case_grouping_map",[ processedCluster = {}; var groupCount = 1; - var groups = []; + var groups = [DEFAULT_GROUP]; for (const cluster of sourceFeatures) { const clusterId = cluster.properties.cluster_id; @@ -530,8 +541,11 @@ hqDefine("geospatial/js/case_grouping_map",[ const groupUUID = uuidv4(); if (casePoints.length > 0) { - groupName = "Group " + groupCount; + groupName = _.template(gettext("Group <%- groupCount %>"))({ + groupCount: groupCount, + }); groupCount += 1; + groups.push({ name: groupName, groupId: groupUUID, @@ -557,7 +571,7 @@ hqDefine("geospatial/js/case_grouping_map",[ }); alertUser.alert_user(message, 'danger'); } - exportModelInstance.addGroupDataToCases(caseGroups, groups); + exportModelInstance.addGroupDataToCases(caseGroups, groups, true); caseGroupsInstance.loadCaseGroups(caseGroups, groups); } diff --git a/corehq/apps/geospatial/templates/case_grouping_map.html b/corehq/apps/geospatial/templates/case_grouping_map.html index 66250c380e90..b00d411680e9 100644 --- a/corehq/apps/geospatial/templates/case_grouping_map.html +++ b/corehq/apps/geospatial/templates/case_grouping_map.html @@ -77,7 +77,8 @@
From 8394b93aa3e61859dc3c1284d4229933d95f3efc Mon Sep 17 00:00:00 2001 From: Charl Smit Date: Fri, 10 Nov 2023 09:01:40 +0200 Subject: [PATCH 3/9] Decouple groups table data from generated groups --- .../static/geospatial/js/case_grouping_map.js | 32 ++++++++++++------- .../templates/case_grouping_map.html | 2 +- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js index 0428a38609e7..89a0caf0e962 100644 --- a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js +++ b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js @@ -112,7 +112,6 @@ hqDefine("geospatial/js/case_grouping_map",[ self.addGroupDataToCases = function(caseGroups, groupsData, assignDefaultGroup) { const defaultGroup = groupsData[0]; - self.casesToExport().forEach(caseItem => { const groupId = caseGroups[caseItem.caseId]; if (groupId !== undefined) { @@ -337,7 +336,7 @@ hqDefine("geospatial/js/case_grouping_map",[ self.isSelected = ko.observable(false); self.markerColors = markerColors; - self.groupsOptions = ko.observable(caseGroupsInstance.allGroups()); + self.groupsOptions = ko.observable(caseGroupsInstance.allGroups); self.selectedGroup = ko.observable(itemData.groupId); self.updateGroup = ko.computed(function () { @@ -426,8 +425,11 @@ hqDefine("geospatial/js/case_grouping_map",[ 'use strict'; var self = {}; - self.allGroups = ko.observableArray([]); self.allCaseGroups; + // allGroups and caseGroupsForTable contains the same data, but there's weird knockoutjs behaviour + // if we're making allGroups an observable. caseGroupsForTable is populated by setCaseGroupsForTable + self.allGroups = []; + self.caseGroupsForTable = ko.observableArray([]); self.visibleGroupIDs = ko.observableArray([]); self.casePerGroup = {}; @@ -436,7 +438,7 @@ hqDefine("geospatial/js/case_grouping_map",[ }; self.getGroupByID = function(groupID) { - return self.allGroups().find((group) => group.groupId === groupID); + return self.allGroups.find((group) => group.groupId === groupID); }; self.updateCaseGroup = function(itemId, newGroupId) { @@ -445,14 +447,14 @@ hqDefine("geospatial/js/case_grouping_map",[ self.loadCaseGroups = function(caseGroups, groups) { self.allCaseGroups = caseGroups; - self.allGroups(groups); - let visibleIDs = _.map(self.allGroups(), function(group) {return group.groupId}); - self.visibleGroupIDs(visibleIDs); + self.allGroups = groups; + self.showAllGroups(); }; self.clear = function() { - self.allGroups([]); + self.allGroups = []; + self.caseGroupsForTable([]); self.visibleGroupIDs([]); }; @@ -478,7 +480,7 @@ hqDefine("geospatial/js/case_grouping_map",[ }); if (marker) { setMarkerOpacity(marker, opacity); - } + } }); }; @@ -498,7 +500,7 @@ hqDefine("geospatial/js/case_grouping_map",[ filteredCaseGroups[caseID] = self.allCaseGroups[caseID]; } } - exportModelInstance.addGroupDataToCases(filteredCaseGroups, self.allGroups()); + exportModelInstance.addGroupDataToCases(filteredCaseGroups, self.allGroups); revealGroupsOnMap(); }; @@ -506,9 +508,15 @@ hqDefine("geospatial/js/case_grouping_map",[ if (!self.allCaseGroups) { return; } - self.visibleGroupIDs(_.map(self.allGroups(), function(group) {return group.groupId})); + self.visibleGroupIDs(_.map(self.allGroups, function(group) {return group.groupId})); revealGroupsOnMap(); + self.setCaseGroupsForTable(); }; + + self.setCaseGroupsForTable = function() { + self.caseGroupsForTable(self.allGroups); + } + return self; } @@ -555,8 +563,8 @@ hqDefine("geospatial/js/case_grouping_map",[ lat: cluster.geometry.coordinates[1], } }); - for (const casePoint of casePoints) { + console.log("Hitting case and adding to group"); const caseId = casePoint.properties.id; caseGroups[caseId] = groupUUID; } diff --git a/corehq/apps/geospatial/templates/case_grouping_map.html b/corehq/apps/geospatial/templates/case_grouping_map.html index b00d411680e9..43faa650da5f 100644 --- a/corehq/apps/geospatial/templates/case_grouping_map.html +++ b/corehq/apps/geospatial/templates/case_grouping_map.html @@ -71,7 +71,7 @@ {% trans "Select Case Groups to View" %} - +
From e1a11f4e7bdc34f7b2941ee69839a06deb830bc7 Mon Sep 17 00:00:00 2001 From: Charl Smit Date: Fri, 10 Nov 2023 09:22:39 +0200 Subject: [PATCH 4/9] Disable grouping actions when groups are not loaded --- .../geospatial/static/geospatial/js/case_grouping_map.js | 9 +++++++++ corehq/apps/geospatial/templates/case_grouping_map.html | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js index 89a0caf0e962..a819c12beb6c 100644 --- a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js +++ b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js @@ -141,6 +141,11 @@ hqDefine("geospatial/js/case_grouping_map",[ } }); } + + self.groupsReady = function() { + return groupLockModelInstance.groupsLocked(); + } + return self; } @@ -517,6 +522,10 @@ hqDefine("geospatial/js/case_grouping_map",[ self.caseGroupsForTable(self.allGroups); } + self.groupsReady = function() { + return groupLockModelInstance.groupsLocked() && self.caseGroupsForTable().length; + }; + return self; } diff --git a/corehq/apps/geospatial/templates/case_grouping_map.html b/corehq/apps/geospatial/templates/case_grouping_map.html index 43faa650da5f..fd63a23d06b5 100644 --- a/corehq/apps/geospatial/templates/case_grouping_map.html +++ b/corehq/apps/geospatial/templates/case_grouping_map.html @@ -22,7 +22,7 @@
-
@@ -88,12 +88,12 @@
-
-
From ce88c07aa751ef5d7977081256f4e5d4045f89ca Mon Sep 17 00:00:00 2001 From: Charl Smit Date: Fri, 10 Nov 2023 10:42:08 +0200 Subject: [PATCH 5/9] Adjust styling of popup --- .../static/geospatial/js/case_grouping_map.js | 1 - .../apps/geospatial/templates/case_grouping_map.html | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js index a819c12beb6c..8258e8b10cd0 100644 --- a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js +++ b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js @@ -573,7 +573,6 @@ hqDefine("geospatial/js/case_grouping_map",[ } }); for (const casePoint of casePoints) { - console.log("Hitting case and adding to group"); const caseId = casePoint.properties.id; caseGroups[caseId] = groupUUID; } diff --git a/corehq/apps/geospatial/templates/case_grouping_map.html b/corehq/apps/geospatial/templates/case_grouping_map.html index fd63a23d06b5..db62c9704753 100644 --- a/corehq/apps/geospatial/templates/case_grouping_map.html +++ b/corehq/apps/geospatial/templates/case_grouping_map.html @@ -104,13 +104,11 @@
From 566c2f83da9dd69f495b24bfcf1c56b4718b7116 Mon Sep 17 00:00:00 2001 From: Charl Smit Date: Fri, 10 Nov 2023 11:12:37 +0200 Subject: [PATCH 6/9] Fix linting --- .../apps/geospatial/static/geospatial/js/case_grouping_map.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js index 8258e8b10cd0..f78ffcca2789 100644 --- a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js +++ b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js @@ -291,7 +291,7 @@ hqDefine("geospatial/js/case_grouping_map",[ "type": "Point", "coordinates": [coordinates.lng, coordinates.lat], }, - }, + } ); } }); @@ -422,7 +422,7 @@ hqDefine("geospatial/js/case_grouping_map",[ function uuidv4() { // https://stackoverflow.com/questions/105034/how-do-i-create-a-guid-uuid/2117523#2117523 return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c => - (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16), + (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) ); } From 1f79cf5f35397123ac60fcd3ff6052c354cc65c5 Mon Sep 17 00:00:00 2001 From: Charl Smit Date: Fri, 10 Nov 2023 17:02:28 +0200 Subject: [PATCH 7/9] Replace indexing with find operation --- .../apps/geospatial/static/geospatial/js/case_grouping_map.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js index f78ffcca2789..f6a2a5b57e4f 100644 --- a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js +++ b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js @@ -111,7 +111,7 @@ hqDefine("geospatial/js/case_grouping_map",[ }; self.addGroupDataToCases = function(caseGroups, groupsData, assignDefaultGroup) { - const defaultGroup = groupsData[0]; + const defaultGroup = groupsData.find((group) => {return group.groupId === DEFAULT_GROUP_ID}); self.casesToExport().forEach(caseItem => { const groupId = caseGroups[caseItem.caseId]; if (groupId !== undefined) { From ee64cca0eb4486504f3de2a4169fbb6cf8acd9d2 Mon Sep 17 00:00:00 2001 From: Charl Smit Date: Mon, 13 Nov 2023 16:58:27 +0200 Subject: [PATCH 8/9] Small refactors --- .../static/geospatial/js/case_grouping_map.js | 41 ++++++++++--------- .../templates/case_grouping_map.html | 2 +- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js index 604dae89a6a5..f19a4eabff3a 100644 --- a/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js +++ b/corehq/apps/geospatial/static/geospatial/js/case_grouping_map.js @@ -221,6 +221,7 @@ hqDefine("geospatial/js/case_grouping_map",[ function mapMarkerModel(itemId, itemData, marker, markerColors) { 'use strict'; var self = {}; + self.title = gettext("Select group"); self.itemId = itemId; self.itemData = itemData; self.marker = marker; @@ -228,7 +229,7 @@ hqDefine("geospatial/js/case_grouping_map",[ self.isSelected = ko.observable(false); self.markerColors = markerColors; - self.groupsOptions = ko.observable(caseGroupsInstance.allGroups); + self.groupsOptions = ko.observable(caseGroupsInstance.generatedGroups); self.selectedGroup = ko.observable(itemData.groupId); self.updateGroup = ko.computed(function () { @@ -312,10 +313,10 @@ hqDefine("geospatial/js/case_grouping_map",[ 'use strict'; var self = {}; - self.allCaseGroups; - // allGroups and caseGroupsForTable contains the same data, but there's weird knockoutjs behaviour - // if we're making allGroups an observable. caseGroupsForTable is populated by setCaseGroupsForTable - self.allGroups = []; + self.groupsByCase; + // generatedGroups and caseGroupsForTable contains the same data, but there's weird knockoutjs behaviour + // if we're making generatedGroups an observable. caseGroupsForTable is populated by setCaseGroupsForTable + self.generatedGroups = []; self.caseGroupsForTable = ko.observableArray([]); self.visibleGroupIDs = ko.observableArray([]); self.casePerGroup = {}; @@ -325,22 +326,22 @@ hqDefine("geospatial/js/case_grouping_map",[ }; self.getGroupByID = function(groupID) { - return self.allGroups.find((group) => group.groupId === groupID); + return self.generatedGroups.find((group) => group.groupId === groupID); }; self.updateCaseGroup = function(itemId, newGroupId) { - self.allCaseGroups[itemId] = newGroupId; + self.groupsByCase[itemId] = newGroupId; }; self.loadCaseGroups = function(caseGroups, groups) { - self.allCaseGroups = caseGroups; - self.allGroups = groups; + self.groupsByCase = caseGroups; + self.generatedGroups = groups; self.showAllGroups(); }; self.clear = function() { - self.allGroups = []; + self.generatedGroups = []; self.caseGroupsForTable([]); self.visibleGroupIDs([]); }; @@ -377,31 +378,31 @@ hqDefine("geospatial/js/case_grouping_map",[ }; self.showSelectedGroups = function() { - if (!self.allCaseGroups) { + if (!self.groupsByCase) { return; } let filteredCaseGroups = {}; - for (const caseID in self.allCaseGroups) { - if (self.groupIDInVisibleGroupIds(self.allCaseGroups[caseID])) { - filteredCaseGroups[caseID] = self.allCaseGroups[caseID]; + for (const caseID in self.groupsByCase) { + if (self.groupIDInVisibleGroupIds(self.groupsByCase[caseID])) { + filteredCaseGroups[caseID] = self.groupsByCase[caseID]; } } - exportModelInstance.addGroupDataToCases(filteredCaseGroups, self.allGroups); + exportModelInstance.addGroupDataToCases(filteredCaseGroups, self.generatedGroups); revealGroupsOnMap(); }; self.showAllGroups = function() { - if (!self.allCaseGroups) { + if (!self.groupsByCase) { return; } - self.visibleGroupIDs(_.map(self.allGroups, function(group) {return group.groupId})); + self.visibleGroupIDs(_.map(self.generatedGroups, function(group) {return group.groupId})); revealGroupsOnMap(); self.setCaseGroupsForTable(); }; self.setCaseGroupsForTable = function() { - self.caseGroupsForTable(self.allGroups); + self.caseGroupsForTable(self.generatedGroups); } self.groupsReady = function() { @@ -426,7 +427,7 @@ hqDefine("geospatial/js/case_grouping_map",[ for (const cluster of sourceFeatures) { const clusterId = cluster.properties.cluster_id; - if (processedCluster[clusterId] == undefined) { + if (processedCluster[clusterId] === undefined) { processedCluster[clusterId] = true; } else { @@ -439,7 +440,7 @@ hqDefine("geospatial/js/case_grouping_map",[ const casePoints = await getClusterLeavesAsync(clusterSource, clusterId, pointCount); const groupUUID = utils.uuidv4(); - if (casePoints.length > 0) { + if (casePoints.length) { groupName = _.template(gettext("Group <%- groupCount %>"))({ groupCount: groupCount, }); diff --git a/corehq/apps/geospatial/templates/case_grouping_map.html b/corehq/apps/geospatial/templates/case_grouping_map.html index 4ef144aa11f3..e2c285b2b1fd 100644 --- a/corehq/apps/geospatial/templates/case_grouping_map.html +++ b/corehq/apps/geospatial/templates/case_grouping_map.html @@ -129,7 +129,7 @@