Merge pull request #66 from Fisker-Inc/car-location-visualizer

CEC-337: car location visualizer
This commit is contained in:
Drew Taylor
2021-07-22 11:53:11 -07:00
committed by GitHub
31 changed files with 1123 additions and 509 deletions

8
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,8 @@
# default codeowners
* jwu@fiskerinc.com dtaylor@fiskerinc.com ggetsin@fiskerinc.com
# devops
.github rgreenberg@fiskerinc.com jwu@fiskerinc.com dtaylor@fiskerinc.com ggetsin@fiskerinc.com
Jenkinsfile rgreenberg@fiskerinc.com jwu@fiskerinc.com dtaylor@fiskerinc.com ggetsin@fiskerinc.com
k8s rgreenberg@fiskerinc.com jwu@fiskerinc.com dtaylor@fiskerinc.com ggetsin@fiskerinc.com
Dockerfile rgreenberg@fiskerinc.com jwu@fiskerinc.com dtaylor@fiskerinc.com ggetsin@fiskerinc.com

View File

@@ -9,7 +9,7 @@ jobs:
strategy:
matrix:
node-version: [12.x]
node-version: [14.x]
steps:
- uses: actions/checkout@v2

View File

@@ -1,4 +1,4 @@
FROM node:12-alpine as builder
FROM node:14-alpine as builder
COPY package*.json ./
RUN npm install

View File

@@ -1,4 +1,4 @@
FROM node:12-alpine as builder
FROM node:14-alpine as builder
COPY package*.json ./
RUN npm install

View File

@@ -6,7 +6,7 @@ Front-end web application for administrating services
Running locally
1. Install Node 12
1. Install Node 14
2. Run `npm install`
3. Copy .env.template to .env and edit the service urls for authentication and api services
4. Run `./run.sh` from the terminal

220
package-lock.json generated
View File

