Skip to content

Commit 7ded6cf

Browse files
dee077pandafynemesifier
committed
[feature] Allowed showing moving devices in dashboard map #664
- Added the possibility to show changes to the position of moving nodes in realtime - Improved loading overlay and other UX details Closes #664 --------- Co-authored-by: Gagan Deep <pandafy.dev@gmail.com> Co-authored-by: Federico Capoano <f.capoano@openwisp.io>
1 parent 73b2324 commit 7ded6cf

File tree

17 files changed

+350
-210
lines changed

17 files changed

+350
-210
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,6 @@ jobs:
8585
pip install -r requirements-test.txt
8686
pip install -U -I -e .
8787
pip uninstall -y Django
88-
# TODO: Remove before merging - install branch build of openwisp-utils for CI testing
89-
pip install -U -I "openwisp-utils @ https://github.com/openwisp/openwisp-utils/tarball/gsoc25-map-adjustments"
9088
pip install -U ${{ matrix.django-version }}
9189
sudo npm install -g prettier
9290

openwisp_monitoring/device/admin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,8 @@ def patch_device_location_inline(self):
649649
js=(
650650
"admin/js/jquery.init.js",
651651
"monitoring/js/location-inline.js",
652-
)
652+
),
653+
css={"all": ("monitoring/css/monitoring.css",)},
653654
)
654655
return base + extra
655656

openwisp_monitoring/device/migrations/0010_map.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ class Migration(migrations.Migration):
1717
options={
1818
"abstract": False,
1919
"proxy": True,
20-
"swappable": "DEVICE_MONITORING_MAP_MODEL",
2120
"indexes": [],
2221
"constraints": [],
2322
},

openwisp_monitoring/device/models.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,3 @@ class Map(BaseLocation):
4343
class Meta:
4444
proxy = True
4545
abstract = False
46-
swappable = swappable_setting("device_monitoring", "Map")

openwisp_monitoring/device/static/monitoring/css/device-map.css

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,22 @@
2727
font-weight: bold;
2828
text-transform: uppercase;
2929
}
30-
#device-map-container {
31-
height: 430px;
32-
width: 90%;
33-
margin: 30px auto 0px auto;
30+
#dashboard-map-overlay {
3431
position: relative;
35-
border: 1px solid rgba(0, 0, 0, 0.3);
3632
}
37-
#device-map-container .ow-loading-spinner {
33+
#dashboard-map-overlay .ow-loading-spinner {
3834
position: absolute;
3935
z-index: 9999;
4036
top: 41%;
4137
left: 49%;
4238
}
39+
#device-map-container {
40+
height: 430px;
41+
width: 90%;
42+
margin: 30px auto 0px auto;
43+
position: relative;
44+
border: 1px solid rgba(0, 0, 0, 0.3);
45+
}
4346
#device-map-container .leaflet-interactive:focus {
4447
outline: none;
4548
}
@@ -230,6 +233,7 @@
230233
min-height: 375px;
231234
}
232235
#floorplan-container {
236+
position: relative;
233237
background: white;
234238
z-index: 99999;
235239
padding: 16px;
@@ -270,6 +274,12 @@
270274
height: 100%;
271275
flex: 1;
272276
}
277+
.floorplan-loading-spinner {
278+
position: absolute;
279+
top: 40%;
280+
left: 50%;
281+
z-index: 1000;
282+
}
273283
.floor-content {
274284
width: 100%;
275285
height: 100%;
@@ -401,3 +411,10 @@
401411
min-width: auto;
402412
}
403413
}
414+
415+
/* Map Page */
416+
.dedicated-map-page {
417+
width: 100%;
418+
height: 87.7vh !important;
419+
margin: 15px auto 0 auto !important;
420+
}
5.4 KB
Loading

openwisp_monitoring/device/static/monitoring/css/monitoring.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,12 @@ ul.tabs .charts > .current,
130130
ul.tabs .status > .current {
131131
background-color: var(--body-bg);
132132
}
133+
134+
/* Device Location Inline */
135+
fieldset.module.aligned .form-row.view-on-map-div {
136+
display: block;
137+
}
138+
fieldset.module .view-on-map-btn {
139+
color: white;
140+
text-decoration: none !important;
141+
}

openwisp_monitoring/device/static/monitoring/js/device-map.js

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use strict";
22

