mirror of
https://github.com/owntracks/frontend.git
synced 2026-04-19 01:56:38 +00:00
Merge pull request #20 from owntracks/clean-up-the-typing-mess
Clean up the typing mess
This commit is contained in:
31
src/api.js
31
src/api.js
@@ -1,23 +1,11 @@
|
||||
import { log, logLevels } from "@/logging";
|
||||
import { getApiUrl } from "@/util";
|
||||
|
||||
/** @typedef {import("./types").QueryParams} QueryParams */
|
||||
/** @typedef {import("./types").User} User */
|
||||
/** @typedef {import("./types").Device} Device */
|
||||
/** @typedef {import("./types").LastLocation} LastLocation */
|
||||
/** @typedef {import("./types").LocationHistory} LocationHistory */
|
||||
|
||||
/**
|
||||
* Callback for new WebSocket location messages.
|
||||
*
|
||||
* @callback webSocketLocationCallback
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fetch an API resource.
|
||||
*
|
||||
* @param {String} path API resource path
|
||||
* @param {QueryParams} [params] Query parameters
|
||||
* @param {Object} [params] Query parameters
|
||||
* @returns {Promise} Promise returned by the fetch function
|
||||
*/
|
||||
const fetchApi = (path, params = {}) => {
|
||||
@@ -42,7 +30,7 @@ export const getVersion = async () => {
|
||||
/**
|
||||
* Get all users.
|
||||
*
|
||||
* @returns {Array.<User>} Array of usernames
|
||||
* @returns {User[]} Array of usernames
|
||||
*/
|
||||
export const getUsers = async () => {
|
||||
const response = await fetchApi("/api/0/list");
|
||||
@@ -54,8 +42,8 @@ export const getUsers = async () => {
|
||||
/**
|
||||
* Get all devices for the provided users.
|
||||
*
|
||||
* @param {Array.<User>} users Array of usernames
|
||||
* @returns {Object.<User, Array.<Device>>}
|
||||
* @param {User[]} users Array of usernames
|
||||
* @returns {{User: Device[]}}
|
||||
* Object mapping each username to an array of device names
|
||||
*/
|
||||
export const getDevices = async users => {
|
||||
@@ -76,7 +64,7 @@ export const getDevices = async users => {
|
||||
*
|
||||
* @param {User} [user] Get last locations of all devices from this user
|
||||
* @param {Device} [device] Get last location of specific device
|
||||
* @returns {Array.<LastLocation>} Array of last location objects
|
||||
* @returns {OTLocation[]} Array of last location objects
|
||||
*/
|
||||
export const getLastLocations = async (user, device) => {
|
||||
const params = {};
|
||||
@@ -98,7 +86,7 @@ export const getLastLocations = async (user, device) => {
|
||||
* @param {Device} device Device name
|
||||
* @param {String} start Start date and time in UTC
|
||||
* @param {String} end End date and time in UTC
|
||||
* @returns {LocationHistory} Array of location history objects
|
||||
* @returns {OTLocation[]} Array of location history objects
|
||||
*/
|
||||
export const getUserDeviceLocationHistory = async (
|
||||
user,
|
||||
@@ -120,12 +108,11 @@ export const getUserDeviceLocationHistory = async (
|
||||
/**
|
||||
* Get the location history of multiple devices.
|
||||
*
|
||||
* @param {Object.<User, Array.<Device>>} devices
|
||||
* @param {{User: Device[]}} devices
|
||||
* Devices of which the history should be fetched
|
||||
* @param {String} start Start date and time in UTC
|
||||
* @param {String} end End date and time in UTC
|
||||
* @returns {Object.<User, Object.<Device, LocationHistory>>}
|
||||
* Array of location history objects
|
||||
* @returns {LocationHistory} Location history
|
||||
*/
|
||||
export const getLocationHistory = async (devices, start, end) => {
|
||||
const locationHistory = {};
|
||||
@@ -151,7 +138,7 @@ export const getLocationHistory = async (devices, start, end) => {
|
||||
* Connect to the WebSocket API, reconnect when necessary and handle received
|
||||
* messages.
|
||||
*
|
||||
* @param {webSocketLocationCallback} [callback] Callback for location messages
|
||||
* @param {WebSocketLocationCallback} [callback] Callback for location messages
|
||||
*/
|
||||
export const connectWebsocket = async callback => {
|
||||
let url = getApiUrl("/ws/last");
|
||||
|
||||
220
src/index.d.ts
vendored
Normal file
220
src/index.d.ts
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
/** Configuration object. */
|
||||
interface Config {
|
||||
api: {
|
||||
baseUrl: string;
|
||||
};
|
||||
endDateTime: Date;
|
||||
ignorePingLocation: boolean;
|
||||
locale: string;
|
||||
map: {
|
||||
attribution: string;
|
||||
circle: {
|
||||
color: OptionalColor;
|
||||
fillColor: OptionalColor;
|
||||
fillOpacity: number;
|
||||
};
|
||||
circleMarker: {
|
||||
color: OptionalColor;
|
||||
fillColor: OptionalColor;
|
||||
fillOpacity: number;
|
||||
radius: number;
|
||||
};
|
||||
controls: {
|
||||
scale: {
|
||||
display: boolean;
|
||||
imperial: boolean;
|
||||
maxWidth: number;
|
||||
metric: boolean;
|
||||
position: string;
|
||||
};
|
||||
zoom: {
|
||||
display: boolean;
|
||||
position: string;
|
||||
};
|
||||
};
|
||||
heatmap: {
|
||||
blur: number;
|
||||
gradient: { number: Color } | null;
|
||||
max: number;
|
||||
radius: number;
|
||||
};
|
||||
layers: {
|
||||
heatmap: boolean;
|
||||
last: boolean;
|
||||
line: boolean;
|
||||
points: boolean;
|
||||
};
|
||||
maxNativeZoom: number;
|
||||
maxPointDistance: number | null;
|
||||
maxZoom: number;
|
||||
polyline: {
|
||||
color: OptionalColor;
|
||||
fillColor: OptionalColor;
|
||||
};
|
||||
url: string;
|
||||
};
|
||||
onLocationChange: {
|
||||
reloadHistory: boolean;
|
||||
};
|
||||
primaryColor: Color;
|
||||
selectedUser: User| null;
|
||||
selectedDevice: Device| null;
|
||||
startDateTime: Date;
|
||||
verbose: boolean;
|
||||
}
|
||||
|
||||
/** Vuex state. */
|
||||
interface State {
|
||||
isLoading: boolean;
|
||||
frontendVersion: string;
|
||||
recorderVersion: string;
|
||||
users: User[];
|
||||
devices: { User: Device[] };
|
||||
lastLocations: OTLocation[];
|
||||
locationHistory: LocationHistory;
|
||||
selectedUser: User| null;
|
||||
selectedDevice: Device| null;
|
||||
startDateTime: string;
|
||||
endDateTime: string;
|
||||
map: {
|
||||
center: {
|
||||
lat: number;
|
||||
lng: number;
|
||||
};
|
||||
layers: {
|
||||
heatmap: boolean;
|
||||
last: boolean;
|
||||
line: boolean;
|
||||
points: boolean;
|
||||
};
|
||||
zoom: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A location object as returned by the OwnTracks recorder.
|
||||
* https://owntracks.org/booklet/tech/json/#_typelocation
|
||||
*/
|
||||
interface OTLocation {
|
||||
_http: boolean;
|
||||
/**
|
||||
* In this case always "location"
|
||||
* https://owntracks.org/booklet/tech/json/#types
|
||||
*/
|
||||
_type: string;
|
||||
/** Accuracy in meters */
|
||||
acc?: number;
|
||||
/** Altitude above sea level in meters */
|
||||
alt?: number;
|
||||
/** Device battery level in percent */
|
||||
batt?: number;
|
||||
/**
|
||||
* Battery status (iOS only)
|
||||
*
|
||||
* - `0` = unknown
|
||||
* - `1` = unplugged
|
||||
* - `2` = charging
|
||||
* - `3` = full
|
||||
*/
|
||||
bs?: number;
|
||||
/** Course over ground in degrees (iOS only) */
|
||||
cog?: number;
|
||||
/**
|
||||
* Internet connectivity status (route to host) when the message is created
|
||||
*
|
||||
* - `"w"` = phone is connected to a WiFi connection
|
||||
* - `"o"` = phone is offline
|
||||
* - `"m"` = mobile data
|
||||
*/
|
||||
conn?: string;
|
||||
/** Device name */
|
||||
device?: Device;
|
||||
/** Timestamp in a readable format */
|
||||
disptst: string;
|
||||
/** Base64-encoded face image (device icon) */
|
||||
face?: string;
|
||||
/**
|
||||
* Geohash of the location
|
||||
* https://en.wikipedia.org/wiki/Geohash
|
||||
*/
|
||||
ghash?: string;
|
||||
/** Regions the device is currently in (e.g. `["Home", "Garage"]`). Might be empty. */
|
||||
inregions?: string[];
|
||||
/**
|
||||
* No idea; some kind of timestamp as well - figure it out yourself. :)
|
||||
* https://github.com/owntracks/recorder/blob/df009f791a845012e9cce24923e6203a079ca1ed/storage.c#L659
|
||||
* https://github.com/owntracks/recorder/blob/df009f791a845012e9cce24923e6203a079ca1ed/storage.c#L704
|
||||
*/
|
||||
isorcv?: string;
|
||||
/** ISO 8601 timestamp */
|
||||
isotst?: string;
|
||||
/** Latitude in degrees */
|
||||
lat: number;
|
||||
/** Longitude in degrees */
|
||||
lon: number;
|
||||
/** Friendly device name */
|
||||
name?: string;
|
||||
/**
|
||||
* Trigger for the location report
|
||||
*
|
||||
* - `"p"` = ping issued randomly by background task
|
||||
* - `"c"` = circular region enter/leave event
|
||||
* - `"b"` = beacon region enter/leave event (iOS only)
|
||||
* - `"r"` = response to a reportLocation cmd message
|
||||
* - `"u"` = manual publish requested by the user
|
||||
* - `"t"` = timer based publish in move move (iOS only)
|
||||
* - `"v"` = updated by Settings/Privacy/Locations Services/System Services/Frequent Locations monitoring (iOS only)
|
||||
*/
|
||||
t?: string;
|
||||
/** Tracker ID used to display the initials of a user */
|
||||
tid?: string;
|
||||
/**
|
||||
* Original publish topic
|
||||
* https://owntracks.org/booklet/tech/json/#topics
|
||||
*/
|
||||
topic?: string;
|
||||
/** UNIX epoch timestamp of the location fix in seconds */
|
||||
tst: number;
|
||||
/** User */
|
||||
username?: User;
|
||||
/** Vertical accuracy of the alt element in meters */
|
||||
vac?: number;
|
||||
/** Velocity in km/h */
|
||||
vel?: number;
|
||||
}
|
||||
|
||||
/** URL query parameters (prior to any parsing so it's all strings). */
|
||||
interface QueryParams {
|
||||
/** Map center latitude */
|
||||
lat?: string;
|
||||
/** Map center longitude */
|
||||
lng?: string;
|
||||
/** Start date and time of selected time range */
|
||||
start?: string;
|
||||
/** End date and time of selected time range */
|
||||
end?: string;
|
||||
/** Selected user */
|
||||
user?: string;
|
||||
/** Selected device */
|
||||
device?: string;
|
||||
/** Comma-separated list of active layers */
|
||||
layers?: string;
|
||||
}
|
||||
|
||||
/** Callback for new WebSocket location messages. */
|
||||
interface WebSocketLocationCallback { (): void }
|
||||
|
||||
/** A CSS color. */
|
||||
type Color = string;
|
||||
|
||||
/** A CSS color that will use `primaryColor` as fallback. */
|
||||
type OptionalColor = Color | null;
|
||||
|
||||
/** A user's name. */
|
||||
type User = string;
|
||||
|
||||
/** A device's name. */
|
||||
type Device = string;
|
||||
|
||||
/** Multiple location histories mapped to user and devices. */
|
||||
type LocationHistory = { User: { Device: OTLocation[] } };
|
||||
@@ -3,10 +3,6 @@ import * as api from "@/api";
|
||||
import config from "@/config";
|
||||
import { distanceBetweenCoordinates, isIsoDateTime } from "@/util";
|
||||
|
||||
/** @typedef {import("./types").QueryParams} QueryParams */
|
||||
/** @typedef {import("./types").User} User */
|
||||
/** @typedef {import("./types").Device} Device */
|
||||
|
||||
/**
|
||||
* Populate the state from URL query parameters.
|
||||
*
|
||||
|
||||
@@ -3,10 +3,6 @@ import L from "leaflet";
|
||||
import config from "@/config";
|
||||
import { distanceBetweenCoordinates } from "@/util";
|
||||
|
||||
/** @typedef {import("./types").State} State */
|
||||
/** @typedef {import("./types").MultiLocationHistory} MultiLocationHistory */
|
||||
/** @typedef {import("./types").DatepickerConfig} DatepickerConfig */
|
||||
|
||||
/**
|
||||
* From the selected users' and devices' location histories, create an
|
||||
* array of all coordinates.
|
||||
@@ -14,7 +10,7 @@ import { distanceBetweenCoordinates } from "@/util";
|
||||
* @param {State} state
|
||||
* @param {MultiLocationHistory} state.locationHistory
|
||||
* Location history of selected users and devices
|
||||
* @returns {Array.<L.LatLng>} All coordinates
|
||||
* @returns {L.LatLng[]} All coordinates
|
||||
*/
|
||||
const locationHistoryLatLngs = state => {
|
||||
const latLngs = [];
|
||||
@@ -36,7 +32,7 @@ const locationHistoryLatLngs = state => {
|
||||
* @param {State} state
|
||||
* @param {MultiLocationHistory} state.locationHistory
|
||||
* Location history of selected users and devices
|
||||
* @returns {Array.<Array.<L.LatLng>>} Groups of coherent coordinates
|
||||
* @returns {L.LatLng[][]} Groups of coherent coordinates
|
||||
*/
|
||||
const locationHistoryLatLngGroups = state => {
|
||||
const groups = [];
|
||||
|
||||
57
src/types.js
57
src/types.js
@@ -1,57 +0,0 @@
|
||||
/* eslint max-len: 0 */
|
||||
|
||||
/**
|
||||
* A coordinate with latitude and longitude.
|
||||
*
|
||||
* @typedef Coordinate
|
||||
* @type {(Object|L.LatLng)}
|
||||
* @property {Number} lat Latitude
|
||||
* @property {Number} lng Longitude
|
||||
*/
|
||||
|
||||
/**
|
||||
* Vuex state.
|
||||
*
|
||||
* @typedef {Object.<String, *>} State
|
||||
*/
|
||||
|
||||
/**
|
||||
* URL query parameter object.
|
||||
*
|
||||
* @typedef {Object.<String, *>} QueryParams
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} DatepickerConfig
|
||||
* @property {Function} DatepickerConfig.customPredictor Custom predictor function
|
||||
*/
|
||||
|
||||
/**
|
||||
* A user's name.
|
||||
*
|
||||
* @typedef {String} User
|
||||
*/
|
||||
|
||||
/**
|
||||
* A device's name.
|
||||
*
|
||||
* @typedef {String} Device
|
||||
*/
|
||||
|
||||
/**
|
||||
* A last location object.
|
||||
*
|
||||
* @typedef {Object.<String, *>} LastLocation
|
||||
*/
|
||||
|
||||
/**
|
||||
* An array of location history objects
|
||||
*
|
||||
* @typedef {Array.<Object.<String, *>>} LocationHistory
|
||||
*/
|
||||
|
||||
/**
|
||||
* Multiple arrays of location history objects mapped to user and devices.
|
||||
*
|
||||
* @typedef {Object.<User, Object.<Device, LocationHistory>>} MultiLocationHistory
|
||||
*/
|
||||
@@ -3,8 +3,6 @@ import moment from "moment";
|
||||
import config from "@/config";
|
||||
import { DATE_TIME_FORMAT, EARTH_RADIUS_IN_KM } from "@/constants";
|
||||
|
||||
/** @typedef {import("./types").Coordinate} Coordinate */
|
||||
|
||||
/**
|
||||
* Get a complete URL for any API resource, taking the
|
||||
* base URL configuration into account.
|
||||
|
||||
Reference in New Issue
Block a user