@@ -1275,9 +1275,9 @@
"integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg=="
},
"@datadog/browser-core": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/@datadog/browser-core/-/browser-core-2.15.0.tgz",
"integrity": "sha512-qWTAysGYQXVpM5FOdstaqIF6B99nyQ2N/rJsi1ruPgFmU9yMM9tRdvqiJ7NZcy+OOsZWiinvFRFUMv9SOsHeUA==",
"version": "2.17.0",
"resolved": "https://registry.npmjs.org/@datadog/browser-core/-/browser-core-2.17.0.tgz",
"integrity": "sha512-jGIiVIzxdfQ+FnuFY+tC/j4gBFmK74xW/NIVqHIdN/hbGqA0oXOYs3Qof39ILLhXM5+zxa44RYFY6r/9JaxMIg==",
"requires": {
"tslib": "^1.10.0"
},
@@ -1290,18 +1290,35 @@
}
},
"@datadog/browser-logs": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/@datadog/browser-logs/-/browser-logs-2.15.0.tgz",
"integrity": "sha512-kZb0nKx1XoZibs3nkBwcP2iff23kX11yUcQj0aXHLL4yulO5I0AqEhoZXwVFfG8KP82sflX+uyssdNIUwMr1cg==",
"version": "2.17.0",
"resolved": "https://registry.npmjs.org/@datadog/browser-logs/-/browser-logs-2.17.0.tgz",
"integrity": "sha512-2S6ryflc28EErDJ+SgWo2OdkvWQ5KA5uqzzvbcnEBeFQpAV5ukAIfElHLiQrwSF4J6NkfLFA3tLt6KPGZE5F2w==",
"requires": {
"@datadog/browser-core": "2.15.0",
"@datadog/browser-core": "2.17.0",
"tslib": "^1.10.0"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@datadog/browser-rum": {
"version": "2.18.0",
"resolved": "https://registry.npmjs.org/@datadog/browser-rum/-/browser-rum-2.18.0.tgz",
"integrity": "sha512-cfji5LdYJl1EpDhDZS67cpvgF6mC+qHSKRDxHQmqYurZW8R97wRhvrfpQWpDrKnl46MCvdQ76qDpSk9AVqK1zg==",
"requires": {
"@datadog/browser-core": "2.18.0",
"@datadog/browser-rum-core": "2.18.0",
"tslib": "^1.10.0"
},
"dependencies": {
"@datadog/browser-core": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/@datadog/browser-core/-/browser-core-2.15.0.tgz",
"integrity": "sha512-qWTAysGYQXVpM5FOdstaqIF6B99nyQ2N/rJsi1ruPgFmU9yMM9tRdvqiJ7NZcy+OOsZWiinvFRFUMv9SOsHeUA==",
"version": "2.18.0",
"resolved": "https://registry.npmjs.org/@datadog/browser-core/-/browser-core-2.18.0.tgz",
"integrity": "sha512-1RvxLK8TiuAaDrwkrlOg7wM+7FilJtNbC30h5BxoGChWEBB7QsgeYGnliQ60byZUCzhbvARVzHHNZTxUiP+fPQ==",
"requires": {
"tslib": "^1.10.0"
}
@@ -1313,32 +1330,23 @@
}
}
},
"@datadog/browser-rum": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/@datadog/browser-rum/-/browser-rum-2.15.0.tgz",
"integrity": "sha512-E9PmGHxGQEdn8SUA7DmUu2mf/ifWGXLuGm95Hes/+dqoXbIPryFdmPCFnHaVF2nZNIA7wwW23oqe60KKo2Qjaw==",
"requires": {
"@datadog/browser-core": "2.15.0",
"@datadog/browser-rum-core": "2.15.0",
"tslib": "^1.10.0"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@datadog/browser-rum-core": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/@datadog/browser-rum-core/-/browser-rum-core-2.15.0.tgz",
"integrity": "sha512-XXEe3JpSyvSvYXpXz/MgrVqs5Rl4Zu2eJXmHfxafAxb3i+VxyA6vc/pLnXPaKeWVcO489MpBEr6Gv7HiOEFZNA==",
"version": "2.18.0",
"resolved": "https://registry.npmjs.org/@datadog/browser-rum-core/-/browser-rum-core-2.18.0.tgz",
"integrity": "sha512-HzdoQltOdIkEEDiZj7r0kHDa/bw6WIBfKPQIv680arRXwhIrvaguwWUiJFTEXI865NA5ouSwGMpPm8Xgrb3B5g==",
"requires": {
"@datadog/browser-core": "2.15.0",
"@datadog/browser-core": "2.18.0",
"tslib": "^1.10.0"
},
"dependencies": {
"@datadog/browser-core": {
"version": "2.18.0",
"resolved": "https://registry.npmjs.org/@datadog/browser-core/-/browser-core-2.18.0.tgz",
"integrity": "sha512-1RvxLK8TiuAaDrwkrlOg7wM+7FilJtNbC30h5BxoGChWEBB7QsgeYGnliQ60byZUCzhbvARVzHHNZTxUiP+fPQ==",
"requires": {
"tslib": "^1.10.0"
}
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@@ -1768,13 +1776,13 @@
}
},
"@material-ui/core": {
"version": "4.11.4",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.4.tgz",
"integrity": "sha512-oqb+lJ2Dl9HXI9orc6/aN8ZIAMkeThufA5iZELf2LQeBn2NtjVilF5D2w7e9RpntAzDb4jK5DsVhkfOvFY/8fg==",
"version": "4.12.1",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.1.tgz",
"integrity": "sha512-C6hYsjkWCTfBx9FaqxhCZCITBagh7fyCKFtHyvO3tTOcBw6NJaktdhNZ2n82jQdQdgfFvg6OOxi7OOzsAdAcBQ==",
"requires": {
"@babel/runtime": "^7.4.4",
"@material-ui/styles": "^4.11.4",
"@material-ui/system": "^4.11.3",
"@material-ui/system": "^4.12.1",
"@material-ui/types": "5.1.0",
"@material-ui/utils": "^4.11.2",
"@types/react-transition-group": "^4.2.0",
@@ -1818,9 +1826,9 @@
}
},
"@material-ui/system": {
"version": "4.11.3",
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.11.3.tgz",
"integrity": "sha512-SY7otguNGol41Mu2Sg6KbBP1ZRFIbFLHGK81y4KYbsV2yIcaEPOmsCK6zwWlp+2yTV3J/VwT6oSBARtGIVdXPw==",
"version": "4.12.1",
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz",
"integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==",
"requires": {
"@babel/runtime": "^7.4.4",
"@material-ui/utils": "^4.11.2",
@@ -1902,6 +1910,11 @@
}
}
},
"@react-leaflet/core": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-1.1.0.tgz",
"integrity": "sha512-zFxMHgfjCi7khRVB7o7H8NoJl36NaezvfcaeEurVXx22lAGHFlTHiSuLOGA4tOiHj+Ep+Lo3uwUGJ3YM9BGkHg=="
},
"@rollup/plugin-node-resolve": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz",
@@ -2139,9 +2152,9 @@
"integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA=="
},
"@types/aria-query": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.1.tgz",
"integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg=="
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz",
"integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig=="
},
"@types/babel__core": {
"version": "7.1.14",
@@ -2238,9 +2251,9 @@
}
},
"@types/jest": {
"version": "26.0.23",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz",
"integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==",
"version": "26.0.24",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz",
"integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==",
"requires": {
"jest-diff": "^26.0.0",
"pretty-format": "^26.0.0"
@@ -2282,9 +2295,9 @@
"integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA=="
},
"@types/prop-types": {
"version": "15.7.3",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
"version": "15.7.4",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
"integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
},
"@types/q": {
"version": "1.5.4",
@@ -2292,9 +2305,9 @@
"integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug=="
},
"@types/react": {
"version": "17.0.5",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.5.tgz",
"integrity": "sha512-bj4biDB9ZJmGAYTWSKJly6bMr4BLUiBrx9ujiJEoP9XIDY9CTaPGxE5QWN/1WjpPLzYF7/jRNnV2nNxNe970sw==",
"version": "17.0.14",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.14.tgz",
"integrity": "sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ==",
"requires": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -2309,9 +2322,9 @@
}
},
"@types/react-transition-group": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
"integrity": "sha512-vIo69qKKcYoJ8wKCJjwSgCTM+z3chw3g18dkrDfVX665tMH7tmbDxEAnPdey4gTlwZz5QuHGzd+hul0OVZDqqQ==",
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.2.tgz",
"integrity": "sha512-KibDWL6nshuOJ0fu8ll7QnV/LVTo3PzQ9aCPnRUYPfX7eZohHwLIdNHj7pftanREzHNP4/nJa8oeM73uSiavMQ==",
"requires": {
"@types/react": "*"
}
@@ -2325,9 +2338,9 @@
}
},
"@types/scheduler": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz",
"integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA=="
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
},
"@types/source-list-map": {
"version": "0.1.2",
@@ -7659,14 +7672,6 @@
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
},
"indefinite-observable": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-2.0.1.tgz",
"integrity": "sha512-G8vgmork+6H9S8lUAg1gtXEj2JxIQTo0g2PbFiYOdjkziSI0F7UYBiVwhZRuixhBCNGczAls34+5HJPyZysvxQ==",
"requires": {
"symbol-observable": "1.2.0"
}
},
"indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
@@ -9149,13 +9154,12 @@
}
},
"jss": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/jss/-/jss-10.6.0.tgz",
"integrity": "sha512-n7SHdCozmxnzYGXBHe0NsO0eUf9TvsHVq2MXvi4JmTn3x5raynodDVE/9VQmBdWFyyj9HpHZ2B4xNZ7MMy7lkw==",
"version": "10.7.1",
"resolved": "https://registry.npmjs.org/jss/-/jss-10.7.1.tgz",
"integrity": "sha512-5QN8JSVZR6cxpZNeGfzIjqPEP+ZJwJJfZbXmeABNdxiExyO+eJJDy6WDtqTf8SDKnbL5kZllEpAP71E/Lt7PXg==",
"requires": {
"@babel/runtime": "^7.3.1",
"csstype": "^3.0.2",
"indefinite-observable": "^2.0.1",
"is-in-browser": "^1.1.3",
"tiny-warning": "^1.0.2"
},
@@ -9168,70 +9172,70 @@
}
},
"jss-plugin-camel-case": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.6.0.tgz",
"integrity": "sha512-JdLpA3aI/npwj3nDMKk308pvnhoSzkW3PXlbgHAzfx0yHWnPPVUjPhXFtLJzgKZge8lsfkUxvYSQ3X2OYIFU6A==",
"version": "10.7.1",
"resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.7.1.tgz",
"integrity": "sha512-+ioIyWvmAfgDCWXsQcW1NMnLBvRinOVFkSYJUgewQ6TynOcSj5F1bSU23B7z0p1iqK0PPHIU62xY1iNJD33WGA==",
"requires": {
"@babel/runtime": "^7.3.1",
"hyphenate-style-name": "^1.0.3",
"jss": "10.6.0"
"jss": "10.7.1"
}
},
"jss-plugin-default-unit": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.6.0.tgz",
"integrity": "sha512-7y4cAScMHAxvslBK2JRK37ES9UT0YfTIXWgzUWD5euvR+JR3q+o8sQKzBw7GmkQRfZijrRJKNTiSt1PBsLI9/w==",
"version": "10.7.1",
"resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.7.1.tgz",
"integrity": "sha512-tW+dfYVNARBQb/ONzBwd8uyImigyzMiAEDai+AbH5rcHg5h3TtqhAkxx06iuZiT/dZUiFdSKlbe3q9jZGAPIwA==",
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "10.6.0"
"jss": "10.7.1"
}
},
"jss-plugin-global": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.6.0.tgz",
"integrity": "sha512-I3w7ji/UXPi3VuWrTCbHG9rVCgB4yoBQLehGDTmsnDfXQb3r1l3WIdcO8JFp9m0YMmyy2CU7UOV6oPI7/Tmu+w==",
"version": "10.7.1",
"resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.7.1.tgz",
"integrity": "sha512-FbxCnu44IkK/bw8X3CwZKmcAnJqjAb9LujlAc/aP0bMSdVa3/MugKQRyeQSu00uGL44feJJDoeXXiHOakBr/Zw==",
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "10.6.0"
"jss": "10.7.1"
}
},
"jss-plugin-nested": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.6.0.tgz",
"integrity": "sha512-fOFQWgd98H89E6aJSNkEh2fAXquC9aZcAVjSw4q4RoQ9gU++emg18encR4AT4OOIFl4lQwt5nEyBBRn9V1Rk8g==",
"version": "10.7.1",
"resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.7.1.tgz",
"integrity": "sha512-RNbICk7FlYKaJyv9tkMl7s6FFfeLA3ubNIFKvPqaWtADK0KUaPsPXVYBkAu4x1ItgsWx67xvReMrkcKA0jSXfA==",
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "10.6.0",
"jss": "10.7.1",
"tiny-warning": "^1.0.2"
}
},
"jss-plugin-props-sort": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.6.0.tgz",
"integrity": "sha512-oMCe7hgho2FllNc60d9VAfdtMrZPo9n1Iu6RNa+3p9n0Bkvnv/XX5San8fTPujrTBScPqv9mOE0nWVvIaohNuw==",
"version": "10.7.1",
"resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.7.1.tgz",
"integrity": "sha512-eyd5FhA+J0QrpqXxO7YNF/HMSXXl4pB0EmUdY4vSJI4QG22F59vQ6AHtP6fSwhmBdQ98Qd9gjfO+RMxcE39P1A==",
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "10.6.0"
"jss": "10.7.1"
}
},
"jss-plugin-rule-value-function": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.6.0.tgz",
"integrity": "sha512-TKFqhRTDHN1QrPTMYRlIQUOC2FFQb271+AbnetURKlGvRl/eWLswcgHQajwuxI464uZk91sPiTtdGi7r7XaWfA==",
"version": "10.7.1",
"resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.7.1.tgz",
"integrity": "sha512-fGAAImlbaHD3fXAHI3ooX6aRESOl5iBt3LjpVjxs9II5u9tzam7pqFUmgTcrip9VpRqYHn8J3gA7kCtm8xKwHg==",
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "10.6.0",
"jss": "10.7.1",
"tiny-warning": "^1.0.2"
}
},
"jss-plugin-vendor-prefixer": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.6.0.tgz",
"integrity": "sha512-doJ7MouBXT1lypLLctCwb4nJ6lDYqrTfVS3LtXgox42Xz0gXusXIIDboeh6UwnSmox90QpVnub7au8ybrb0krQ==",
"version": "10.7.1",
"resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.7.1.tgz",
"integrity": "sha512-1UHFmBn7hZNsHXTkLLOL8abRl8vi+D1EVzWD4WmLFj55vawHZfnH1oEz6TUf5Y61XHv0smdHabdXds6BgOXe3A==",
"requires": {
"@babel/runtime": "^7.3.1",
"css-vendor": "^2.0.8",
"jss": "10.6.0"
"jss": "10.7.1"
}
},
"jsx-ast-utils": {
@@ -9285,6 +9289,11 @@
"webpack-sources": "^1.1.0"
}
},
"leaflet": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.7.1.tgz",
"integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw=="
},
"leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -12154,6 +12163,14 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz",
"integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA=="
},
"react-leaflet": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-3.2.0.tgz",
"integrity": "sha512-eHVqoRGjW8T9GxLt7jyTKP3BDQ7XQ5AD+tc/zkbaABn1dbmREDy8GojNcYjZQa3QFLQoOLQMcUC1PTtzytZpUA==",
"requires": {
"@react-leaflet/core": "^1.1.0"
}
},
"react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
@@ -12294,9 +12311,9 @@
}
},
"react-transition-group": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
"integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==",
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
"integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==",
"requires": {
"@babel/runtime": "^7.5.5",
"dom-helpers": "^5.0.1",
@@ -14130,11 +14147,6 @@
}
}
},
"symbol-observable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
},
"symbol-tree": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",