33
(function ($) {
4-
const loadingOverlay = $("#device-map-container .ow-loading-spinner");
4+
const loadingOverlay = $("#dashboard-map-overlay .ow-loading-spinner");
55
const localStorageKey = "ow-map-shown";
66
const mapContainer = $("#device-map-container");
77
const statuses = ["critical", "problem", "ok", "unknown", "deactivated"];
@@ -51,6 +51,7 @@
5151
};
5252

5353
let currentPopup = null;
54+
let currentPopupLocationId = null;
5455

5556
const loadPopUpContent = function (nodeData, netjsongraphInstance, url) {
5657
loadingOverlay.show();
@@ -61,7 +62,6 @@
6162
if (currentPopup) {
6263
currentPopup.remove();
6364
}
64-
loadingOverlay.show();
6565

6666
$.ajax({
6767
dataType: "json",
@@ -137,6 +137,7 @@
137137
</div>
138138
`;
139139

140+
currentPopupLocationId = locationId;
140141
currentPopup = L.popup({
141142
autoPan: true,
142143
autoPanPadding: [25, 25],
@@ -262,6 +263,8 @@
262263
el.find(".leaflet-popup-close-button").on("click", function () {
263264
const id = netjsongraphInstance.config.bookmarkableActions.id;
264265
netjsongraphInstance.utils.removeUrlFragment(id);
266+
currentPopup = null;
267+
currentPopupLocationId = null;
265268
});
266269
loadingOverlay.hide();
267270
},
@@ -554,7 +557,7 @@
554557
}
555558
const option = map.echarts.getOption();
556559
const series = option.series.find(
557-
(s) => s.type === "scatter" || "effectScatter",
560+
(s) => s.type === "scatter" || s.type === "effectScatter",
558561
);
559562
const seriesIndex = option.series.indexOf(series);
560563

@@ -573,6 +576,7 @@
573576
},
574577
});
575578
map.render();
579+
listenForLocationUpdates(map);
576580
window._owGeoMap = map;
577581
}
578582

@@ -588,4 +592,24 @@
588592
success: onAjaxSuccess,
589593
context: window,
590594
});
595+
function listenForLocationUpdates(map) {
596+
if (!map) {
597+
return;
598+
}
599+
var host = window.location.host,
600+
protocol = window.location.protocol === "http:" ? "ws" : "wss",
601+
ws = new ReconnectingWebSocket(protocol + "://" + host + "/ws/loci/location/");
602+
ws.onmessage = function (e) {
603+
const data = JSON.parse(e.data);
604+
const [lng, lat] = data.geometry.coordinates;
605+
if (currentPopup && data.id === currentPopupLocationId) {
606+
$(".leaflet-popup").hide();
607+
}
608+
map.utils.moveNodeInRealTime(data.id, { lng, lat });
609+
if (currentPopup && data.id === currentPopupLocationId) {
610+
currentPopup.setLatLng([lat, lng]);
611+
$(".leaflet-popup").show();
612+
}
613+
};
614+
}
591615
})(django.jQuery);

openwisp_monitoring/device/static/monitoring/js/floorplan.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
(function ($) {
44
const status_colors = window._owGeoMapConfig.STATUS_COLORS;
5-
65
let allResults = {};
76
let floors = [];
87
let currentFloor = null;
@@ -13,7 +12,6 @@
1312
let maps = {};
1413
let locationId = null;
1514
let popstateHandler = null;
16-
1715
// Use case: we support overlaying two maps. The URL hash contains up to two
1816
// fragments separated by ';' — one is the geo map and the other is an indoor map.
1917
//
@@ -90,10 +88,8 @@
9088
const $floorNavigation = createFloorNavigation();
9189

9290
$(".menu-backdrop").addClass("active");
93-
9491
$("#dashboard-map-overlay").append($floorPlanContainer);
9592
$("#floorplan-overlay").append($floorNavigation);
96-
9793
$("#floorplan-close-btn").on("click", closeButtonHandler);
9894
addFloorButtons(selectedIndex, navWindowStart);
9995
addNavigationHandlers(url);
@@ -201,7 +197,6 @@
201197

202198
$(".left-arrow").toggleClass("disabled", selectedIndex === 0);
203199
$(".right-arrow").toggleClass("disabled", selectedIndex === floors.length - 1);
204-
205200
$(".floor-btn").removeClass("active selected");
206201
$('.floor-btn[data-index="' + selectedIndex + '"]').addClass("active selected");
207202
}
@@ -212,6 +207,7 @@
212207

213208
$nav.off("click");
214209
$nav.on("click", ".floor-btn", async (e) => {
210+
$(".floorplan-loading-spinner").show();
215211
selectedIndex = +e.currentTarget.dataset.index;
216212
const center = Math.floor(NAV_WINDOW_SIZE / 2);
217213
navWindowStart = Math.max(0, Math.min(selectedIndex - center, maxStart));
@@ -222,6 +218,7 @@
222218
});
223219

224220
$nav.on("click", ".right-arrow:not(.disabled)", async () => {
221+
$(".floorplan-loading-spinner").show();
225222
if (selectedIndex < floors.length - 1) {
226223
selectedIndex++;
227224
const center = Math.floor(NAV_WINDOW_SIZE / 2);
@@ -234,6 +231,7 @@
234231
});
235232

236233
$nav.on("click", ".left-arrow:not(.disabled)", async () => {
234+
$(".floorplan-loading-spinner").show();
237235
if (selectedIndex > 0) {
238236
selectedIndex--;
239237
const center = Math.floor(NAV_WINDOW_SIZE / 2);
@@ -252,7 +250,6 @@
252250
.filter(`[data-floor="${floor}"]`)
253251
.addClass("active selected");
254252

255-
$(".floorplan-loading-spinner").hide();
256253
await fetchData(url, floor);
257254

258255
const nodesThisFloor = { nodes: allResults[floor], links: [] };
@@ -437,6 +434,7 @@
437434
map.setMaxBounds(bnds.pad(1));
438435
initialZoom = map.getZoom();
439436
map.invalidateSize();
437+
$(".floorplan-loading-spinner").hide();
440438

441439
map.on("fullscreenchange", () => {
442440
const floorNavigation = $("#floorplan-navigation");

openwisp_monitoring/device/static/monitoring/js/lib/netjsongraph.min.js

Lines changed: 2 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)