mirror of
https://github.com/owntracks/frontend.git
synced 2026-03-07 22:40:17 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
458658865e | ||
|
|
e744e2c001 | ||
|
|
feff6d5272 | ||
|
|
7b88102c2b | ||
|
|
a2c7974f38 | ||
|
|
b3fdf1eabe | ||
|
|
1482833e05 | ||
|
|
04fa3392f0 | ||
|
|
a4334e5273 | ||
|
|
806526380d |
@@ -2,11 +2,18 @@
|
||||
|
||||
Dates are in UTC.
|
||||
|
||||
## 2.1.0 (2020-03-18)
|
||||
|
||||
- Replace default Leaflet marker with a custom one ([#2](https://github.com/owntracks/frontend/issues/2))
|
||||
- Improve verbose mode logging
|
||||
- Improve mobile usability ([#19](https://github.com/owntracks/frontend/issues/19))
|
||||
- Upgrade dependencies
|
||||
|
||||
## 2.0.0 (2020-03-01)
|
||||
|
||||
Stable release of v2, finally! 🎉
|
||||
|
||||
_This is just a version bump, see all the beta releases below, esspecially the first one, for a list of changes._
|
||||
_This is just a version bump, see all the beta releases below, especially the first one, for a list of changes._
|
||||
|
||||
## 2.0.0-beta.11 (2020-03-01)
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ directory as `docker-compose.yml`)
|
||||
|
||||
### Manually
|
||||
|
||||
- Run `yarn install --production` to install dependencies
|
||||
- Run `yarn install` to install dependencies
|
||||
- Run `yarn build` to compile and minify for production
|
||||
- Copy the content of the `dist/` directory to your webroot
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ COPY . ./
|
||||
RUN yarn build
|
||||
|
||||
FROM nginx:1.17-alpine
|
||||
LABEL version="2.0.0"
|
||||
LABEL version="2.1.0"
|
||||
LABEL description="OwnTracks UI"
|
||||
LABEL maintainer="Linus Groh <mail@linusgroh.de>"
|
||||
ENV LISTEN_PORT=80 \
|
||||
|
||||
13
package.json
13
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "owntracks-ui",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.0",
|
||||
"author": {
|
||||
"name": "Linus Groh",
|
||||
"email": "mail@linusgroh.de"
|
||||
@@ -26,12 +26,13 @@
|
||||
"vue": "^2.6.11",
|
||||
"vue-ctk-date-time-picker": "^2.4.0",
|
||||
"vue-feather-icons": "^5.0.0",
|
||||
"vue-i18n": "^8.15.4",
|
||||
"vue-i18n": "^8.15.5",
|
||||
"vue-js-modal": "^1.3.33",
|
||||
"vue-mq": "^1.0.1",
|
||||
"vue-outside-events": "^1.1.3",
|
||||
"vue-router": "^3.1.6",
|
||||
"vue2-leaflet": "^2.5.2",
|
||||
"vuex": "^3.1.2"
|
||||
"vuex": "^3.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^4.2.3",
|
||||
@@ -39,15 +40,15 @@
|
||||
"@vue/cli-plugin-unit-jest": "^4.2.3",
|
||||
"@vue/cli-service": "^4.2.3",
|
||||
"@vue/eslint-config-prettier": "^6.0.0",
|
||||
"@vue/test-utils": "1.0.0-beta.31",
|
||||
"@vue/test-utils": "1.0.0-beta.32",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^25.1.0",
|
||||
"cors-anywhere": "^0.4.1",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-prettier": "^3.1.2",
|
||||
"eslint-plugin-vue": "^6.2.1",
|
||||
"jest-fetch-mock": "^3.0.1",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"lint-staged": "^10.0.8",
|
||||
"moment-locales-webpack-plugin": "^1.1.2",
|
||||
"node-sass": "^4.13.1",
|
||||
|
||||
37
src/api.js
37
src/api.js
@@ -1,5 +1,5 @@
|
||||
import { log, logLevels } from "@/logging";
|
||||
import { getApiUrl } from "@/util";
|
||||
import { getApiUrl, getLocationHistoryCount } from "@/util";
|
||||
|
||||
/**
|
||||
* Fetch an API resource.
|
||||
@@ -24,6 +24,7 @@ export const getVersion = async () => {
|
||||
const response = await fetchApi("/api/0/version");
|
||||
const json = await response.json();
|
||||
const version = json.version;
|
||||
log("API", () => `[getVersion] ${version}`);
|
||||
return version;
|
||||
};
|
||||
|
||||
@@ -36,6 +37,7 @@ export const getUsers = async () => {
|
||||
const response = await fetchApi("/api/0/list");
|
||||
const json = await response.json();
|
||||
const users = json.results;
|
||||
log("API", () => `[getUsers] Fetched ${users.length} users`);
|
||||
return users;
|
||||
};
|
||||
|
||||
@@ -56,6 +58,15 @@ export const getDevices = async users => {
|
||||
devices[user] = userDevices;
|
||||
})
|
||||
);
|
||||
log("API", () => {
|
||||
const devicesCount = Object.keys(devices)
|
||||
.map(user => devices[user].length)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
return (
|
||||
`[getDevices] Fetched ${devicesCount} ` +
|
||||
`devices for ${users.length} users`
|
||||
);
|
||||
});
|
||||
return devices;
|
||||
};
|
||||
|
||||
@@ -76,7 +87,12 @@ export const getLastLocations = async (user, device) => {
|
||||
}
|
||||
const response = await fetchApi("/api/0/last", params);
|
||||
const json = await response.json();
|
||||
return json;
|
||||
const lastLocations = json;
|
||||
log(
|
||||
"API",
|
||||
() => `[getLastLocations] Fetched ${lastLocations.length} last locations`
|
||||
);
|
||||
return lastLocations;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -102,7 +118,15 @@ export const getUserDeviceLocationHistory = async (
|
||||
format: "json",
|
||||
});
|
||||
const json = await response.json();
|
||||
return json.data;
|
||||
const userDeviceLocationHistory = json.data;
|
||||
log(
|
||||
"API",
|
||||
() =>
|
||||
`[getUserDeviceLocationHistory] Fetched ` +
|
||||
`${userDeviceLocationHistory.length} locations for ` +
|
||||
`${user}/${device} from ${start} - ${end}`
|
||||
);
|
||||
return userDeviceLocationHistory;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -131,6 +155,13 @@ export const getLocationHistory = async (devices, start, end) => {
|
||||
);
|
||||
})
|
||||
);
|
||||
log("API", () => {
|
||||
const locationHistoryCount = getLocationHistoryCount(locationHistory);
|
||||
return (
|
||||
"[getLocationHistory] Fetched " +
|
||||
`${locationHistoryCount} locations in total`
|
||||
);
|
||||
});
|
||||
return locationHistory;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,25 @@
|
||||
<template>
|
||||
<header>
|
||||
<nav>
|
||||
<div v-if="$mq === 'sm'" class="header-item">
|
||||
<button
|
||||
class="button button-flat button-icon"
|
||||
@click="showMobileNav = !showMobileNav"
|
||||
>
|
||||
<MenuIcon size="1x" aria-hidden="true" role="img" />
|
||||
</button>
|
||||
</div>
|
||||
<nav
|
||||
v-if="$mq === 'sm' ? showMobileNav : true"
|
||||
class="header-item header-item-grow"
|
||||
:class="$mq === 'sm' ? 'nav-sm' : null"
|
||||
>
|
||||
<div class="nav-item">
|
||||
<CrosshairIcon
|
||||
v-if="$mq === 'sm'"
|
||||
size="1x"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
/>
|
||||
<button
|
||||
class="button button-outline"
|
||||
:title="
|
||||
@@ -46,7 +64,7 @@
|
||||
:title="$t('Select start date')"
|
||||
/>
|
||||
</VueCtkDateTimePicker>
|
||||
{{ $t("to") }}
|
||||
<span>{{ $t("to") }}</span>
|
||||
<VueCtkDateTimePicker
|
||||
v-model="endDateTime"
|
||||
:format="DATE_TIME_FORMAT"
|
||||
@@ -97,7 +115,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</nav>
|
||||
<nav class="nav-shrink">
|
||||
<nav class="header-item header-item-right">
|
||||
<div
|
||||
v-if="$config.showDistanceTravelled && distanceTravelled"
|
||||
class="nav-item"
|
||||
@@ -136,9 +154,11 @@ import moment from "moment";
|
||||
import { mapActions, mapGetters, mapMutations, mapState } from "vuex";
|
||||
import {
|
||||
CalendarIcon,
|
||||
CrosshairIcon,
|
||||
DownloadIcon,
|
||||
InfoIcon,
|
||||
LayersIcon,
|
||||
MenuIcon,
|
||||
SmartphoneIcon,
|
||||
UserIcon,
|
||||
} from "vue-feather-icons";
|
||||
@@ -153,9 +173,11 @@ import { humanReadableDistance } from "@/util";
|
||||
export default {
|
||||
components: {
|
||||
CalendarIcon,
|
||||
CrosshairIcon,
|
||||
DownloadIcon,
|
||||
InfoIcon,
|
||||
LayersIcon,
|
||||
MenuIcon,
|
||||
SmartphoneIcon,
|
||||
UserIcon,
|
||||
VueCtkDateTimePicker,
|
||||
@@ -170,6 +192,7 @@ export default {
|
||||
{ layer: "points", label: this.$t("Show location history (points)") },
|
||||
{ layer: "heatmap", label: this.$t("Show location heatmap") },
|
||||
],
|
||||
showMobileNav: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
19
src/components/LCustomMarker.js
Normal file
19
src/components/LCustomMarker.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/* eslint-disable max-len */
|
||||
const svg = `
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="691.429"
|
||||
height="1007.429"
|
||||
viewBox="0 0 182.94 266.549"
|
||||
>
|
||||
<path
|
||||
d="M182.94 91.47c0 50.518-55.748 139.357-91.47 175.079C55.75 230.827 0 141.988 0 91.47 0 40.953 40.953 0 91.47 0c50.518 0 91.47 40.953 91.47 91.47z"
|
||||
/>
|
||||
</svg>
|
||||
`;
|
||||
/* eslint-enable */
|
||||
|
||||
export default L.divIcon({
|
||||
className: "",
|
||||
html: `<span class="pin">${svg}</span>`,
|
||||
});
|
||||
3
src/index.d.ts
vendored
3
src/index.d.ts
vendored
@@ -204,6 +204,9 @@ interface QueryParams {
|
||||
/** Callback for new WebSocket location messages. */
|
||||
interface WebSocketLocationCallback { (): void }
|
||||
|
||||
/** Function for lazy evaluation of log messages. */
|
||||
interface LogMessageFunction { (): string }
|
||||
|
||||
/** A CSS color. */
|
||||
type Color = string;
|
||||
|
||||
|
||||
@@ -20,6 +20,16 @@ const logColors = {
|
||||
[logLevels.ERROR]: "#ad1515",
|
||||
};
|
||||
|
||||
/**
|
||||
* Log a message to the browser's console.
|
||||
*
|
||||
* Convenience wrapper for `console.{info,warn,error}` doing some formatting
|
||||
* and taking the `verbose` config option into account.
|
||||
*
|
||||
* @param {String} label Log message label, useful for filtering
|
||||
* @param {String|LogMessageFunction} message Log message
|
||||
* @param {String} [level] Log level, use `logLevels` constants
|
||||
*/
|
||||
export const log = (label, message, level = logLevels.INFO) => {
|
||||
if (!Object.keys(logLevels).includes(level)) {
|
||||
log("WARNING", `invalid log level: ${level}`, logLevels.WARNING);
|
||||
@@ -35,5 +45,9 @@ export const log = (label, message, level = logLevels.INFO) => {
|
||||
padding: 3px;
|
||||
`;
|
||||
const logFunc = logFunctions[level];
|
||||
logFunc(`%c${label}`, css, message);
|
||||
logFunc(
|
||||
`%c${label}`,
|
||||
css,
|
||||
typeof message === "function" ? message() : message
|
||||
);
|
||||
};
|
||||
|
||||
19
src/main.js
19
src/main.js
@@ -1,17 +1,28 @@
|
||||
import Vue from "vue";
|
||||
import VueModal from "vue-js-modal";
|
||||
import VueOutsideEvents from "vue-outside-events";
|
||||
import VueMq from "vue-mq";
|
||||
|
||||
import App from "@/App.vue";
|
||||
import config from "@/config";
|
||||
import { log } from "@/logging";
|
||||
import i18n from "@/i18n";
|
||||
import router from "@/router";
|
||||
import store from "@/store";
|
||||
import VModal from "vue-js-modal";
|
||||
import VOutsideEvents from "vue-outside-events";
|
||||
|
||||
Vue.use(VModal);
|
||||
Vue.use(VOutsideEvents);
|
||||
Vue.use(VueModal);
|
||||
Vue.use(VueOutsideEvents);
|
||||
Vue.use(VueMq, {
|
||||
breakpoints: {
|
||||
sm: 1300,
|
||||
lg: Infinity,
|
||||
},
|
||||
});
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
log("CONFIG", config);
|
||||
|
||||
Vue.prototype.$config = config;
|
||||
|
||||
new Vue({
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import * as types from "@/store/mutation-types";
|
||||
import * as api from "@/api";
|
||||
import config from "@/config";
|
||||
import { distanceBetweenCoordinates, isIsoDateTime } from "@/util";
|
||||
import { log } from "@/logging";
|
||||
import {
|
||||
distanceBetweenCoordinates,
|
||||
isIsoDateTime,
|
||||
getLocationHistoryCount,
|
||||
} from "@/util";
|
||||
|
||||
/**
|
||||
* Populate the state from URL query parameters.
|
||||
@@ -118,6 +123,7 @@ const getLastLocations = async ({ commit, state }) => {
|
||||
};
|
||||
|
||||
const _getDistanceTravelled = locationHistory => {
|
||||
const start = Date.now();
|
||||
let distanceTravelled = 0;
|
||||
Object.keys(locationHistory).forEach(user => {
|
||||
Object.keys(locationHistory[user]).forEach(device => {
|
||||
@@ -143,6 +149,15 @@ const _getDistanceTravelled = locationHistory => {
|
||||
});
|
||||
});
|
||||
});
|
||||
const end = Date.now();
|
||||
log("DISTANCE", () => {
|
||||
const locationHistoryCount = getLocationHistoryCount(locationHistory);
|
||||
const duration = (end - start) / 1000;
|
||||
return (
|
||||
`[_getDistanceTravelled] Took ${duration} seconds to ` +
|
||||
`calculate distance of ${locationHistoryCount} locations`
|
||||
);
|
||||
});
|
||||
return distanceTravelled;
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { distanceBetweenCoordinates } from "@/util";
|
||||
* array of all coordinates.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {MultiLocationHistory} state.locationHistory
|
||||
* @param {LocationHistory} state.locationHistory
|
||||
* Location history of selected users and devices
|
||||
* @returns {L.LatLng[]} All coordinates
|
||||
*/
|
||||
@@ -30,7 +30,7 @@ const locationHistoryLatLngs = state => {
|
||||
* coordinates does not exceed `config.map.maxPointDistance`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @param {MultiLocationHistory} state.locationHistory
|
||||
* @param {LocationHistory} state.locationHistory
|
||||
* Location history of selected users and devices
|
||||
* @returns {L.LatLng[][]} Groups of coherent coordinates
|
||||
*/
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
--color-primary-text: #fff;
|
||||
--drop-shadow: drop-shadow(0 10px 10px rgb(0, 0, 0, 0.2));
|
||||
--dropdown-arrow: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2225%22%20height%3D%2210%22%3E%3Cpath%20fill%3D%22%23333%22%20fill-opacity%3D%221%22%20stroke%3D%22none%22%20d%3D%22M0%2C0%20L0%2C0%20L1%2C0%20L1%2C6%20L7%2C6%20L7%2C7%20L0%2C7%20z%22%20transform%3D%22rotate(-45%205%200)%22%20%2F%3E%3C%2Fsvg%3E");
|
||||
--pin-width: 32px;
|
||||
}
|
||||
|
||||
html, body {
|
||||
@@ -105,30 +106,75 @@ pre {
|
||||
color: var(--color-primary-text);
|
||||
background: var(--color-primary);
|
||||
|
||||
nav {
|
||||
.header-item {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
&.nav-shrink {
|
||||
flex: 0 1 auto;
|
||||
&-grow {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nav-item:not(:first-child) {
|
||||
margin-left: 20px;
|
||||
&-right {
|
||||
margin-left: auto !important;
|
||||
}
|
||||
|
||||
.feather {
|
||||
font-size: 20px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.button-icon .feather {
|
||||
.nav-item {
|
||||
&:not(:first-child) {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
> span {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.feather {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.button-icon .feather {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.nav-sm {
|
||||
background: var(--color-primary);
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.2);
|
||||
bottom: 0;
|
||||
display: block;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
overflow-x: auto;
|
||||
padding: 30px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 76px;
|
||||
z-index: 1;
|
||||
|
||||
.nav-item {
|
||||
&:not(:first-child) {
|
||||
margin-left: 0;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
> span {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// THIS IS TERRIBLE (but it works for now)
|
||||
> :not(:nth-child(1)):not(:nth-child(2)) {
|
||||
display: block;
|
||||
margin-left: 30px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,8 +218,8 @@ pre {
|
||||
overflow: hidden;
|
||||
padding: 8px 16px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
transition: box-shadow 0.2s;
|
||||
white-space: nowrap;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
|
||||
@@ -6,5 +6,14 @@
|
||||
box-shadow: none !important;
|
||||
filter: var(--drop-shadow);
|
||||
margin-top: 5px;
|
||||
|
||||
@media screen and (max-width: 415px) {
|
||||
// Fix buttons being off screen
|
||||
.datepicker-buttons-container {
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
.leaflet-popup {
|
||||
filter: var(--drop-shadow);
|
||||
margin-bottom: 25px;
|
||||
margin-bottom: calc(var(--pin-width) * 1.5 + 20px);
|
||||
|
||||
.leaflet-popup-content-wrapper {
|
||||
border-radius: 3px;
|
||||
@@ -44,4 +44,38 @@
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.leaflet-marker-icon {
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
margin: 0 !important;
|
||||
|
||||
.pin {
|
||||
display: block;
|
||||
margin-left: calc(-1 * var(--pin-width) / 2);
|
||||
margin-top: calc(-1 * var(--pin-width) * 1.5);
|
||||
position: relative;
|
||||
width: var(--pin-width);
|
||||
|
||||
&::before {
|
||||
background: var(--color-background);
|
||||
border-radius: 100%;
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: calc(var(--pin-width) / 2);
|
||||
height: calc(var(--pin-width) / 2);
|
||||
top: calc(var(--pin-width) / 4);
|
||||
left: calc(var(--pin-width) / 4);
|
||||
}
|
||||
|
||||
svg {
|
||||
height: auto;
|
||||
width: 100%;
|
||||
|
||||
path {
|
||||
fill: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
15
src/util.js
15
src/util.js
@@ -101,3 +101,18 @@ export const humanReadableDistance = distance => {
|
||||
maximumFractionDigits: 1,
|
||||
})} ${unit}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the total number of locations from a nested location history.
|
||||
*
|
||||
* @param {LocationHistory} locationHistory Location history
|
||||
* @returns {Number} Total number of locations
|
||||
*/
|
||||
export const getLocationHistoryCount = locationHistory =>
|
||||
Object.keys(locationHistory)
|
||||
.map(user =>
|
||||
Object.keys(locationHistory[user])
|
||||
.map(device => locationHistory[user][device].length)
|
||||
.reduce((a, b) => a + b, 0)
|
||||
)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
v-for="l in lastLocations"
|
||||
:key="`${l.topic}-marker`"
|
||||
:lat-lng="[l.lat, l.lon]"
|
||||
:icon="markerIcon"
|
||||
>
|
||||
<LDeviceLocationPopup
|
||||
:user="l.username"
|
||||
@@ -119,22 +120,11 @@ import {
|
||||
LPolyline,
|
||||
} from "vue2-leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import markerIcon from "leaflet/dist/images/marker-icon.png";
|
||||
import markerIcon2x from "leaflet/dist/images/marker-icon-2x.png";
|
||||
import markerShadow from "leaflet/dist/images/marker-shadow.png";
|
||||
|
||||
import * as types from "@/store/mutation-types";
|
||||
import LCustomMarker from "@/components/LCustomMarker";
|
||||
import LHeatmap from "@/components/LHeatmap";
|
||||
import LDeviceLocationPopup from "@/components/LDeviceLocationPopup";
|
||||
|
||||
// See https://github.com/KoRiGaN/Vue2Leaflet/issues/28#issuecomment-299038157
|
||||
delete L.Icon.Default.prototype._getIconUrl;
|
||||
L.Icon.Default.mergeOptions({
|
||||
iconUrl: markerIcon,
|
||||
iconRetinaUrl: markerIcon2x,
|
||||
shadowUrl: markerShadow,
|
||||
});
|
||||
|
||||
export default {
|
||||
components: {
|
||||
LMap,
|
||||
@@ -154,6 +144,7 @@ export default {
|
||||
center: this.$store.state.map.center,
|
||||
controls: this.$config.map.controls,
|
||||
heatmap: this.$config.map.heatmap,
|
||||
markerIcon: LCustomMarker,
|
||||
maxZoom: this.$config.map.maxZoom,
|
||||
maxNativeZoom: this.$config.map.maxNativeZoom,
|
||||
url: this.$config.map.url,
|
||||
@@ -215,8 +206,8 @@ export default {
|
||||
*
|
||||
* @param {User} user Username
|
||||
* @param {Device} device Device name
|
||||
* @param {LocationHistory} deviceLocations Device name
|
||||
* @returns {LocationHistory} Updated location history
|
||||
* @param {OTLocation[]} deviceLocations Device name
|
||||
* @returns {OTLocation[]} Updated locations
|
||||
*/
|
||||
deviceLocationsWithNameAndFace(user, device, deviceLocations) {
|
||||
const lastLocation = this.lastLocations.find(
|
||||
|
||||
65
yarn.lock
65
yarn.lock
@@ -1752,10 +1752,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.1.tgz#18723530d304f443021da2292d6ec9502826104a"
|
||||
integrity sha512-8VCoJeeH8tCkzhkpfOkt+abALQkS11OIHhte5MBzYaKMTqK0A3ZAKEUVAffsOklhEv7t0yrQt696Opnu9oAx+w==
|
||||
|
||||
"@vue/test-utils@1.0.0-beta.31":
|
||||
version "1.0.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.0.0-beta.31.tgz#580d6e45f07452e497d69807d80986e713949b73"
|
||||
integrity sha512-IlhSx5hyEVnbvDZ3P98R1jNmy88QAd/y66Upn4EcvxSD5D4hwOutl3dIdfmSTSXs4b9DIMDnEVjX7t00cvOnvg==
|
||||
"@vue/test-utils@1.0.0-beta.32":
|
||||
version "1.0.0-beta.32"
|
||||
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.0.0-beta.32.tgz#38c3947886236201a3f24b583c73598eb95ccc69"
|
||||
integrity sha512-ywhe7PATMAk/ZGdsrcuQIliQusOyfe0OOHjKKCCERqgHh1g/kqPtmSMT5Jx4sErx53SYbNucr8QOK6/u5ianAw==
|
||||
dependencies:
|
||||
dom-event-types "^1.0.0"
|
||||
lodash "^4.17.15"
|
||||
@@ -1964,9 +1964,9 @@ acorn-walk@^7.0.0:
|
||||
integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==
|
||||
|
||||
acorn@^5.5.3:
|
||||
version "5.7.3"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
|
||||
integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
|
||||
version "5.7.4"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
|
||||
integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==
|
||||
|
||||
acorn@^6.0.1, acorn@^6.0.7, acorn@^6.2.1:
|
||||
version "6.3.0"
|
||||
@@ -4410,10 +4410,10 @@ eslint-plugin-prettier@^3.1.2:
|
||||
dependencies:
|
||||
prettier-linter-helpers "^1.0.0"
|
||||
|
||||
eslint-plugin-vue@^6.2.1:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-6.2.1.tgz#ca802df5c33146aed1e56bb21d250c1abb6120a3"
|
||||
integrity sha512-MiIDOotoWseIfLIfGeDzF6sDvHkVvGd2JgkvjyHtN3q4RoxdAXrAMuI3SXTOKatljgacKwpNAYShmcKZa4yZzw==
|
||||
eslint-plugin-vue@^6.2.2:
|
||||
version "6.2.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-6.2.2.tgz#27fecd9a3a24789b0f111ecdd540a9e56198e0fe"
|
||||
integrity sha512-Nhc+oVAHm0uz/PkJAWscwIT4ijTrK5fqNqz9QB1D35SbbuMG1uB6Yr5AJpvPSWg+WOw7nYNswerYh0kOk64gqQ==
|
||||
dependencies:
|
||||
natural-compare "^1.4.0"
|
||||
semver "^5.6.0"
|
||||
@@ -6392,10 +6392,10 @@ jest-environment-node@^24.9.0:
|
||||
jest-mock "^24.9.0"
|
||||
jest-util "^24.9.0"
|
||||
|
||||
jest-fetch-mock@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-fetch-mock/-/jest-fetch-mock-3.0.1.tgz#4dde94c9e91fa76bceb6001f54e33039f1f02da6"
|
||||
integrity sha512-R5GVbQLVjk+PCfzf4vFoYDXt+oCEWuYigyaAnucdeVCXkElAgAYXDFFikHxLyCVjSNDc7TCYQZ1ItLNOE6OCrQ==
|
||||
jest-fetch-mock@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz#31749c456ae27b8919d69824f1c2bd85fe0a1f3b"
|
||||
integrity sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==
|
||||
dependencies:
|
||||
cross-fetch "^3.0.4"
|
||||
promise-polyfill "^8.1.3"
|
||||
@@ -6873,6 +6873,13 @@ json-stringify-safe@~5.0.1:
|
||||
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
||||
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
||||
|
||||
json2mq@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a"
|
||||
integrity sha1-tje9O6nqvhIsg+lyBIOusQ0skEo=
|
||||
dependencies:
|
||||
string-convert "^0.2.0"
|
||||
|
||||
json3@^3.3.2:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81"
|
||||
@@ -10255,6 +10262,11 @@ string-argv@0.3.1:
|
||||
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da"
|
||||
integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==
|
||||
|
||||
string-convert@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97"
|
||||
integrity sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c=
|
||||
|
||||
string-length@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed"
|
||||
@@ -11182,10 +11194,10 @@ vue-i18n@^8.0.0:
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.15.1.tgz#90097a08a1e932f645c6b9c404c780d24f6d6224"
|
||||
integrity sha512-GBbz8qYCu0U2LNu4IcuFLZiuyninG4k26knvhL7GZG5Ncp4RR2VKDEH6g8gQ6I+UUBCvH2MBQVPSdxWe4DBkPw==
|
||||
|
||||
vue-i18n@^8.15.4:
|
||||
version "8.15.4"
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.15.4.tgz#1bfba2b6a6cb6de7b44f0f0aa89ad775fc902bc2"
|
||||
integrity sha512-brhbJRB/gyWlroAhQZU0TNTQzNonbkHmzH4HlJzs7c+DsVIhB5OlRHg3zAl+85kkT8mpxzvBE6Bm1slqnRRmsg==
|
||||
vue-i18n@^8.15.5:
|
||||
version "8.15.5"
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.15.5.tgz#e39e4724c88ec38ef72217de325e8b10a35718cf"
|
||||
integrity sha512-lIej02+w8lP0k1PEN1xtXqKpQ1hDh17zvDF+7Oc2qJi+cTMDlfPM771w4euVaHO67AxEz4WL9MIgkyn3tkeCtQ==
|
||||
|
||||
vue-jest@^3.0.5:
|
||||
version "3.0.5"
|
||||
@@ -11219,6 +11231,13 @@ vue-loader@^15.8.3:
|
||||
vue-hot-reload-api "^2.3.0"
|
||||
vue-style-loader "^4.1.0"
|
||||
|
||||
vue-mq@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-mq/-/vue-mq-1.0.1.tgz#ee7dec5a0f50b4e2edbacd8ed43c57e15a072989"
|
||||
integrity sha512-FceZ1tFE0MZ8GroRBKPQWBRy4ZEAa7p5R7cGAzJpGuKPU2AI4ClmE+S6O/yV4jO5271o9tgaUFt7fzUAIf9xOQ==
|
||||
dependencies:
|
||||
json2mq "^0.2.0"
|
||||
|
||||
vue-outside-events@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/vue-outside-events/-/vue-outside-events-1.1.3.tgz#75b3e3b7856590fbe4455c87075b54f92b2a9654"
|
||||
@@ -11265,10 +11284,10 @@ vue@^2.6.11, vue@^2.6.9:
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5"
|
||||
integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==
|
||||
|
||||
vuex@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.2.tgz#a2863f4005aa73f2587e55c3fadf3f01f69c7d4d"
|
||||
integrity sha512-ha3jNLJqNhhrAemDXcmMJMKf1Zu4sybMPr9KxJIuOpVcsDQlTBYLLladav2U+g1AvdYDG5Gs0xBTb0M5pXXYFQ==
|
||||
vuex@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.3.tgz#f2ad73e3fb73691698b38c93f66e58e267947180"
|
||||
integrity sha512-k8vZqNMSNMgKelVZAPYw5MNb2xWSmVgCKtYKAptvm9YtZiOXnRXFWu//Y9zQNORTrm3dNj1n/WaZZI26tIX6Mw==
|
||||
|
||||
w3c-hr-time@^1.0.1:
|
||||
version "1.0.1"
|
||||
|
||||
Reference in New Issue
Block a user