osr proxy

This commit is contained in:
2026-04-04 11:29:19 -04:00
parent 9b8b9ec664
commit 27a2904bab
20 changed files with 688 additions and 354 deletions

View File

@@ -39,6 +39,7 @@ export default defineConfigWithVueTs(
files: ['**/*.ts', '**/*.vue'], files: ['**/*.ts', '**/*.vue'],
rules: { rules: {
'@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }], '@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
'vue/no-v-text-v-html-on-component': 'off'
}, },
}, },
// https://github.com/vuejs/eslint-config-typescript // https://github.com/vuejs/eslint-config-typescript

208
package-lock.json generated
View File

@@ -10,6 +10,8 @@
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@quasar/extras": "^1.16.4", "@quasar/extras": "^1.16.4",
"@sentry/tracing": "^7.120.4",
"@sentry/vue": "^10.47.0",
"@vue-leaflet/vue-leaflet": "^0.10.1", "@vue-leaflet/vue-leaflet": "^0.10.1",
"axios": "^1.2.1", "axios": "^1.2.1",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
@@ -1961,6 +1963,212 @@
"win32" "win32"
] ]
}, },
"node_modules/@sentry-internal/browser-utils": {
"version": "10.47.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.47.0.tgz",
"integrity": "sha512-bVFRAeJWMBcBCvJKIFCMJ1/yQToL4vPGqfmlnDZeypcxkqUDKQ/Y3ziLHXoDL2sx0lagcgU2vH1QhCQ67Aujjw==",
"license": "MIT",
"dependencies": {
"@sentry/core": "10.47.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/browser-utils/node_modules/@sentry/core": {
"version": "10.47.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.47.0.tgz",
"integrity": "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/feedback": {
"version": "10.47.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.47.0.tgz",
"integrity": "sha512-pdvMmi4dQpX5S/vAAzrhHPIw3T3HjUgDNgUiCBrlp7N9/6zGO2gNPhUnNekP+CjgI/z0rvf49RLqlDenpNrMOg==",
"license": "MIT",
"dependencies": {
"@sentry/core": "10.47.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/feedback/node_modules/@sentry/core": {
"version": "10.47.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.47.0.tgz",
"integrity": "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/replay": {
"version": "10.47.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.47.0.tgz",
"integrity": "sha512-ScdovxP7hJxgMt70+7hFvwT02GIaIUAxdEM/YPsayZBeCoAukPW8WiwztJfoKtsfPyKJ5A6f0H3PIxTPcA9Row==",
"license": "MIT",
"dependencies": {
"@sentry-internal/browser-utils": "10.47.0",
"@sentry/core": "10.47.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/replay-canvas": {
"version": "10.47.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.47.0.tgz",
"integrity": "sha512-A5OY8friSe6g8WAK4L8IeOPiEd9D3Ps40DzRH5j2f6SUja0t90mKMvHRcRf8zq0d4BkdB+JM7tjOkwxpuv8heA==",
"license": "MIT",
"dependencies": {
"@sentry-internal/replay": "10.47.0",
"@sentry/core": "10.47.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/core": {
"version": "10.47.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.47.0.tgz",
"integrity": "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/replay/node_modules/@sentry/core": {
"version": "10.47.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.47.0.tgz",
"integrity": "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/tracing": {
"version": "7.120.4",
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.120.4.tgz",
"integrity": "sha512-Fz5+4XCg3akeoFK+K7g+d7HqGMjmnLoY2eJlpONJmaeT9pXY7yfUyXKZMmMajdE2LxxKJgQ2YKvSCaGVamTjHw==",
"license": "MIT",
"dependencies": {
"@sentry/core": "7.120.4",
"@sentry/types": "7.120.4",
"@sentry/utils": "7.120.4"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/browser": {
"version": "10.47.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.47.0.tgz",
"integrity": "sha512-rC0agZdxKA5XWfL4VwPOr/rJMogXDqZgnVzr93YWpFn9DMZT/7LzxSJVPIJwRUjx3bFEby3PcTa3YaX7pxm1AA==",
"license": "MIT",
"dependencies": {
"@sentry-internal/browser-utils": "10.47.0",
"@sentry-internal/feedback": "10.47.0",
"@sentry-internal/replay": "10.47.0",
"@sentry-internal/replay-canvas": "10.47.0",
"@sentry/core": "10.47.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/browser/node_modules/@sentry/core": {
"version": "10.47.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.47.0.tgz",
"integrity": "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/core": {
"version": "7.120.4",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.120.4.tgz",
"integrity": "sha512-TXu3Q5kKiq8db9OXGkWyXUbIxMMuttB5vJ031yolOl5T/B69JRyAoKuojLBjRv1XX583gS1rSSoX8YXX7ATFGA==",
"license": "MIT",
"dependencies": {
"@sentry/types": "7.120.4",
"@sentry/utils": "7.120.4"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/tracing": {
"version": "7.120.4",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.120.4.tgz",
"integrity": "sha512-cAtpLh23qW3hoqZJ6c36EvFki5NhFWUSK71ALHefqDXEocMlfDc9I+IGn3B/ola2D2TDEDamCy3x32vctKqOag==",
"license": "MIT",
"dependencies": {
"@sentry-internal/tracing": "7.120.4"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/types": {
"version": "7.120.4",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.120.4.tgz",
"integrity": "sha512-cUq2hSSe6/qrU6oZsEP4InMI5VVdD86aypE+ENrQ6eZEVLTCYm1w6XhW1NvIu3UuWh7gZec4a9J7AFpYxki88Q==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/utils": {
"version": "7.120.4",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.120.4.tgz",
"integrity": "sha512-zCKpyDIWKHwtervNK2ZlaK8mMV7gVUijAgFeJStH+CU/imcdquizV3pFLlSQYRswG+Lbyd6CT/LGRh3IbtkCFw==",
"license": "MIT",
"dependencies": {
"@sentry/types": "7.120.4"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/vue": {
"version": "10.47.0",
"resolved": "https://registry.npmjs.org/@sentry/vue/-/vue-10.47.0.tgz",
"integrity": "sha512-zIscc2e1d70yGK4qi4nqBy87TaQBKy0aXza+PtxI9qUWelF4bw0SJoVSglbISw+eOO4y0CBxZVRibLuj0Kv1pw==",
"license": "MIT",
"dependencies": {
"@sentry/browser": "10.47.0",
"@sentry/core": "10.47.0"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@tanstack/vue-router": "^1.64.0",
"pinia": "2.x || 3.x",
"vue": "2.x || 3.x"
},
"peerDependenciesMeta": {
"@tanstack/vue-router": {
"optional": true
},
"pinia": {
"optional": true
}
}
},
"node_modules/@sentry/vue/node_modules/@sentry/core": {
"version": "10.47.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.47.0.tgz",
"integrity": "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@socket.io/component-emitter": { "node_modules/@socket.io/component-emitter": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",

View File

@@ -16,6 +16,8 @@
}, },
"dependencies": { "dependencies": {
"@quasar/extras": "^1.16.4", "@quasar/extras": "^1.16.4",
"@sentry/tracing": "^7.120.4",
"@sentry/vue": "^10.47.0",
"@vue-leaflet/vue-leaflet": "^0.10.1", "@vue-leaflet/vue-leaflet": "^0.10.1",
"axios": "^1.2.1", "axios": "^1.2.1",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",

View File

@@ -124,7 +124,7 @@ export default defineConfig((/* ctx */) => {
'/api': { '/api': {
target: 'http://localhost:49151', target: 'http://localhost:49151',
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''), // rewrite: (path) => path.replace(/^\/api/, ''),
}, },
'/socket.io': { '/socket.io': {
target: 'http://localhost:49151', // Your backend WebSocket server target: 'http://localhost:49151', // Your backend WebSocket server
@@ -134,15 +134,6 @@ export default defineConfig((/* ctx */) => {
changeOrigin: true, changeOrigin: true,
// rewrite: (path) => path.replace(/^\/socket.io/, ''), // rewrite: (path) => path.replace(/^\/socket.io/, ''),
}, },
'/osm': {
target: 'https://nominatim.openstreetmap.org',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/osm/, ''),
headers: {
Referer: 'https://nominatim.openstreetmap.org/',
'User-Agent': 'map-sim-location/0.0.1 (iam@williambr.uno)',
},
},
'/ors': { '/ors': {
// target: 'https://router.project-osrm.org', // target: 'https://router.project-osrm.org',
target: 'http://localhost:8080', target: 'http://localhost:8080',

View File

@@ -1,31 +0,0 @@
import { defineBoot } from '#q-app/wrappers';
import axios, { type AxiosInstance } from 'axios';
declare module 'vue' {
interface ComponentCustomProperties {
$axios: AxiosInstance;
$api: AxiosInstance;
}
}
// Be careful when using SSR for cross-request state pollution
// due to creating a Singleton instance here;
// If any client changes this (global) instance, it might be a
// good idea to move this instance creation inside of the
// "export default () => {}" function below (which runs individually
// for each client)
const api = axios.create({ baseURL: 'http://localhost:5000/api' });
export default defineBoot(({ app }) => {
// for use inside Vue files (Options API) through this.$axios and this.$api
app.config.globalProperties.$axios = axios;
// ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
// so you won't necessarily have to import axios in each vue file
app.config.globalProperties.$api = api;
// ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
// so you can easily perform requests against your app's API
});
export { api };

18
src/boot/sentry.ts Normal file
View File

@@ -0,0 +1,18 @@
import { defineBoot } from '#q-app/wrappers'
import * as Sentry from '@sentry/vue';
export default defineBoot(({ app }) => {
Sentry.init({
app,
dsn: "https://c117cc7eee3a88df9d289edc77d57c60@o4511152447553536.ingest.us.sentry.io/4511152493559808",
sendDefaultPii: true,
enableLogs: true,
integrations: [
Sentry.browserTracingIntegration(),
Sentry.replayIntegration()
],
tracesSampleRate: 1.0,
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
});
})

View File

@@ -0,0 +1,102 @@
<template>
<div>
{{ formattedAddressLine1 }}
<q-inner-loading v-if="loading">
<q-spinner-dots color="primary" />
</q-inner-loading>
</div>
<div>
{{ formattedAddressLine2 }}
<q-inner-loading v-if="loading">
<q-spinner-dots color="primary" />
</q-inner-loading>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import type { NominatimResponse } from 'components/models';
const props = defineProps({
address: Object as () => NominatimResponse,
});
const loading = ref(false);
const formattedAddressLine1 = computed(() => {
if (!loading.value && props.address) {
const formAddress: string = props.address.house_number + ' ' + props.address.road;
return formAddress;
} else {
return '';
}
});
const formattedAddressLine2 = computed(() => {
if (!loading.value && props.address) {
const town: string = props.address.city
? props.address.city
: props.address.village
? props.address.village
: ' ';
const stateAbbr = stateAbbrevMap[props.address.state] ?? props.address.state ?? ' ';
const formAddress: string = town + ', ' + stateAbbr + ' ' + props.address.postcode;
return formAddress;
} else {
return '';
}
});
const stateAbbrevMap: Record<string, string> = {
Alabama: 'AL',
Alaska: 'AK',
Arizona: 'AZ',
Arkansas: 'AR',
California: 'CA',
Colorado: 'CO',
Connecticut: 'CT',
Delaware: 'DE',
Florida: 'FL',
Georgia: 'GA',
Hawaii: 'HI',
Idaho: 'ID',
Illinois: 'IL',
Indiana: 'IN',
Iowa: 'IA',
Kansas: 'KS',
Kentucky: 'KY',
Louisiana: 'LA',
Maine: 'ME',
Maryland: 'MD',
Massachusetts: 'MA',
Michigan: 'MI',
Minnesota: 'MN',
Mississippi: 'MS',
Missouri: 'MO',
Montana: 'MT',
Nebraska: 'NE',
Nevada: 'NV',
'New Hampshire': 'NH',
'New Jersey': 'NJ',
'New Mexico': 'NM',
'New York': 'NY',
'North Carolina': 'NC',
'North Dakota': 'ND',
Ohio: 'OH',
Oklahoma: 'OK',
Oregon: 'OR',
Pennsylvania: 'PA',
'Rhode Island': 'RI',
'South Carolina': 'SC',
'South Dakota': 'SD',
Tennessee: 'TN',
Texas: 'TX',
Utah: 'UT',
Vermont: 'VT',
Virginia: 'VA',
Washington: 'WA',
'West Virginia': 'WV',
Wisconsin: 'WI',
Wyoming: 'WY',
};
</script>

View File

@@ -245,7 +245,6 @@ export class OpenRouteServiceV2 extends L.Class {
/** /**
* Leaflet factory function (typed) * Leaflet factory function (typed)
* Attach to L.Routing.openrouteserviceV2 so that it's callable as L.Routing.openrouteserviceV2
*/ */
export function openrouteserviceV2( export function openrouteserviceV2(
apiKeyOrOptions: string | ORSRequestOptions, apiKeyOrOptions: string | ORSRequestOptions,
@@ -264,15 +263,5 @@ export function openrouteserviceV2(
); );
} }
type LeafletWithRouting = typeof L & { // Do not mutate the ESM namespace import (`import * as L`) because it is non-extensible
Routing?: { // in production bundles. Consumers should import and use `openrouteserviceV2` directly.
openrouteserviceV2?: typeof openrouteserviceV2;
[key: string]: unknown;
};
};
const leafletWithRouting = L as LeafletWithRouting;
if (!leafletWithRouting.Routing) {
leafletWithRouting.Routing = {};
}
leafletWithRouting.Routing.openrouteserviceV2 = openrouteserviceV2;

View File

@@ -108,18 +108,41 @@
:lat-lng="safeMarkerLatLng" :lat-lng="safeMarkerLatLng"
@click="handleMarkerClick" @click="handleMarkerClick"
> >
<L-Popup :options="{ closeOnClick: true }"> <L-Popup
<q-list dense seperator style="min-width: 150px" class="bg-grey-10"> :options="{ closeOnClick: true, closeButton: false, className: 'marker-popup' }"
<q-item clickable v-close-popup @click="handleAddLocation"> >
<q-item-section avatar><q-icon name="add_location" /></q-item-section> <q-list dense seperator style="min-width: 100px" class="bg-grey-10">
<q-item clickable v-ripple @click="handleAddLocation">
<q-item-section avatar>
<q-avatar
icon="add_location"
color="primary"
text-color="white"
size="sm"
/>
</q-item-section>
<q-item-section>Add Location</q-item-section> <q-item-section>Add Location</q-item-section>
</q-item> </q-item>
<q-item clickable v-close-popup @click="setStartRoute"> <q-item clickable v-ripple @click="setStartRoute">
<q-item-section avatar><q-icon name="add_location" /></q-item-section> <q-item-section avatar>
<q-avatar
icon="add_location"
color="primary"
text-color="white"
size="sm"
/>
</q-item-section>
<q-item-section>Set Route Start</q-item-section> <q-item-section>Set Route Start</q-item-section>
</q-item> </q-item>
<q-item clickable v-close-popup @click="setEndRoute"> <q-item clickable v-ripple @click="setEndRoute">
<q-item-section avatar><q-icon name="add_location" /></q-item-section> <q-item-section avatar>
<q-avatar
icon="add_location"
color="primary"
text-color="white"
size="sm"
/>
</q-item-section>
<q-item-section>Set Route End</q-item-section> <q-item-section>Set Route End</q-item-section>
</q-item> </q-item>
</q-list> </q-list>
@@ -186,7 +209,7 @@ import LRoutingMachine from 'components/LRoutingMachine.vue';
import LocationMark from 'components/LocationMark.vue'; import LocationMark from 'components/LocationMark.vue';
import SetLocationDialog from 'components/SetLocationDialog.vue'; import SetLocationDialog from 'components/SetLocationDialog.vue';
import { customRouter } from 'functions/serviceURL'; import { customRouter } from 'functions/serviceURL';
import { reverseGeocodeRateLimited } from 'functions/reverseGeocode'; //import { reverseGeocodeRateLimited } from 'functions/reverseGeocode';
import { useRoutingEvents } from '../composables/useRoutingEvents'; import { useRoutingEvents } from '../composables/useRoutingEvents';
import { useMarkerContextMenu } from '../composables/useMarkerContextMenu'; import { useMarkerContextMenu } from '../composables/useMarkerContextMenu';
import type { IRouter } from 'leaflet-routing-machine'; import type { IRouter } from 'leaflet-routing-machine';
@@ -195,8 +218,7 @@ import type { IRouter } from 'leaflet-routing-machine';
import type { import type {
coords, coords,
SearchControlProps, SearchControlProps,
NominatimAddress, // NominatimAddress,
routeSegments,
} from 'components/models'; } from 'components/models';
import type { LeafletMouseEvent, Map } from 'leaflet'; import type { LeafletMouseEvent, Map } from 'leaflet';
@@ -208,7 +230,7 @@ import { useLeafletStore } from 'stores/leaflet';
import { favorites } from 'constants/favorites'; import { favorites } from 'constants/favorites';
const leafletStore = useLeafletStore(); const leafletStore = useLeafletStore();
const { zoom, center, markerLatLng, qLocDrawer, routeSet, routeSegments } = const { zoom, center, markerLatLng, qLocDrawer, routeSet, routeDirections } =
storeToRefs(leafletStore); storeToRefs(leafletStore);
const socketStore = useSocketioStore(); const socketStore = useSocketioStore();
@@ -226,7 +248,6 @@ const $q = useQuasar();
const mapRef = ref(); const mapRef = ref();
const responseMessage = ref(''); const responseMessage = ref('');
const miniState = ref(true); const miniState = ref(true);
const loading = ref(false);
const safeCenter = computed<[number, number]>(() => { const safeCenter = computed<[number, number]>(() => {
const lat = center.value?.[0]; const lat = center.value?.[0];
const lng = center.value?.[1]; const lng = center.value?.[1];
@@ -320,25 +341,54 @@ function updateMarker(event: LeafletMouseEvent) {
center.value = [event.latlng.lat, event.latlng.lng]; center.value = [event.latlng.lat, event.latlng.lng];
} }
function routeToQueue() { function closeAllPopups() {
console.log('routeToQueue'); if (mapRef.value) {
if (routeSet.value.start && routeSet.value.end && routeSegments.value) { // Access the Leaflet map instance directly
console.log('routeToQueue: start: ', routeSet.value.start); mapRef.value.leafletObject.closePopup();
setLocation({ lat: routeSet.value.start.lat, lng: routeSet.value.start.lng }, 0);
routeSegments.value.forEach((segment: routeSegments) => {
console.log('routeToQueue: segment: ', segment);
setLocation(
{ lat: segment.toCoordinates.lat, lng: segment.toCoordinates.lng },
segment.timeSeconds,
);
});
console.log('routeToQueue: end: ', routeSet.value.end);
setLocation({ lat: routeSet.value.end.lat, lng: routeSet.value.end.lng }, 0);
} }
} }
const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));
async function routeToQueue() {
if (routeSet.value.start && routeSet.value.end && routeDirections) {
if (routeDirections.value && routeDirections.value.length > 0) {
for (const direction of routeDirections.value) {
if (direction.coordinates) {
await setLocation(
{ lat: Number(direction.coordinates.lat), lng: Number(direction.coordinates.lng) },
direction.time,
);
}
await delay(1000);
}
}
}
}
/* function routeToQueue() {
console.log('routeToQueue');
if (routeSet.value.start && routeSet.value.end && routeSegments) {
console.log('routeToQueue: start: ', routeSet.value.start);
setLocation(
{ lat: Number(routeSet.value.start.lat), lng: Number(routeSet.value.start.lng) },
0,
);
if (routeSegments.value) {
routeSegments.value.forEach((segment: routeSegments) => {
console.log('routeToQueue: segment: ', segment);
setLocation(
{ lat: Number(segment.toCoordinates.lat), lng: Number(segment.toCoordinates.lng) },
segment.timeSeconds,
);
});
}
console.log('routeToQueue: end: ', routeSet.value.end);
setLocation({ lat: Number(routeSet.value.end.lat), lng: Number(routeSet.value.end.lng) }, 0);
}
}
*/
function clearRoute() { function clearRoute() {
routeSegments.value = []; void leafletStore.clearRouteSegments;
routingOptions.waypoints = []; routingOptions.waypoints = [];
routeSet.value.start = { lat: null, lng: null }; routeSet.value.start = { lat: null, lng: null };
routeSet.value.end = { lat: null, lng: null }; routeSet.value.end = { lat: null, lng: null };
@@ -362,21 +412,23 @@ const updateRoute = () => {
const { clickedLatLng, handleMarkerClick, setStartRoute, setEndRoute } = useMarkerContextMenu( const { clickedLatLng, handleMarkerClick, setStartRoute, setEndRoute } = useMarkerContextMenu(
routeSet, routeSet,
updateRoute, updateRoute,
closeAllPopups,
); );
function handleAddLocation() { function handleAddLocation() {
if (clickedLatLng.value) { if (clickedLatLng.value) {
const latlng = clickedLatLng.value; const latlng = clickedLatLng.value;
closeAllPopups();
$q.notify(`add location...${latlng.toString()}`); $q.notify(`add location...${latlng.toString()}`);
reverseGeocode(latlng.lat, latlng.lng) // reverseGeocode(latlng.lat, latlng.lng)
.then((data) => { // .then((data) => {
const NomAddress = data.address as unknown as NominatimAddress; // const NomAddress = data.address as unknown as NominatimAddress;
$q.dialog({ $q.dialog({
component: SetLocationDialog, component: SetLocationDialog,
componentProps: { componentProps: {
lat: Number(latlng.lat), lat: Number(latlng.lat),
lng: Number(latlng.lng), lng: Number(latlng.lng),
address: NomAddress, // address: NomAddress,
}, },
}) })
.onOk((delay: number) => { .onOk((delay: number) => {
@@ -396,13 +448,13 @@ function handleAddLocation() {
.onDismiss(() => { .onDismiss(() => {
console.log('Dialog dismissed'); console.log('Dialog dismissed');
}); });
}) // })
.catch((error) => { // .catch((error) => {
console.error('Error fetching reverse geocode:', error); // console.error('Error fetching reverse geocode:', error);
}); // });
} }
} }
/*
async function reverseGeocode(lat: number, lng: number) { async function reverseGeocode(lat: number, lng: number) {
loading.value = true; loading.value = true;
try { try {
@@ -416,29 +468,36 @@ async function reverseGeocode(lat: number, lng: number) {
loading.value = false; loading.value = false;
} }
} }
*/
function setLocation(coords: coords, delay: number) { async function setLocation(coords: coords, delay: number) {
return new Promise((resolve, reject) => {
let notType: string = 'positive'; let notType: string = 'positive';
try { try {
const setCmdRsp = socketStore.simulationControl('add', delay, coords.lat, coords.lng); const setCmdRsp = socketStore.simulationControl('add', delay, coords.lat, coords.lng);
if (setCmdRsp.sts === 'error') {
notType = 'negative';
}
if (setCmdRsp.msg) { if (setCmdRsp.msg) {
responseMessage.value = setCmdRsp.msg; responseMessage.value = setCmdRsp.msg;
} }
if (setCmdRsp.sts === 'error') {
notType = 'negative';
reject(new Error(setCmdRsp.msg || 'Unknown error'));
}
resolve(setCmdRsp);
} catch (error: unknown) { } catch (error: unknown) {
notType = 'negative'; notType = 'negative';
if (error instanceof Error) { if (error instanceof Error) {
console.error('Error setting location:', error.message); console.error('Error setting location:', error.message);
responseMessage.value = `Failed to set location: ${error.message}`; responseMessage.value = `Failed to set location: ${error.message}`;
reject(error);
} else { } else {
console.error('Error setting location:', error); console.error('Error setting location:', error);
responseMessage.value = `Failed to set location: Unknown error`; responseMessage.value = `Failed to set location: Unknown error`;
reject(new Error('Unknown error'));
} }
} finally { } finally {
$q.notify({ type: notType, message: responseMessage.value }); $q.notify({ type: notType, message: responseMessage.value });
} }
});
} }
function zoomToCoods(arg: string) { function zoomToCoods(arg: string) {
@@ -507,4 +566,9 @@ onMounted(() => {
.leafletDrawer .leafletDrawer
background-color: $dark background-color: $dark
color: $dark color: $dark
.marker-popup .leaflet-popup-content-wrapper, .marker-popup .leaflet-popup-tip
background-color: $dark
.marker-popup .leaflet-popup-content
margin: 13px 10px 13px 10px
</style> </style>

View File

@@ -2,15 +2,18 @@
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useSocketioStore } from 'stores/socketio'; import { useSocketioStore } from 'stores/socketio';
import { computed, onMounted, onUnmounted, ref } from 'vue'; import { computed, onMounted, onUnmounted, ref } from 'vue';
import type { NominatimResponse } from 'components/models';
import { Icon, PinCirclePanel } from 'leaflet-extra-markers'; import { Icon, PinCirclePanel } from 'leaflet-extra-markers';
import FormattedAddress from 'components/FormattedAddress.vue';
const socketStore = useSocketioStore(); const socketStore = useSocketioStore();
const { currentLocation, locationQueueOrder, simulationRunning } = storeToRefs(socketStore); const { currentLocation, locationQueueOrder, simulationRunning } = storeToRefs(socketStore);
const props = defineProps({ const props = defineProps({
address: { address: {
type: String, type: Object as () => NominatimResponse,
required: true, required: true,
}, },
latitude: { latitude: {
@@ -52,7 +55,7 @@ const props = defineProps({
index: { index: {
type: Number, type: Number,
default: 0, default: 0,
} },
}); });
// Define custom events that this component can emit // Define custom events that this component can emit
@@ -133,7 +136,7 @@ const humanReadableDateTime = (iso: string) => {
minute: '2-digit', minute: '2-digit',
}); });
}; };
/*
const stateAbbrevMap: Record<string, string> = { const stateAbbrevMap: Record<string, string> = {
Alabama: 'AL', Alabama: 'AL',
Alaska: 'AK', Alaska: 'AK',
@@ -204,6 +207,7 @@ function formatAddress(input: string): string {
return `${streetNumber} ${streetName}, ${city}, ${state} ${zip}`; return `${streetNumber} ${streetName}, ${city}, ${state} ${zip}`;
} }
*/
const currentIndex = computed(() => { const currentIndex = computed(() => {
return currentLocation.value ? locationQueueOrder.value.indexOf(currentLocation.value.loc_id) : 0; return currentLocation.value ? locationQueueOrder.value.indexOf(currentLocation.value.loc_id) : 0;
@@ -260,8 +264,8 @@ onUnmounted(() => {
<template> <template>
<q-item v-ripple clickable :active="active" @click="itemClicked" :class="itemClass"> <q-item v-ripple clickable :active="active" @click="itemClicked" :class="itemClass">
<q-item-section> <q-item-section>
<q-item-label <q-item-label>
>{{ formatAddress(address) }} <FormattedAddress :address="props.address" />
<q-tooltip> {{ latitude }}, {{ longitude }} </q-tooltip> <q-tooltip> {{ latitude }}, {{ longitude }} </q-tooltip>
</q-item-label> </q-item-label>
<q-item-label caption lines="1" v-if="start && simulationRunning"> <q-item-label caption lines="1" v-if="start && simulationRunning">

View File

@@ -17,7 +17,7 @@ const $q = useQuasar();
const leafletStore = useLeafletStore(); const leafletStore = useLeafletStore();
const socketStore = useSocketioStore(); const socketStore = useSocketioStore();
const { center, markerLatLng } = storeToRefs(leafletStore); const { center, markerLatLng, zoom } = storeToRefs(leafletStore);
const { simulationRunning, simulationState, simulationQueueLength, icloudMonitor, testMode } = const { simulationRunning, simulationState, simulationQueueLength, icloudMonitor, testMode } =
storeToRefs(socketStore); storeToRefs(socketStore);
@@ -57,6 +57,7 @@ function hasSubitems(item: unknown): item is FavoriteWithSubitems {
function handleFavClick(coords: coords) { function handleFavClick(coords: coords) {
center.value = [coords.lat, coords.lng]; center.value = [coords.lat, coords.lng];
markerLatLng.value = [coords.lat, coords.lng]; markerLatLng.value = [coords.lat, coords.lng];
zoom.value = 15;
} }
function handleTestToggle() { function handleTestToggle() {
@@ -181,7 +182,7 @@ function handleControlClick(cmdAttr: ControlAction) {
<template> <template>
<q-toolbar :class="testMode ? 'bg-warning text-black' : 'bg-primary text-white'"> <q-toolbar :class="testMode ? 'bg-warning text-black' : 'bg-primary text-white'">
<q-btn <!-- <q-btn
@click=" @click="
$emit('drawer'); $emit('drawer');
leafletStore.toggleQLocDrawer(); leafletStore.toggleQLocDrawer();
@@ -192,6 +193,7 @@ function handleControlClick(cmdAttr: ControlAction) {
icon="menu" icon="menu"
class="q-mr-sm" class="q-mr-sm"
/> />
-->
<q-separator dark inset /> <q-separator dark inset />
<q-space /> <q-space />
<q-btn <q-btn

View File

@@ -1,16 +1,16 @@
<template> <template>
<q-dialog ref="dlgRef" persistent> <q-dialog ref="dlgRef" persistent>
<q-card class="bg-secondary text-grey-1 add-loc-card"> <q-card class="bg-dark text-grey-1 add-loc-card q-pa-sm">
<q-card-section> <q-toolbar>
<q-avatar icon="add_location" color="dark" text-color="white" /> <q-avatar icon="add_location" color="primary" text-color="white" />
<span class="text-h6"> Add Location to Queue</span> <q-toolbar-title>Add Location to Queue</q-toolbar-title>
</q-card-section> </q-toolbar>
<q-card-section class="q-ml-lg"> <q-card-section class="q-ml-lg">
<div class="q-mb-sm">Are you sure you want to set location to:</div> <div class="q-mb-sm">Are you sure you want to set location to:</div>
<div class="q-ml-lg">{{ formattedAddressLine1 }}</div> <div class="q-ml-lg">
<div class="q-ml-lg">{{ formattedAddressLine2 }}</div> <formatted-address :address="address" />
<q-input <q-input
class="q-mt-sm"
style="max-width: 150px" style="max-width: 150px"
v-model.number="delay" v-model.number="delay"
filled filled
@@ -20,6 +20,7 @@
suffix="seconds" suffix="seconds"
color="grey-4" color="grey-4"
/> />
</div>
</q-card-section> </q-card-section>
<q-separator /> <q-separator />
<q-card-actions align="right"> <q-card-actions align="right">
@@ -32,42 +33,35 @@
<script setup lang="ts"> <script setup lang="ts">
import { useDialogPluginComponent } from 'quasar'; import { useDialogPluginComponent } from 'quasar';
import { computed, ref } from 'vue'; import { reverseGeocodeRateLimited } from 'functions/reverseGeocode';
import type { PropType } from 'vue'; import { ref, onMounted } from 'vue';
import type { NominatimAddress } from 'components/models'; import FormattedAddress from 'components/FormattedAddress.vue';
const props = defineProps({ const props = defineProps({
lat: { type: Number, required: true }, lat: { type: Number, required: true },
lng: { type: Number, required: true }, lng: { type: Number, required: true },
address: { type: Object as PropType<NominatimAddress>, required: false },
}); });
const loading = ref(true);
const delay = ref(0); const delay = ref(0);
defineEmits([...useDialogPluginComponent.emits]); defineEmits([...useDialogPluginComponent.emits]);
const { dialogRef: dlgRef, onDialogOK, onDialogCancel } = useDialogPluginComponent(); const { dialogRef: dlgRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
const formattedAddressLine1 = computed(() => { const address = ref();
if (props.address) {
const formAddress: string = props.address.house_number + ' ' + props.address.road;
return formAddress;
} else {
return '';
}
});
const formattedAddressLine2 = computed(() => { onMounted(async () => {
if (props.address) { try {
const town: string = props.address.city loading.value = true;
? props.address.city const response = await reverseGeocodeRateLimited(props.lat, props.lng);
: props.address.village console.log('reverse geocode response: ', response);
? props.address.village address.value = response;
: ' '; } catch (error) {
const formAddress: string = town + ', ' + props.address.state + ' ' + props.address.postcode; console.error('Error fetching reverse geocode:', error);
return formAddress; throw error;
} else { } finally {
return ''; loading.value = false;
} }
}); });

View File

@@ -2,12 +2,25 @@ export interface CtrlAttrs {
[key: string]: CtrlAttr; [key: string]: CtrlAttr;
} }
export type SimulationCommands =
export type SimulationCommands = 'start' | 'pause' | 'resume' | 'clear' | 'end' | 'add' | 'test-mode'; | 'start'
| 'pause'
| 'resume'
| 'clear'
| 'end'
| 'add'
| 'test-mode';
export type DeviceCommands = 'start_tunnel' | 'stop_tunnel' | 'shutdown' | 'reboot'; export type DeviceCommands = 'start_tunnel' | 'stop_tunnel' | 'shutdown' | 'reboot';
export type TunnelCommands = 'start' | 'start-watcher' | 'end-watcher' | 'shutdown' | 'restart' | 'clear' | 'cancel' ; export type TunnelCommands =
| 'start'
| 'start-watcher'
| 'end-watcher'
| 'shutdown'
| 'restart'
| 'clear'
| 'cancel';
export interface CtrlAttr { export interface CtrlAttr {
name: string; name: string;
@@ -28,7 +41,7 @@ export interface DevCtrlAttr {
} }
export interface LocationQueue { export interface LocationQueue {
[key: string]: LocationMark [key: string]: LocationMark;
} }
interface LocationMark { interface LocationMark {
@@ -37,7 +50,7 @@ interface LocationMark {
longitude: number | undefined | null; longitude: number | undefined | null;
address?: string | undefined | null; address?: string | undefined | null;
delay?: number | undefined | null; delay?: number | undefined | null;
start?: string | undefined | null; start: string | undefined | null;
end?: string | undefined | null; end?: string | undefined | null;
} }
@@ -254,24 +267,22 @@ export interface NextLocation {
time_at_location?: number | null; time_at_location?: number | null;
} }
export interface NominatimReverseResponse { export interface NominatimReverseResponse {
place_id: number place_id: number;
licence: string licence: string;
osm_type: string osm_type: string;
osm_id: number osm_id: number;
lat: string lat: string;
lon: string lon: string;
class: string class: string;
type: string type: string;
place_rank: number place_rank: number;
importance: number importance: number;
addresstype: string addresstype: string;
name: string name: string;
display_name: string display_name: string;
address: NominatimAddress address: NominatimAddress;
boundingbox: string[] boundingbox: string[];
} }
export interface NominatimAddress { export interface NominatimAddress {
@@ -289,8 +300,53 @@ export interface NominatimAddress {
export interface routeSegments { export interface routeSegments {
fromWaypoint: number; fromWaypoint: number;
toWaypoint: number, toWaypoint: number;
distanceMeters: number, distanceMeters: number;
timeSeconds: number, timeSeconds: number;
toCoordinates: {lat: number, lng: number}; toCoordinates: LatLng;
}
export interface RoutesSet {
[key: string]: RouteSet;
}
export interface LatLng {
lat: number | null | undefined;
lng: number | null | undefined;
}
export interface routeDirections {
dirIndex: number;
coordinateIndex: number;
text: string;
distance: number;
time: number;
coordinates: LatLng | null | undefined;
}
export interface RouteSet {
start: [number, number] | [null, null] | [undefined, undefined] | null | undefined;
end: [number, number] | [null, null] | [undefined, undefined] | null | undefined;
wayPoints?: [number, number][] | [null, null] | [undefined, undefined] | null | undefined;
}
// TypeScript Interface for Reverse Geocoding Response
export interface NominatimResponse {
house_number?: string | null | undefined;
road: string;
neighbourhood?: string | null | undefined;
suburb?: string | null | undefined;
county: string;
city?: string | null | undefined;
village?: string | null | undefined;
state: string;
'ISO3166-2-lvl4': string;
postcode: string;
country: string;
country_code: string;
}
export interface NominatimRequest {
latitude: number;
longitude: number;
} }

View File

@@ -13,17 +13,23 @@ type RouteSetLike = {
[key: string]: unknown; [key: string]: unknown;
}; };
export function useMarkerContextMenu(routeSet: Ref<RouteSetLike>, updateRoute: () => void) { export function useMarkerContextMenu(
routeSet: Ref<RouteSetLike>,
updateRoute: () => void,
closeAllPopups: () => void,
) {
const clickedLatLng = ref<LeafLet.LatLng | null>(null); const clickedLatLng = ref<LeafLet.LatLng | null>(null);
const handleMarkerClick = (event: LeafletMouseEvent) => { const handleMarkerClick = (event: LeafletMouseEvent) => {
console.log('marker clicked', event); console.log('marker clicked', event);
closeAllPopups();
clickedLatLng.value = event.latlng; clickedLatLng.value = event.latlng;
LeafLet.DomEvent.stopPropagation(event.originalEvent); LeafLet.DomEvent.stopPropagation(event.originalEvent);
}; };
const setStartRoute = () => { const setStartRoute = () => {
if (!clickedLatLng.value) return; if (!clickedLatLng.value) return;
closeAllPopups();
(routeSet.value as RouteSet).start = clickedLatLng.value; (routeSet.value as RouteSet).start = clickedLatLng.value;
console.log('setStartRoute: ', routeSet.value.start); console.log('setStartRoute: ', routeSet.value.start);
}; };
@@ -31,6 +37,7 @@ export function useMarkerContextMenu(routeSet: Ref<RouteSetLike>, updateRoute: (
const setEndRoute = () => { const setEndRoute = () => {
if (!clickedLatLng.value) return; if (!clickedLatLng.value) return;
(routeSet.value as RouteSet).end = clickedLatLng.value; (routeSet.value as RouteSet).end = clickedLatLng.value;
closeAllPopups();
console.log('setEndRoute: ', routeSet.value.end); console.log('setEndRoute: ', routeSet.value.end);
updateRoute(); updateRoute();
console.log('updating Route'); console.log('updating Route');

View File

@@ -4,7 +4,6 @@ import { storeToRefs } from 'pinia';
const leafletStore = useLeafletStore(); const leafletStore = useLeafletStore();
const { routeSegments, routeDirections } = storeToRefs(leafletStore); const { routeSegments, routeDirections } = storeToRefs(leafletStore);
type RouteSummary = { type RouteSummary = {
totalDistance: number; totalDistance: number;
totalTime: number; totalTime: number;
@@ -17,6 +16,11 @@ type RouteWaypoint = {
}; };
}; };
type RouteCoordinates = {
lat: number;
lng: number;
};
type RouteInstructions = { type RouteInstructions = {
text: string; text: string;
distance: number; distance: number;
@@ -30,6 +34,7 @@ type RouteResult = {
inputWaypoints?: RouteWaypoint[]; inputWaypoints?: RouteWaypoint[];
instructions?: RouteInstructions[]; instructions?: RouteInstructions[];
waypoints?: RouteWaypoint[]; waypoints?: RouteWaypoint[];
coordinates?: RouteCoordinates[];
}; };
export function useRoutingEvents() { export function useRoutingEvents() {
@@ -50,24 +55,32 @@ export function useRoutingEvents() {
toWaypoint: index + 1, toWaypoint: index + 1,
distanceMeters: segment.totalDistance, distanceMeters: segment.totalDistance,
timeSeconds: segment.totalTime, timeSeconds: segment.totalTime,
toCoordinates: route.inputWaypoints?.[index + 1]?.latLng ?? null, toCoordinates: route.inputWaypoints?.[index + 1]?.latLng ??
route.waypoints?.[index + 1]?.latLng ?? { lat: 0, lng: 0 },
})); }));
if (routeSegments) {
routeSegments.value = segmentSummary; routeSegments.value = segmentSummary;
}
console.log('Waypoint segment summary:', segmentSummary); console.log('Waypoint segment summary:', segmentSummary);
} }
if (route.instructions?.length) { if (route.instructions?.length) {
const directionsSummary = route.instructions.map((direction, inx) => ({ const directionsSummary = route.instructions.map((direction, inx) => ({
waypoint: inx, dirIndex: inx,
coordinateIndex: direction.index,
text: direction.text, text: direction.text,
distance: direction.distance, distance: direction.distance,
time: direction.time, time: direction.time,
coordinates: route.waypoints?.[direction.index], coordinates: {
lat: route.coordinates?.[direction.index]?.lat,
lng: route.coordinates?.[direction.index]?.lng,
},
})); }));
console.log('Direction waypoint segment summary:', directionsSummary); console.log('Direction waypoint segment summary:', directionsSummary);
if (routeDirections) {
routeDirections.value = directionsSummary; routeDirections.value = directionsSummary;
} }
}
}; };
return { return {

View File

@@ -1,26 +1,13 @@
// services/nominatimService.ts // services/nominatimService.ts
import { osm } from 'boot/axios'; import { api } from 'boot/axios';
import type { NominatimResponse, NominatimRequest } from 'components/models';
// TypeScript Interface for Reverse Geocoding Response
export interface NominatimResponse {
place_id: number;
display_name: string;
address: {
road?: string;
city?: string;
country?: string;
[key: string]: unknown;
};
lat: string;
lon: string;
}
const API_URL = '/reverse';
// Simple debounce to respect 1s limit
let lastRequestTime = 0; let lastRequestTime = 0;
export const reverseGeocodeRateLimited = async (lat: number, lon: number): Promise<NominatimResponse> => { export const reverseGeocodeRateLimited = async (
lat: number,
lon: number,
): Promise<NominatimResponse> => {
const now = Date.now(); const now = Date.now();
const timeSinceLast = now - lastRequestTime; const timeSinceLast = now - lastRequestTime;
@@ -28,19 +15,10 @@ export const reverseGeocodeRateLimited = async (lat: number, lon: number): Promi
if (timeSinceLast < 1000) { if (timeSinceLast < 1000) {
await new Promise((resolve) => setTimeout(resolve, 1000 - timeSinceLast)); await new Promise((resolve) => setTimeout(resolve, 1000 - timeSinceLast));
} }
const response = await api.post<NominatimResponse>('/rev_geocode', {
const response = await osm.get<NominatimResponse>(API_URL, { latitude: lat,
params: { longitude: lon,
lat, } as NominatimRequest);
lon,
format: 'jsonv2',
addressdetails: 1,
},
headers: {
// It is mandatory to set a descriptive User-Agent
'User-Agent': 'Vue3App/1.0 (your-email@example.com)',
},
});
lastRequestTime = Date.now(); lastRequestTime = Date.now();
return response.data; return response.data;

View File

@@ -1,9 +1,10 @@
import { openrouteserviceV2 } from 'components/L.Routing.OpenRouteServiceV2'; import { openrouteserviceV2 } from 'components/L.Routing.OpenRouteServiceV2';
export const customRouter = openrouteserviceV2({ export const customRouter = openrouteserviceV2({
api_key: '',
profile: 'driving-car', profile: 'driving-car',
geometry_simplify: true, geometry_simplify: true,
host: '/ors', host: '/api/proxy/ors/',
}); });
//export const customRouter = L.Routing.osrmv1({ //export const customRouter = L.Routing.osrmv1({

View File

@@ -1,37 +1,6 @@
import { defineStore, acceptHMRUpdate } from 'pinia'; import { defineStore, acceptHMRUpdate } from 'pinia';
import { favorites } from 'constants/favorites' import { favorites } from 'constants/favorites'
import type { RoutesSet, LatLng, routeSegments, routeDirections } from 'components/models';
interface RoutesSet {
[key: string]: RouteSet
}
interface LatLng {
lat: number | null | undefined;
lng: number | null | undefined;
}
interface routeSegments {
fromWaypoint: number;
toWaypoint: number;
distanceMeters: number;
timeSeconds: number;
toCoordinates: LatLng | null | undefined;
}
interface routeDirections {
waypoint: number;
text: string;
distance: number;
time: number;
coordinates: LatLng | null | undefined;
}
interface RouteSet {
start: [number, number] | [null, null] | [undefined, undefined] | null | undefined;
end: [number, number] | [null, null] | [undefined, undefined] | null | undefined;
wayPoints?: [number, number][] | [null, null] | [undefined, undefined] | null | undefined;
}
interface State { interface State {
zoom: number; zoom: number;
@@ -39,8 +8,8 @@ interface State {
markerLatLng: [number, number] | [null, null] | null; markerLatLng: [number, number] | [null, null] | null;
qLocDrawer: boolean; qLocDrawer: boolean;
routeSet: { routeSet: {
start: LatLng | null | undefined; start: LatLng;
end: LatLng | null | undefined; end: LatLng;
wayPoints?: LatLng[] | null | undefined; wayPoints?: LatLng[] | null | undefined;
}; };
routesSet: RoutesSet[] | null; routesSet: RoutesSet[] | null;
@@ -60,12 +29,15 @@ export const useLeafletStore = defineStore('leaflet', {
end: { lat: null, lng: null }, end: { lat: null, lng: null },
wayPoints: null, wayPoints: null,
}, },
routesSet: null, routesSet: [],
routeSegments: null, routeSegments: [],
routeDirections: null, routeDirections: [],
}; };
}, },
actions: { actions: {
clearRouteSegments() {
this.routeSegments = [];
},
setCenter(lat: number, lng: number) { setCenter(lat: number, lng: number) {
this.center = [lat, lng]; this.center = [lat, lng];
}, },

View File

@@ -14,7 +14,6 @@ import type {
SimulationStatus, SimulationStatus,
} from 'components/models'; } from 'components/models';
const $q = useQuasar(); const $q = useQuasar();
const debugLog: boolean = true; const debugLog: boolean = true;
@@ -115,14 +114,19 @@ export const useSocketioStore = defineStore('socketio', {
if (debugLog) { if (debugLog) {
console.log('event: simulation_status received: ', data); console.log('event: simulation_status received: ', data);
} }
console.log('updating currentLocation', data) console.log('updating currentLocation', data);
this.currentLocation = { this.currentLocation = {
loc_id: data.loc_id, loc_id: data.loc_id,
latitude: data.latitude, latitude: data.latitude,
longitude: data.longitude, longitude: data.longitude,
next_move: data.next_move, next_move: data.next_move,
}; };
this.locationQueueData[data.loc_id]['start'] = data.start; if (data.start) {
const queueItem = this.locationQueueData[data.loc_id];
if (queueItem) {
queueItem.start = data.start;
}
}
}); });
socket.on('icloud_2fa_request', (callback) => { socket.on('icloud_2fa_request', (callback) => {
@@ -226,7 +230,8 @@ export const useSocketioStore = defineStore('socketio', {
fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status }; fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status };
this.icloudMonitor = true; this.icloudMonitor = true;
} }
}); },
);
break; break;
case 'stop': case 'stop':
if (debugLog) { if (debugLog) {
@@ -258,7 +263,8 @@ export const useSocketioStore = defineStore('socketio', {
fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status }; fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status };
this.icloudMonitor = false; this.icloudMonitor = false;
} }
}); },
);
break; break;
case 'status': case 'status':
if (debugLog) { if (debugLog) {
@@ -289,11 +295,14 @@ export const useSocketioStore = defineStore('socketio', {
'iCloud Monitor Enabled: ' + 'iCloud Monitor Enabled: ' +
response.icloud_monitor_enabled + response.icloud_monitor_enabled +
'iCloud Monitor Running: ' + 'iCloud Monitor Running: ' +
response.icloud_monitor_running response.icloud_monitor_running,
}; };
} }
this.icloudMonitor = !!(response.icloud_monitor_enabled && response.icloud_monitor_running); this.icloudMonitor = !!(
}); response.icloud_monitor_enabled && response.icloud_monitor_running
);
},
);
break; break;
default: default:
fnctRtn = { sts: 'error', msg: 'Invalid command' }; fnctRtn = { sts: 'error', msg: 'Invalid command' };

View File

@@ -1,46 +0,0 @@
import type { OpenStreetMapProvider } from 'leaflet-geosearch';
export interface DeviceShort {
udid: string | null;
connection_type: string | null;
}
export interface StatusUpdate {
device_connected: boolean;
device_count: number;
// devices?: Array<DeviceShort>;
udid?: string | null;
device_name?: string | null;
product_version?: string | null;
phone_number?: string | null;
developer_mode_enabled?: boolean;
ddi_mounted?: boolean;
rsd_address?: string | null;
rsd_port?: number;
lockdown_trusted_port?: number;
lockdown_untrusted_port?: number;
lockdown_trusted_reachable?: boolean;
lockdown_untrusted_reachable?: boolean;
dtservicehub_reachable?: boolean;
}
export interface coords {
lat: number;
lng: number;
}
export interface SearchControlProps {
provider: OpenStreetMapProvider;
showMarker: boolean;
autoClose: boolean;
updateMap: boolean;
showPopup: boolean;
style: 'button' | 'bar';
acceptAutoLoad: boolean;
autoComplete: boolean;
autoCompleteDelay: number;
retainZoomLevel: boolean;
animateZoom: boolean;
keepResult: boolean;
}