View File

@@ -3,18 +3,20 @@
"version": "0.1.1",
"private": true,
"dependencies": {
"@datadog/browser-logs": "^2.15.0",
"@datadog/browser-rum": "^2.15.0",
"@material-ui/core": "^4.11.4",
"@datadog/browser-logs": "^2.17.0",
"@datadog/browser-rum": "^2.17.0",
"@material-ui/core": "^4.12.1",
"@material-ui/icons": "^4.11.2",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
"axios": "^0.21.1",
"clsx": "^1.1.1",
"leaflet": "^1.7.1",
"material-ui-dropzone": "^3.5.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-leaflet": "^3.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"web-vitals": "^0.2.4"
@@ -32,18 +34,11 @@
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"browserslist": [
">0.2%",
"not dead",
"not op_mini all"
],
"engines": {
"node": "12.20.1"
},

View File

@@ -1,22 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Fisker Admin Portal"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<title>Fisker Admin Portal</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Fisker Admin Portal" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
<title>Fisker Admin Portal</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

BIN
src/assets/green-car.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

BIN
src/assets/red-car.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

View File

@@ -6,7 +6,7 @@ jest.mock("../Contexts/ManifestsContext");
jest.mock("../Contexts/CarUpdatesContext");
jest.mock("../../services/monitoring");
import { render, screen, cleanup, waitForElementToBeRemoved } from "@testing-library/react";
import { render, screen, cleanup, waitFor, waitForElementToBeRemoved } from "@testing-library/react";
import { setToken } from "../Contexts/UserContext";
import { TEST_AUTH_OBJECT } from "../../utils/testing"
import App from ".";
@@ -28,6 +28,13 @@ const check = async (path, selector, compare) => {
expect(container).toMatchSnapshot();
};
const sleepAndCheck = async (path, selector, compare) => {
const container = await renderRoute(path);
await waitFor(() => { });
expect(container.querySelector(selector).innerHTML).toEqual(compare);
expect(container).toMatchSnapshot();
};
describe("App", () => {
beforeAll(() => {
// Stablize Table Pagination control ids
@@ -107,12 +114,12 @@ describe("App", () => {
it("Route / authenticated", async () => {
setToken(TEST_AUTH_OBJECT);
await check("/", "h1", "Welcome John!");
await sleepAndCheck("/", "h1", "Welcome John!");
});
it("Route /home authenticated", async () => {
setToken(TEST_AUTH_OBJECT);
await check("/home", "h1", "Welcome John!");
await sleepAndCheck("/home", "h1", "Welcome John!");
});
it("Route /package-upload authenticated", async () => {

File diff suppressed because it is too large Load Diff

View File

@@ -150,8 +150,8 @@ const MainForm = () => {
inputProps: { "aria-label": "rows per page" },
native: true,
}}
onChangePage={handleChangePageIndex}
onChangeRowsPerPage={handleChangePageSize}
onPageChange={handleChangePageIndex}
onRowsPerPageChange={handleChangePageSize}
/>
</TableRow>
</TableFooter>

View File

@@ -176,8 +176,8 @@ const CarSelectionTable = (props) => {
inputProps: { "aria-label": "rows per page" },
native: true,
}}
onChangePage={handleChangePageIndex}
onChangeRowsPerPage={handleChangePageSize}
onPageChange={handleChangePageIndex}
onRowsPerPageChange={handleChangePageSize}
/>
</TableRow>
</TableFooter>

View File

@@ -170,8 +170,8 @@ const MainForm = () => {
inputProps: { "aria-label": "rows per page" },
native: true,
}}
onChangePage={handleChangePageIndex}
onChangeRowsPerPage={handleChangePageSize}
onPageChange={handleChangePageIndex}
onRowsPerPageChange={handleChangePageSize}
/>
</TableRow>
</TableFooter>

View File

@@ -147,8 +147,8 @@ const MainForm = () => {
inputProps: { "aria-label": "rows per page" },
native: true,
}}
onChangePage={handleChangePageIndex}
onChangeRowsPerPage={handleChangePageSize}
onPageChange={handleChangePageIndex}
onRowsPerPageChange={handleChangePageSize}
/>
</TableRow>
</TableFooter>

View File

@@ -103,7 +103,7 @@ export const VehicleProvider = ({ children }) => {
const result = await api.getConnections(vins, token);
if (result.error) {
throw new Error(`Get connections error. ${result.message}`);
throw new Error(`Add connections error. ${result.message}`);
}
cars.forEach((car) => {
car.connected = result[car.vin] || false;
@@ -125,6 +125,30 @@ export const VehicleProvider = ({ children }) => {
}
};
const getLocations = async (token) => {
try {
setBusy(true);
const result = await api.getLocations(token);
if (result.error)
throw new Error(`Get locations error. ${result.message}`);
return result;
} finally {
setBusy(false);
}
};
const getState = async (token, vin) => {
try {
setBusy(true);
const result = await api.getState(token, vin);
if (result.error)
throw new Error(`Get state error. ${result.message}`);
return result;
} finally {
setBusy(false);
}
};
return (
<VehicleContext.Provider
value={{
@@ -139,6 +163,8 @@ export const VehicleProvider = ({ children }) => {
getYears,
sendCommand,
getConnections,
getLocations,
getState,
}}
>
{children}

View File

@@ -39,6 +39,9 @@ export const useVehicleContext = () => ({
return result;
}),
getLocations: jest.fn().mockResolvedValue([
{ "altitude": 5, "longitude": 10, "latitude": 15, "vin": "TESTVIN123" },
])
});
export const setBusy = (val) => {

View File

@@ -5,6 +5,7 @@ import useStyles from "../useStyles";
import { useUserContext } from "../Contexts/UserContext";
import { useStatusContext } from "../Contexts/StatusContext";
import { parsePayload } from "../../utils/jwt";
import VehicleMap from "../VehicleMap";
const DEFAULT_GREETING = "Welcome";
@@ -25,16 +26,17 @@ const Home = () => {
const greeting = getGreeting(token);
const { setTitle } = useStatusContext();
useEffect(() => {
setTitle("");
setTitle("Home");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<div className={classes.paper}>
<Typography component="h1" variant="h5">
<Typography className={classes.homePageTitle} component="h1" variant="h5">
{greeting}
</Typography>
<VehicleMap />
</div>
);
};

View File

@@ -14,7 +14,7 @@ const menuData = [
{
label: "Dashboard",
to: "/dashboard",
roles: [],
roles: [Roles.CREATE, Roles.READ],
},
{
label: "Deploy Packages",
@@ -45,7 +45,7 @@ const menuData = [
label: "Send Command",
to: "/vehicles-command",
roles: [Roles.CREATE],
},
}
];
export default function SideMenu() {

View File

@@ -219,28 +219,6 @@ exports[`SideMenu Unauthenticated 1`] = `
/>
</a>
</li>
<li>
<a
aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/dashboard"
role="button"
tabindex="0"
>
<div
class="MuiListItemText-root"
>
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Dashboard
</span>
</div>
<span
class="MuiTouchRipple-root"
/>
</a>
</li>
</ul>
</div>
</div>

View File

@@ -230,8 +230,8 @@ const MainForm = () => {
inputProps: { "aria-label": "rows per page" },
native: true,
}}
onChangePage={handleChangePageIndex}
onChangeRowsPerPage={handleChangePageSize}
onPageChange={handleChangePageIndex}
onRowsPerPageChange={handleChangePageSize}
/>
</TableRow>
</TableFooter>

View File

@@ -153,8 +153,8 @@ const MainForm = () => {
inputProps: { "aria-label": "rows per page" },
native: true,
}}
onChangePage={handleChangePageIndex}
onChangeRowsPerPage={handleChangePageSize}
onPageChange={handleChangePageIndex}
onRowsPerPageChange={handleChangePageSize}
/>
</TableRow>
</TableFooter>

View File

@@ -75,7 +75,7 @@ const HeaderSortable = (props) => {
<TableCell
key={column.id}
align={column.numeric ? "right" : "center"}
padding={column.disablePadding ? "none" : "default"}
padding={column.disablePadding ? "none" : "normal"}
sortDirection={orderBy === column.id ? order : false}
>
{ColumnLabel(column)}

View File

@@ -46,10 +46,10 @@ exports[`File Upload Form Should render 1`] = `
/>
<fieldset
aria-hidden="true"
class="PrivateNotchedOutline-root-33 MuiOutlinedInput-notchedOutline"
class="PrivateNotchedOutline-root-39 MuiOutlinedInput-notchedOutline"
>
<legend
class="PrivateNotchedOutline-legendLabelled-35"
class="PrivateNotchedOutline-legendLabelled-41"
>
<span>
Package name
@@ -92,10 +92,10 @@ exports[`File Upload Form Should render 1`] = `
/>
<fieldset
aria-hidden="true"
class="PrivateNotchedOutline-root-33 MuiOutlinedInput-notchedOutline"
class="PrivateNotchedOutline-root-39 MuiOutlinedInput-notchedOutline"
>
<legend
class="PrivateNotchedOutline-legendLabelled-35"
class="PrivateNotchedOutline-legendLabelled-41"
>
<span>
Version
@@ -138,10 +138,10 @@ exports[`File Upload Form Should render 1`] = `
/>
<fieldset
aria-hidden="true"
class="PrivateNotchedOutline-root-33 MuiOutlinedInput-notchedOutline"
class="PrivateNotchedOutline-root-39 MuiOutlinedInput-notchedOutline"
>
<legend
class="PrivateNotchedOutline-legendLabelled-35"
class="PrivateNotchedOutline-legendLabelled-41"
>
<span>
Description
@@ -185,10 +185,10 @@ exports[`File Upload Form Should render 1`] = `
/>
<fieldset
aria-hidden="true"
class="PrivateNotchedOutline-root-33 MuiOutlinedInput-notchedOutline"
class="PrivateNotchedOutline-root-39 MuiOutlinedInput-notchedOutline"
>
<legend
class="PrivateNotchedOutline-legendLabelled-35"
class="PrivateNotchedOutline-legendLabelled-41"
>
<span>
Release Notes URL

View File

@@ -225,8 +225,8 @@ const UpdatePackagesList = () => {
inputProps: { "aria-label": "rows per page" },
native: true,
}}
onChangePage={handleChangePageIndex}
onChangeRowsPerPage={handleChangePageSize}
onPageChange={handleChangePageIndex}
onRowsPerPageChange={handleChangePageSize}
/>
</TableRow>
</TableFooter>

View File

@@ -0,0 +1,208 @@
import React, { useEffect, useState } from "react";
import useStyles from "../useStyles";
import L from "leaflet";
import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet";
import { Button } from "@material-ui/core";
import { useUserContext } from "../Contexts/UserContext";
import { useStatusContext } from "../Contexts/StatusContext";
import { useVehicleContext, VehicleProvider } from "../Contexts/VehicleContext";
import { VehiclePopUp } from "./popup";
import GreenCarIcon from "../../assets/green-car.png";
import RedCarIcon from "../../assets/red-car.png";
const Component = () => {
const classes = useStyles();
const { token } = useUserContext();
const { setTitle } = useStatusContext();
const { getConnections, getLocations, getState } = useVehicleContext();
const REQUEST_INTERVAL = 10000;
useEffect(() => {
setTitle("");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const [center, setCenter] = useState([0, 0]);
const [zoom, setZoom] = useState(2);
const [markers, setMarkers] = useState([]);
useEffect(() => {
retrieveAndStoreLocations()
.then(points => {
centerAroundMarkers(points);
})
const id = setInterval(function () {
retrieveAndStoreLocations();
}, REQUEST_INTERVAL);
return () => { clearInterval(id) };
// eslint-disable-next-line
}, []);
const retrieveAndStoreLocations = () => {
return getLocations(token)
.then(result => {
if (result.data != null) {
const points = result.data.map(point => [point.latitude, point.longitude, point.vin]);
setMarkers(points);
return points
}
return []
})
.catch(error => console.log(error));
}
const centerAroundMarkers = (markers) => {
if (markers == null) {
markers = []
}
const coord = markers.reduce((coord, marker) => {
coord[0] += marker[0] / markers.length;
coord[1] += marker[1] / markers.length;
return coord;
}, [0, 0])
setCenter(coord);
setZoom(4);
}
const [connections, setConnections] = useState({});
useEffect(() => {
if (markers.length > 0) {
const vins = markers.map(marker => marker[2]);
getConnections(vins, token)
.then(connections => {
setConnections(connections);
})
}
// eslint-disable-next-line
}, [markers, token])
const [selectedVIN, setSelectedVIN] = useState(null);
const [carState, setCarState] = useState(null);
useEffect(() => {
if (selectedVIN != null) {
retrieveAndStoreCarState(selectedVIN);
const id = setInterval(function () {
retrieveAndStoreCarState(selectedVIN);
}, REQUEST_INTERVAL);
return () => { clearInterval(id) };
}
// eslint-disable-next-line
}, [selectedVIN]);
const selectCar = (e, vin) => {
e.preventDefault();
setSelectedVIN(vin);
}
const retrieveAndStoreCarState = (vin) => {
getState(token, vin)
.then(results => {
setCarState({ ...results.data, vin: vin });
});
}
const handleClose = () => {
setSelectedVIN(null);
setCarState(null);
};
function getCarIcon(vin) {
let icon = RedCarIcon;
if (connections[vin]) {
icon = GreenCarIcon;
} else {
icon = RedCarIcon;
}
return new L.Icon({
iconUrl: icon,
iconAnchor: [15, 0]
});
}
return (
<MapContainer
center={center}
zoom={zoom}
style={{
width: '100%',
height: '900px'
}}
>
<TileLayer
attribution='&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<CenterFocus center={center} zoom={zoom} />
{markers.map((marker) => (
<Marker
icon={getCarIcon(marker[2])}
key={marker[2]}
position={[marker[0], marker[1]]}
title={marker[2]}
opacity={0.9}
>
<Popup>
<div align="center">
<p className={classes.markerTitle}><b>{marker[2]}</b></p>
<Button
type="submit"
variant="contained"
color="primary"
onClick={e => selectCar(e, marker[2])}
>
View Stats
</Button>
</div>
</Popup>
</Marker>
))
}
{
carState ? (
<VehiclePopUp
key={carState.vin}
vin={carState.vin}
online={carState.online}
battery={carState.battery}
doors={carState.doors}
location={carState.location}
windows={carState.windows}
className={classes.popup}
onClose={handleClose}
/>
) : null
}
</MapContainer >
);
};
const CenterFocus = ({ center, zoom }) => {
const map = useMap();
useEffect(() => {
if (center[0] === 0 && center[1] === 0) {
map.flyTo([0, 0], 2, { duration: 1.5 });
} else {
map.flyTo(center, zoom, { duration: 1.5 });
}
}, [center, zoom, map]);
return null;
}
const VehicleMap = () => (
<VehicleProvider>
<Component />
</VehicleProvider>
)
export default VehicleMap;

View File

@@ -0,0 +1,72 @@
import React from "react";
import Dialog from '@material-ui/core/Dialog';
import MuiDialogTitle from '@material-ui/core/DialogTitle';
import IconButton from '@material-ui/core/IconButton';
import CloseIcon from '@material-ui/icons/Close';
import Typography from '@material-ui/core/Typography';
import useStyles from "../useStyles";
const VehiclePopUp = (props) => {
const classes = useStyles();
const { vin, online, battery, doors, location, windows, onClose } = props;
return (
<Dialog
fullWidth
classes={{ paper: classes.popUp }}
open={true}
onClose={onClose}
>
<DialogTitle align="center" onClose={onClose}>{vin}</DialogTitle>
<div align="center" className={classes.popUpContent}>
<p><b>Connected</b>: {online.toString()}</p>
{online && (
<div>
{battery != null && (
<p><b>battery</b>: {battery.percent}%</p>
)}
{doors != null && (
<div>
<h3>Doors</h3>
{Object.entries(doors).map((value) => (<p key={value[0]}><b>{value[0]}</b>: {value[1] ? "open" : "closed"}</p>))}
</div>
)}
{windows != null && (
<div>
<h3>Windows</h3>
{Object.entries(windows).map((value) => (<p key={value[0]}><b>{value[0]}</b>: {value[1] ? "open" : "closed"}</p>))}
</div>
)}
{location != null && (
<div>
<h3>Location</h3>
{Object.entries(location).map((value) => (<p key={value[0]}><b>{value[0]}</b>: {value[1]}</p>))}
</div>
)}
</div>
)}
{(!online || (battery == null && doors == null && location == null && windows == null)) && (
<p>No vehicle data to display.</p>
)}
</div>
</Dialog >
);
};
const DialogTitle = (props) => {
const { children, onClose, ...other } = props;
const classes = useStyles();
return (
<MuiDialogTitle disableTypography className={classes.ppopUpTItle} {...other}>
<Typography variant="h6">{children}</Typography>
{onClose ? (
<IconButton aria-label="close" className={classes.closeButton} onClick={onClose}>
<CloseIcon />
</IconButton>
) : null}
</MuiDialogTitle>
);
};
export { VehiclePopUp };

View File

@@ -173,6 +173,31 @@ const useStyles = makeStyles((theme) => ({
width: "100%",
paddingTop: "56.25%",
},
closeButton: {
position: 'absolute',
right: theme.spacing(1),
top: theme.spacing(1),
color: theme.palette.grey[500],
},
homePageTitle: {
marginBottom: 25,
},
markerTitle: {
margin: 5,
},
popUp: {
minHeight: "15vh",
},
popUpTitle: {
margin: 0,
padding: theme.spacing(2),
},
popUpContent: {
"& p": {
margin: 0,
},
paddingBottom: "2vh",
},
}));
export default useStyles;

View File

@@ -11,7 +11,7 @@ const data = [
const vehiclesAPI = {
getVehicles: async (search, token) => { return { data }; },
addVehicle: async (vehicle, token) => {
addVehicle: async (vehicle, token) => {
data.push(vehicle);
return vehicle;
},
@@ -38,7 +38,10 @@ const vehiclesAPI = {
});
return result;
}
},
getLocations: jest.fn().mockResolvedValue([
{ "altitude": 5, "longitude": 10, "latitude": 15, "vin": "TESTVIN123" },
]),
};
export default vehiclesAPI;

View File

@@ -9,10 +9,10 @@ const vehiclesAPI = {
body: JSON.stringify(vehicle),
})
.then(fetchRespHandler),
getVehicles: async (search, token) => {
const u = addQueryParams(`${API_ENDPOINT}/vehicles`, search);
return fetch(u, {
return fetch(u, {
method: "GET",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
})
@@ -20,10 +20,10 @@ const vehiclesAPI = {
},
getModels: async (token) => fetch(`${API_ENDPOINT}/vehiclemodels`, {
method: "GET",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
})
.then(fetchRespHandler),
method: "GET",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
})
.then(fetchRespHandler),
getYears: async (token) => fetch(`${API_ENDPOINT}/vehicleyears`, {
method: "GET",
@@ -39,15 +39,27 @@ const vehiclesAPI = {
}),
})
.then(fetchRespHandler),
getConnections: async (vins, token) => {
const u = `${API_ENDPOINT}/carsconnected?vins=${vins.join(",")}`
return fetch(u, {
return fetch(u, {
method: "GET",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
})
.then(fetchRespHandler)
},
getLocations: async (token) => fetch(`${API_ENDPOINT}/carslocations`, {
method: "GET",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
})
.then(fetchRespHandler),
getState: async (token, vin) => fetch(`${API_ENDPOINT}/carstate?vin=${vin}`, {
method: "GET",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
})
.then(fetchRespHandler),
};
export default vehiclesAPI;