Setup environment vars for staging and production (#99)

* CEC-371 Car ECU display (#79)

* Merge Development (#53)

* Use responsive iframe control for charts (#49)

* Use responsive iframe control to charts

* Move external Grafana link to Dashboard page

* Remove unused embedded style class

* Add button label

* added delete button to deploy packages

* Fix unit test warning
Remove unused route from test

* Fix styling of button

* minor fixes per pr review

Co-authored-by: jcw-fisker <jwatson@fiskerinc.com>
Co-authored-by: John Cotten Watson <83605808+jcw-fisker@users.noreply.github.com>

* Development Merge (#57)

* CEC-287 Car connection status (#59) (#60)

* Car connection status

* Formatting

* Merge Development (#64)

* Add connection status to vehicles page

* ConnectedIcon control

* Handle Style

* Development (#67)

* preliminary map for vehicles

* weird zoom bug

* passing react tests

* fixing warnings and updating snapshots

* update node environment to 14

* addressing comments by changing variable types and adding styles to home page title

* adding CODEOWNERS file

* fixing token error

* CEC-371 Update car ECUs display (#78)

* Clean up className styles
Update car status page to show update and ECUs

* Add update ecu version button
Show all ECUs on car status page
Only show car ecus for search

Co-authored-by: jcw-fisker <jwatson@fiskerinc.com>
Co-authored-by: John Cotten Watson <83605808+jcw-fisker@users.noreply.github.com>
Co-authored-by: Drew Taylor <69828061+drew-fisker@users.noreply.github.com>

* CEC-394 Car update log (#81)

* CEC-394 Car update status control

* Remove Datadog RUM
Remove package update components
Move control components into Controls folder
Add Car update status page

* Display update status log
Clean up unused update package code

* Remove console.logs

* no vars

* adding timestamp to vehicle popup

* modifying vehicle data query

* removing extraneous code

* removing console log

* Clean up SonarCloud warnings (#83)

* Clean up SonarCloud warnings

* Bogus security warning

* Fix another warning

* Fix unauthorized locations request

* Fix update progress control

* CEC-563 New manifest format (#88)

* Add ManifestCreateContext
Update create manifest page

* Finish UI changes and API integration

* Fixes

* Fix test

* Remove manifest ECU file version and type

* Fixes

* Add manifest ecu file type control

* Fix Sonar warnings

* Fix test

* Update codeowners

* Formatting

* CEC-553 Change file type to string (#90)

* CEC-553 File type uses string enum

* Fix test timeout

* Fix

* Clean up (#95)

* Clean up
Mock missing methods

* Smell

* Setup environment vars

* fix

* Load env file
Remove env var default values

* Dockerfile requires environment value
Do not need dev Dockerfile

* Github Actions pipeline + git flow (#100)

* test workflow

* oops

* latest slack action for custom message

* this works

Co-authored-by: jcw-fisker <jwatson@fiskerinc.com>
Co-authored-by: John Cotten Watson <83605808+jcw-fisker@users.noreply.github.com>
Co-authored-by: Drew Taylor <69828061+drew-fisker@users.noreply.github.com>
Co-authored-by: Drew Taylor <dtaylor@fiskerinc.com>
Co-authored-by: Rafi Greenberg <72412693+rafi-fisker@users.noreply.github.com>
This commit is contained in:
John Wu
2021-11-03 17:50:17 -07:00
committed by GitHub
parent ec3a31a15a
commit 16c3e2902b
21 changed files with 249 additions and 171 deletions

3
.env.dev Normal file
View File

@@ -0,0 +1,3 @@
REACT_APP_AUTH_SERVICE_URL=https://gw-dev.fiskerdps.com/compute_auth
REACT_APP_UPLOAD_SERVICE_URL=https://gw-dev.fiskerdps.com/ota_update
REACT_APP_AUTH_CALLBACK_URL=https://dev-ota-admin.fiskerdps.com

3
.env.local Normal file
View File

@@ -0,0 +1,3 @@
REACT_APP_AUTH_SERVICE_URL=http://localhost/compute_auth
REACT_APP_UPLOAD_SERVICE_URL=http://localhost/ota_update
REACT_APP_AUTH_CALLBACK_URL=http://localhost:3000

3
.env.prd Normal file
View File

@@ -0,0 +1,3 @@
REACT_APP_AUTH_SERVICE_URL=https://gw.fiskerdps.com/compute_auth
REACT_APP_UPLOAD_SERVICE_URL=https://gw.fiskerdps.com/ota_update
REACT_APP_AUTH_CALLBACK_URL=https://ota-admin.fiskerdps.com

3
.env.stg Normal file
View File

@@ -0,0 +1,3 @@
REACT_APP_AUTH_SERVICE_URL=https://gw-stg.fiskerdps.com/compute_auth
REACT_APP_UPLOAD_SERVICE_URL=https://gw-stg.fiskerdps.com/ota_update
REACT_APP_AUTH_CALLBACK_URL=https://stg-ota-admin.fiskerdps.com

72
.github/workflows/deploy.yml vendored Normal file
View File

@@ -0,0 +1,72 @@
on:
push:
branches:
- develop
- main
- 'release/**'
- 'hotfix/**'
jobs:
deploy:
name: Deploy
runs-on: self-hosted
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
TAG: ${{ github.sha }}
PROJECT: ota-admin-portal
steps:
- name: Slack Notify
uses: act10ns/slack@master
with:
channel: "#cloud-builds"
status: starting
- name: Checkout
uses: actions/checkout@v2
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: us-west-2
- name: Create ECR Repo
run: aws ecr create-repository --region us-west-2 --repository-name ${PROJECT} || true
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Set Env
run: |
case ${GITHUB_REF} in
refs/heads/develop)
ENVIRONMENT=dev;;
refs/heads/release/*)
ENVIRONMENT=stg;;
refs/heads/hotfix/*)
ENVIRONMENT=stg;;
refs/heads/main)
ENVIRONMENT=prd;;
*)
ENVIRONMENT=dev;;
esac
echo "ENVIRONMENT=${ENVIRONMENT}" >> $GITHUB_ENV
- name: Build, tag, and push image to Amazon ECR
id: build-tag-push-image
env:
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
run: |
docker build --build-arg ENVIRONMENT=$ENVIRONMENT -t $REGISTRY/$PROJECT:$TAG-$ENVIRONMENT .
docker push $REGISTRY/$PROJECT:$TAG-$ENVIRONMENT
- name: Deploy
id: deploy
env:
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
run: |-
helm upgrade \
--kube-context $ENVIRONMENT \
--set image.registry=$REGISTRY \
--set image.name=$PROJECT \
--set image.tag=$TAG-$ENVIRONMENT \
--wait -i -f k8s/values-$ENVIRONMENT.yaml $PROJECT k8s/
- uses: act10ns/slack@master
with:
channel: "#cloud-builds"
status: ${{ job.status }}
message: Successfully deployed to ${{ env.ENVIRONMENT }}!
if: always()

View File

@@ -1,9 +1,11 @@
FROM node:14-alpine as builder FROM node:14-alpine as builder
ARG ENVIRONMENT
COPY package*.json ./ COPY package*.json ./
RUN npm install RUN npm install
COPY . . COPY . .
RUN npm run build RUN npm run build:${ENVIRONMENT}
FROM nginx:alpine FROM nginx:alpine

View File

@@ -1,12 +0,0 @@
FROM node:14-alpine as builder
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder build /usr/share/nginx/html
COPY .env /usr/share/nginx/html/.env
COPY nginx.conf /etc/nginx/conf.d/default.conf

81
Jenkinsfile vendored
View File

@@ -1,81 +0,0 @@
@Library('fisker') _
pipeline {
agent none
options {
ansiColor('xterm')
}
environment {
PROJECT = getProject()
ENV = getEnv()
}
stages {
stage('Build') {
when {
beforeAgent true
allOf {
not {
changeRequest()
}
anyOf {
branch 'development'
branch 'main'
}
}
}
agent {
kubernetes {
cloud 'dev'
inheritFrom 'fisker'
}
}
steps {
slack("Build Started - ${env.JOB_NAME} (${env.BUILD_URL})", 'info', '#team-eng-compute-jenkins')
slack(getChanges(), 'info', '#team-eng-compute-jenkins')
container('awscli') {
ecr()
}
container('kaniko') {
buildImage()
}
}
post {
failure {
slack("${env.JOB_NAME} build failed!", 'error', '#team-eng-compute-jenkins')
}
}
}
stage('Deploy') {
when {
beforeAgent true
allOf {
not {
changeRequest()
}
anyOf {
branch 'development'
branch 'main'
}
}
}
agent {
kubernetes {
cloud getEnv()
inheritFrom 'fisker'
}
}
steps {
slack("Deploying ${PROJECT} to ${ENV}... :partydeploy: ", 'info', '#team-eng-compute-jenkins')
container('helm') {
deploy(getEnv())
}
slack("Successfully deployed ${PROJECT} to ${ENV}! :tada: ", 'info', '#team-eng-compute-jenkins')
}
post {
failure {
slack("${PROJECT} deploy to ${ENV} failed!", 'error', '#team-eng-compute-jenkins')
}
}
}
}
}

View File

@@ -15,7 +15,7 @@ Running locally
Running Docker container Running Docker container
1. Copy .env.template to .env and edit the service urls for authentication and api services 1. Copy .env.template to .env and edit the service urls for authentication and api services
2. Build the image `docker build -t fiskerinc/portal --file Dockerfile.dev .` 2. Build the image `docker build --build-arg ENVIRONMENT=local -t fiskerinc/portal .`
3. Start the container `docker run -p 3000:80 fiskerinc/portal` 3. Start the container `docker run -p 3000:80 fiskerinc/portal`
4. Access portal at localhost:3000 4. Access portal at localhost:3000

12
k8s/values-stg.yaml Normal file
View File

@@ -0,0 +1,12 @@
ingress:
hostname: stg-ota-admin.fiskerdps.com
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 250m
memory: 256Mi
replicas: 1

53
package-lock.json generated
View File

@@ -3906,9 +3906,9 @@
} }
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30001223", "version": "1.0.30001275",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001223.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001275.tgz",
"integrity": "sha512-k/RYs6zc/fjbxTjaWZemeSmOjO0JJV+KguOBA3NwPup8uzxM1cMhR2BD9XmO86GuqaqTCO8CgkgH9Rz//vdDiA==" "integrity": "sha512-ihJVvj8RX0kn9GgP43HKhb5q9s2XQn4nEQhdldEJvZhCsuiB2XOq6fAMYQZaN6FPWfsr2qU0cdL0CSbETwbJAg=="
}, },
"capture-exit": { "capture-exit": {
"version": "2.0.0", "version": "2.0.0",
@@ -5406,6 +5406,53 @@
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
}, },
"env-cmd": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz",
"integrity": "sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==",
"requires": {
"commander": "^4.0.0",
"cross-spawn": "^7.0.0"
},
"dependencies": {
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
}
},
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"requires": {
"shebang-regex": "^3.0.0"
}
},
"shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"requires": {
"isexe": "^2.0.0"
}
}
}
},
"errno": { "errno": {
"version": "0.1.8", "version": "0.1.8",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",

View File

@@ -11,6 +11,7 @@
"@testing-library/user-event": "^13.2.1", "@testing-library/user-event": "^13.2.1",
"axios": "^0.21.1", "axios": "^0.21.1",
"clsx": "^1.1.1", "clsx": "^1.1.1",
"env-cmd": "^10.1.0",
"leaflet": "^1.7.1", "leaflet": "^1.7.1",
"material-ui-dropzone": "^3.5.0", "material-ui-dropzone": "^3.5.0",
"react": "^17.0.2", "react": "^17.0.2",
@@ -21,9 +22,13 @@
"web-vitals": "^2.1.0" "web-vitals": "^2.1.0"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "env-cmd -f .env.local react-scripts start",
"build": "react-scripts build", "build": "env-cmd -f .env.local react-scripts build",
"test": "react-scripts test", "build:dev": "env-cmd -f .env.dev react-scripts build",
"build:stg": "env-cmd -f .env.stg react-scripts build",
"build:prd": "env-cmd -f .env.prd react-scripts build",
"build:local": "env-cmd -f .env.local react-scripts build",
"test": "env-cmd -f .env.local react-scripts test",
"test:debug": "react-scripts --inspect-brk test --runInBand --no-cache", "test:debug": "react-scripts --inspect-brk test --runInBand --no-cache",
"eject": "react-scripts eject" "eject": "react-scripts eject"
}, },

View File

@@ -1,5 +1,5 @@
const AUTH_URL = process.env.REACT_APP_AUTH_SERVICE_URL || "https://gw-dev.fiskerdps.com/compute_auth"; const AUTH_URL = process.env.REACT_APP_AUTH_SERVICE_URL;
const CALLBACK_URL = process.env.REACT_APP_AUTH_CALLBACK_URL || ""; const CALLBACK_URL = process.env.REACT_APP_AUTH_CALLBACK_URL;
let signInResponse = {}; let signInResponse = {};
let verifyResponse = {}; let verifyResponse = {};
@@ -15,7 +15,13 @@ export default {
signIn: async (username, password) => logResponse(signInResponse), signIn: async (username, password) => logResponse(signInResponse),
verify: async (idToken) => logResponse(verifyResponse), verify: async (idToken) => logResponse(verifyResponse),
refresh: async (refreshToken) => logResponse(refreshResponse), refresh: async (refreshToken) => logResponse(refreshResponse),
setSignInResponse: (value) => { signInResponse = value; }, setSignInResponse: (value) => {
setVerifyResponse: (value) => { verifyResponse = value; }, signInResponse = value;
setRefreshResponse: (value) => { refreshResponse = value; }, },
} setVerifyResponse: (value) => {
verifyResponse = value;
},
setRefreshResponse: (value) => {
refreshResponse = value;
},
};

View File

@@ -1,36 +1,39 @@
import { fetchRespHandler } from "../utils/http"; import { fetchRespHandler } from "../utils/http";
const AUTH_URL = process.env.REACT_APP_AUTH_SERVICE_URL || "https://gw-dev.fiskerdps.com/compute_auth"; const AUTH_URL = process.env.REACT_APP_AUTH_SERVICE_URL;
const CALLBACK_URL = process.env.REACT_APP_AUTH_CALLBACK_URL || "https://dev-ota-admin.fiskerdps.com"; const CALLBACK_URL = process.env.REACT_APP_AUTH_CALLBACK_URL;
const auth = { const auth = {
ssoAuthorize: () => `${AUTH_URL}/authorize?redirect=${CALLBACK_URL}`, ssoAuthorize: () => `${AUTH_URL}/authorize?redirect=${CALLBACK_URL}`,
ssoLogout: () => `${AUTH_URL}/logout?redirect=${CALLBACK_URL}`, ssoLogout: () => `${AUTH_URL}/logout?redirect=${CALLBACK_URL}`,
signIn: (code) => fetch(`${AUTH_URL}/token`, { signIn: (code) =>
fetch(`${AUTH_URL}/token`, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json" "Content-Type": "application/json",
}, },
body: JSON.stringify({ body: JSON.stringify({
code, code,
redirect: CALLBACK_URL, redirect: CALLBACK_URL,
}) }),
}).then(fetchRespHandler), }).then(fetchRespHandler),
verify: (idToken) => fetch(`${AUTH_URL}/verify`, { verify: (idToken) =>
fetch(`${AUTH_URL}/verify`, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json" "Content-Type": "application/json",
}, },
body: JSON.stringify({ token: idToken }) body: JSON.stringify({ token: idToken }),
}).then(fetchRespHandler), }).then(fetchRespHandler),
refresh: (refreshToken) => fetch(`${AUTH_URL}/refresh`, { refresh: (refreshToken) =>
fetch(`${AUTH_URL}/refresh`, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json" "Content-Type": "application/json",
}, },
body: JSON.stringify({ refresh_token: refreshToken }) body: JSON.stringify({ refresh_token: refreshToken }),
}).then(fetchRespHandler), }).then(fetchRespHandler),
}; };

View File

@@ -4,9 +4,7 @@ import {
addQueryParams, addQueryParams,
} from "../utils/http"; } from "../utils/http";
const API_ENDPOINT = const API_ENDPOINT = process.env.REACT_APP_UPLOAD_SERVICE_URL;
process.env.REACT_APP_UPLOAD_SERVICE_URL ||
"https://gw-dev.fiskerdps.com/ota_update";
const manifestsAPI = { const manifestsAPI = {
deleteManifest: async (manifest_id, token) => deleteManifest: async (manifest_id, token) =>

View File

@@ -1,49 +1,64 @@
import { getAuthHeaderOptions, fetchRespHandler, addQueryParams } from "../utils/http"; import {
getAuthHeaderOptions,
fetchRespHandler,
addQueryParams,
} from "../utils/http";
const API_ENDPOINT = process.env.REACT_APP_UPLOAD_SERVICE_URL || "https://gw-dev.fiskerdps.com/ota_update"; const API_ENDPOINT = process.env.REACT_APP_UPLOAD_SERVICE_URL;
const updatesAPI = { const updatesAPI = {
createCarUpdates: async (data, token) => fetch(`${API_ENDPOINT}/carupdate`, { createCarUpdates: async (data, token) =>
fetch(`${API_ENDPOINT}/carupdate`, {
method: "POST", method: "POST",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)), headers: Object.assign(
{ "Content-Type": "application/json" },
getAuthHeaderOptions(token)
),
body: JSON.stringify(data), body: JSON.stringify(data),
}) }).then(fetchRespHandler),
.then(fetchRespHandler),
getCarUpdateLog: async (query, token) => { getCarUpdateLog: async (query, token) => {
const u = addQueryParams(`${API_ENDPOINT}/carupdateslog`, query); const u = addQueryParams(`${API_ENDPOINT}/carupdateslog`, query);
return fetch(u, { return fetch(u, {
method: "GET", method: "GET",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)), headers: Object.assign(
}) { "Content-Type": "application/json" },
.then(fetchRespHandler); getAuthHeaderOptions(token)
),
}).then(fetchRespHandler);
}, },
getCarUpdateProgress: async (carupdateids, token) => { getCarUpdateProgress: async (carupdateids, token) => {
const u = `${API_ENDPOINT}/carupdatesstatuses?carupdateids=${carupdateids}`; const u = `${API_ENDPOINT}/carupdatesstatuses?carupdateids=${carupdateids}`;
return fetch(u, { return fetch(u, {
method: "GET", method: "GET",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)), headers: Object.assign(
}) { "Content-Type": "application/json" },
.then(fetchRespHandler); getAuthHeaderOptions(token)
),
}).then(fetchRespHandler);
}, },
getCarUpdates: async (search, token) => { getCarUpdates: async (search, token) => {
const u = addQueryParams(`${API_ENDPOINT}/carupdates`, search); const u = addQueryParams(`${API_ENDPOINT}/carupdates`, search);
return fetch(u, { return fetch(u, {
method: "GET", method: "GET",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)), headers: Object.assign(
}) { "Content-Type": "application/json" },
.then(fetchRespHandler); getAuthHeaderOptions(token)
),
}).then(fetchRespHandler);
}, },
getVINUpdates: async (vin, token) => { getVINUpdates: async (vin, token) => {
const u = addQueryParams(`${API_ENDPOINT}/carupdates`, { vin }); const u = addQueryParams(`${API_ENDPOINT}/carupdates`, { vin });
return fetch(u, { return fetch(u, {
method: "GET", method: "GET",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)), headers: Object.assign(
}) { "Content-Type": "application/json" },
.then(fetchRespHandler); getAuthHeaderOptions(token)
),
}).then(fetchRespHandler);
}, },
}; };

View File

@@ -1,12 +1,12 @@
import axios from 'axios'; import axios from "axios";
const UPLOAD_ENDPOINT = process.env.REACT_APP_UPLOAD_SERVICE_URL || "https://gw-dev.fiskerdps.com/ota_update"; const UPLOAD_ENDPOINT = process.env.REACT_APP_UPLOAD_SERVICE_URL;
const fileField = "file"; const fileField = "file";
export const getCancelToken = () => { export const getCancelToken = () => {
const token = axios.CancelToken; const token = axios.CancelToken;
return token.source(); return token.source();
} };
export const uploadFile = (data, token, onProgress, cancelToken) => { export const uploadFile = (data, token, onProgress, cancelToken) => {
const form = new FormData(); const form = new FormData();
@@ -14,7 +14,7 @@ export const uploadFile = (data, token, onProgress, cancelToken) => {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "multipart/form-data", "Content-Type": "multipart/form-data",
"Authorization": `Bearer ${token}`, Authorization: `Bearer ${token}`,
}, },
cancelToken, cancelToken,
}; };
@@ -24,8 +24,8 @@ export const uploadFile = (data, token, onProgress, cancelToken) => {
...options, ...options,
onUploadProgress: (event) => { onUploadProgress: (event) => {
onProgress(event.loaded / event.total); onProgress(event.loaded / event.total);
} },
} };
} }
for (let key in data) { for (let key in data) {
@@ -34,7 +34,8 @@ export const uploadFile = (data, token, onProgress, cancelToken) => {
form.append(fileField, data[fileField]); form.append(fileField, data[fileField]);
return axios.post(`${UPLOAD_ENDPOINT}/manifestfile`, form, options) return axios
.post(`${UPLOAD_ENDPOINT}/manifestfile`, form, options)
.then((response) => response.data) .then((response) => response.data)
.catch((error) => { .catch((error) => {
if (typeof error.response.data === "string") { if (typeof error.response.data === "string") {

View File

@@ -4,9 +4,7 @@ import {
addQueryParams, addQueryParams,
} from "../utils/http"; } from "../utils/http";
const API_ENDPOINT = const API_ENDPOINT = process.env.REACT_APP_UPLOAD_SERVICE_URL;
process.env.REACT_APP_UPLOAD_SERVICE_URL ||
"https://gw-dev.fiskerdps.com/ota_update";
const vehiclesAPI = { const vehiclesAPI = {
addVehicle: async (vehicle, token) => addVehicle: async (vehicle, token) =>