diff --git a/webapp/frontend/package-lock.json b/webapp/frontend/package-lock.json
index a935e34..ca56358 100644
--- a/webapp/frontend/package-lock.json
+++ b/webapp/frontend/package-lock.json
@@ -9,7 +9,6 @@
"version": "0.0.0",
"dependencies": {
"@tailwindcss/vite": "^4.1.4",
- "@vueuse/core": "^13.1.0",
"axios": "^1.8.4",
"chart.js": "^4.4.8",
"chartjs-adapter-moment": "^1.0.1",
@@ -1741,12 +1740,6 @@
"@types/geojson": "*"
}
},
- "node_modules/@types/web-bluetooth": {
- "version": "0.0.21",
- "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
- "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
- "license": "MIT"
- },
"node_modules/@vitejs/plugin-vue": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.3.tgz",
@@ -1981,44 +1974,6 @@
"integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==",
"license": "MIT"
},
- "node_modules/@vueuse/core": {
- "version": "13.1.0",
- "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.1.0.tgz",
- "integrity": "sha512-PAauvdRXZvTWXtGLg8cPUFjiZEddTqmogdwYpnn60t08AA5a8Q4hZokBnpTOnVNqySlFlTcRYIC8OqreV4hv3Q==",
- "license": "MIT",
- "dependencies": {
- "@types/web-bluetooth": "^0.0.21",
- "@vueuse/metadata": "13.1.0",
- "@vueuse/shared": "13.1.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- },
- "peerDependencies": {
- "vue": "^3.5.0"
- }
- },
- "node_modules/@vueuse/metadata": {
- "version": "13.1.0",
- "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.1.0.tgz",
- "integrity": "sha512-+TDd7/a78jale5YbHX9KHW3cEDav1lz1JptwDvep2zSG8XjCsVE+9mHIzjTOaPbHUAk5XiE4jXLz51/tS+aKQw==",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- }
- },
- "node_modules/@vueuse/shared": {
- "version": "13.1.0",
- "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.1.0.tgz",
- "integrity": "sha512-IVS/qRRjhPTZ6C2/AM3jieqXACGwFZwWTdw5sNTSKk2m/ZpkuuN+ri+WCVUP8TqaKwJYt/KuMwmXspMAw8E6ew==",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- },
- "peerDependencies": {
- "vue": "^3.5.0"
- }
- },
"node_modules/acorn": {
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
diff --git a/webapp/frontend/package.json b/webapp/frontend/package.json
index 7465a0e..c032b51 100644
--- a/webapp/frontend/package.json
+++ b/webapp/frontend/package.json
@@ -10,7 +10,6 @@
},
"dependencies": {
"@tailwindcss/vite": "^4.1.4",
- "@vueuse/core": "^13.1.0",
"axios": "^1.8.4",
"chart.js": "^4.4.8",
"chartjs-adapter-moment": "^1.0.1",
diff --git a/webapp/frontend/src/components/Announcement.vue b/webapp/frontend/src/components/Announcement.vue
index d9a044d..5eab64d 100644
--- a/webapp/frontend/src/components/Announcement.vue
+++ b/webapp/frontend/src/components/Announcement.vue
@@ -1,11 +1,13 @@
diff --git a/webapp/frontend/src/components/NodeInfo/Traceroutes.vue b/webapp/frontend/src/components/NodeInfo/Traceroutes.vue
index abda406..ec5c4bc 100644
--- a/webapp/frontend/src/components/NodeInfo/Traceroutes.vue
+++ b/webapp/frontend/src/components/NodeInfo/Traceroutes.vue
@@ -1,7 +1,7 @@
diff --git a/webapp/frontend/src/composables/useNodeProcessor.js b/webapp/frontend/src/composables/useNodeProcessor.js
index 3bda542..2abf9e5 100644
--- a/webapp/frontend/src/composables/useNodeProcessor.js
+++ b/webapp/frontend/src/composables/useNodeProcessor.js
@@ -1,11 +1,12 @@
import { useMapStore } from '@/stores/mapStore';
import moment from 'moment';
-import { nodesMaxAge, nodesOfflineAge } from '@/config'; // TODO: use config store
+import { useConfigStore } from '@/stores/configStore';
import { icons } from '@/map';
import { hasNodeUplinkedToMqttRecently, isValidCoordinates } from '@/utils';
export function useNodeProcessor() {
- const mapStore = useMapStore(); // Access your mapStore from Pinia
+ const mapStore = useMapStore();
+ const config = useConfigStore();
// This function processes new node data
const processNewNodes = (newNodes) => {
@@ -15,9 +16,9 @@ export function useNodeProcessor() {
for (const node of newNodes) {
// Skip nodes older than configured node max age
- if (nodesMaxAge.value) {
+ if (config.nodesMaxAge !== null) {
const lastUpdatedAgeInMillis = now.diff(moment(node.updated_at));
- if (lastUpdatedAgeInMillis > nodesMaxAge.value * 1000) {
+ if (lastUpdatedAgeInMillis > config.nodesMaxAge * 1000) {
continue;
}
}
@@ -42,9 +43,9 @@ export function useNodeProcessor() {
let icon = icons.mqttDisconnected;
// Use offline icon for nodes older than configured node offline age
- if (nodesOfflineAge.value) {
+ if (config.nodesOfflineAge !== null) {
const lastUpdatedAgeInMillis = now.diff(moment(node.updated_at));
- if (lastUpdatedAgeInMillis > nodesOfflineAge.value * 1000) {
+ if (lastUpdatedAgeInMillis > config.nodesOfflineAge * 1000) {
icon = icons.offline;
}
}
diff --git a/webapp/frontend/src/config.js b/webapp/frontend/src/config.js
index 60d2bef..dd6a1aa 100644
--- a/webapp/frontend/src/config.js
+++ b/webapp/frontend/src/config.js
@@ -1,27 +1,3 @@
-import { useStorage } from '@vueuse/core';
-
// static
export const CURRENT_ANNOUNCEMENT_ID = 1;
-export const BASE_PATH = 'http://localhost:9090';
-
-// boolean
-export const autoUpdatePositionInUrl = useStorage('auto-update-url', true);
-export const enableMapAnimations = useStorage('map-animations', true);
-export const hasSeenInfoModal = useStorage('seen-info-modal', false);
-// time in seconds
-export const nodesMaxAge = useStorage('nodes-max-age', null);
-export const nodesDisconnectedAge = useStorage('nodes-max-disconnected-age', 604800);
-export const nodesOfflineAge = useStorage('nodes-offline-age', null);
-export const waypointsMaxAge = useStorage('waypoints-max-age', 604800);
-// number
-export const goToNodeZoomLevel = useStorage('zoom-to-node', 15);
-export const lastSeenAnnouncementId = useStorage('last-seen-announcement-id', 1);
-// distance in meters
-export const neighboursMaxDistance = useStorage('neighbors-distance', null);
-// device info ranges
-export const deviceMetricsTimeRange = useStorage('device-metrics-range', '3d');
-export const powerMetricsTimeRange = useStorage('power-metrics-range', '3d');
-export const environmentMetricsTimeRange = useStorage('environment-metrics-range', '3d');
-// map config
-export const enabledOverlayLayers = useStorage('enabled-overlay-layers', ['Legend', 'Position History']);
-export const selectedTileLayerName = useStorage('selected-tile-layer', 'OpenStreetMap');
\ No newline at end of file
+export const BASE_PATH = 'http://localhost:9090';
\ No newline at end of file
diff --git a/webapp/frontend/src/stores/configStore.js b/webapp/frontend/src/stores/configStore.js
index 2065020..cc0e816 100644
--- a/webapp/frontend/src/stores/configStore.js
+++ b/webapp/frontend/src/stores/configStore.js
@@ -21,7 +21,7 @@ export const useConfigStore = defineStore('config', {
lastSeenAnnouncementId: 1,
// Distance values (for max distances)
- neighboursMaxDistance: null,
+ neighborsMaxDistance: null,
// Device info ranges (can be persisted)
deviceMetricsTimeRange: '3d',
diff --git a/webapp/frontend/src/views/HomeView.vue b/webapp/frontend/src/views/HomeView.vue
index dca596c..a906de7 100644
--- a/webapp/frontend/src/views/HomeView.vue
+++ b/webapp/frontend/src/views/HomeView.vue
@@ -12,6 +12,7 @@ import NodeTooltip from '@/components/NodeTooltip.vue';
import { useUIStore } from '@/stores/uiStore';
import { useMapStore } from '@/stores/mapStore';
+import { useConfigStore } from '@/stores/configStore';
import { useNodeProcessor } from '@/composables/useNodeProcessor';
@@ -20,7 +21,7 @@ import moment from 'moment';
import maplibregl from 'maplibre-gl';
import LegendControl from '@/LegendControl';
import LayerControl from '@/LayerControl';
-import { onMounted, useTemplateRef, ref, watch, markRaw, nextTick, createApp, shallowRef } from 'vue';
+import { onMounted, useTemplateRef, ref, watch, createApp, shallowRef } from 'vue';
import { state } from '@/store';
import {
layerGroups,
@@ -41,21 +42,7 @@ import {
setMap,
getMap,
} from '@/map';
-import {
- nodesMaxAge,
- nodesDisconnectedAge,
- nodesOfflineAge,
- waypointsMaxAge,
- enableMapAnimations,
- goToNodeZoomLevel,
- autoUpdatePositionInUrl,
- neighboursMaxDistance,
- enabledOverlayLayers,
- selectedTileLayerName,
- hasSeenInfoModal,
- lastSeenAnnouncementId,
- CURRENT_ANNOUNCEMENT_ID,
-} from '@/config';
+import { CURRENT_ANNOUNCEMENT_ID } from '@/config';
import {
getColorForSnr,
getPositionPrecisionInMeters,
@@ -75,10 +62,11 @@ const mapEl = useTemplateRef('appMap');
const popup = shallowRef(null); // Keep a single popup reference
const popupTarget = ref(null); // DOM container for Vue teleport
const isTooltipLocked = ref(false); // Locked open (via click)
-const selectedNode = ref(null);
+const selectedNode = ref(null); // related to tooltip only
const ui = useUIStore();
const mapData = useMapStore();
+const config = useConfigStore();
const { parseNodesResponse } = useNodeProcessor();
// watchers
@@ -227,7 +215,7 @@ function showNodeNeighboursThatHeardUs(id) {
const distanceInMeters = neighbourNodeMarker.getLatLng().distanceTo(nodeMarker.getLatLng()).toFixed(2);
// don't show this neighbour connection if further than config allows
- if (neighboursMaxDistance.value != null && parseFloat(distanceInMeters) > neighboursMaxDistance.value) {
+ if (config.neighborsMaxDistance != null && parseFloat(distanceInMeters) > config.neighborsMaxDistance) {
continue;
}
@@ -301,7 +289,7 @@ function showNodeNeighboursThatWeHeard(id) {
// calculate distance in meters between nodes (rounded to 2 decimal places)
const distanceInMeters = nodeMarker.getLatLng().distanceTo(neighbourNodeMarker.getLatLng()).toFixed(2);
- if (neighboursMaxDistance.value != null && parseFloat(distanceInMeters) > neighboursMaxDistance.value) {
+ if (config.neighborsMaxDistance != null && parseFloat(distanceInMeters) > config.neighborsMaxDistance) {
continue;
}
@@ -339,9 +327,9 @@ function onNodesUpdated(nodes) {
mapData.clearNodes();
for (const node of nodes) {
// skip nodes older than configured node max age
- if (nodesMaxAge.value) {
+ if (config.nodesMaxAge !== null) {
const lastUpdatedAgeInMillis = now.diff(moment(node.updated_at));
- if (lastUpdatedAgeInMillis > nodesMaxAge.value * 1000) {
+ if (lastUpdatedAgeInMillis > config.nodesMaxAge * 1000) {
continue;
}
}
@@ -367,9 +355,9 @@ function onNodesUpdated(nodes) {
let icon = icons.mqttDisconnected;
// use offline icon for nodes older than configured node offline age
- if (nodesOfflineAge.value) {
+ if (config.nodesOfflineAge !== null) {
const lastUpdatedAgeInMillis = now.diff(moment(node.updated_at));
- if (lastUpdatedAgeInMillis > nodesOfflineAge.value * 1000) {
+ if (lastUpdatedAgeInMillis > config.nodesOfflineAge * 1000) {
icon = icons.offline;
}
}
@@ -419,9 +407,9 @@ function onWaypointsUpdated(waypoints) {
// add waypoints
for (const waypoint of waypoints) {
// skip waypoints older than configured waypoint max age
- if (waypointsMaxAge.value) {
+ if (config.waypointsMaxAge !== null) {
const lastUpdatedAgeInMillis = now.diff(moment(waypoint.updated_at));
- if (lastUpdatedAgeInMillis > waypointsMaxAge.value * 1000) {
+ if (lastUpdatedAgeInMillis > config.waypointsMaxAge * 1000) {
continue;
}
}
@@ -641,7 +629,7 @@ function goToNode(id, animate, zoom){
const coords = nodeMarker.geometry.coordinates;
getMap().flyTo({
center: coords,
- zoom: parseFloat(zoom || goToNodeZoomLevel.value)
+ zoom: parseFloat(zoom || config.goToNodeZoomLevel)
});
getMap().once('moveend', async () => {
// add position bubble for node
@@ -927,7 +915,6 @@ function measureTooltipSize(node) {
}
async function openLockedTooltipFromNode(feature) {
- console.log('openLockedTooltipFromNode', feature);
const nodeId = feature?.properties?.id;
const node = mapData.findNodeById(nodeId ?? '');
const coordinates = feature?.geometry?.coordinates?.slice();
@@ -1122,10 +1109,10 @@ async function determineAnchorForNode(node, coordinates) {
}
onMounted(() => {
- if (lastSeenAnnouncementId.value !== CURRENT_ANNOUNCEMENT_ID) {
+ if (config.lastSeenAnnouncementId !== CURRENT_ANNOUNCEMENT_ID) {
ui.showAnnouncement();
}
- if (!isMobile() && hasSeenInfoModal.value === false) {
+ if (!isMobile() && config.hasSeenInfoModal === false) {
ui.showInfoModal();
}
})