CEC-179 Car download progress (#32)
* Display download progress * Change default * Fix * Fix * Update readme * Update readme and defaults Fix Dockerfile
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
**/.classpath
|
**/.classpath
|
||||||
**/.dockerignore
|
**/.dockerignore
|
||||||
**/.env
|
|
||||||
**/.git
|
**/.git
|
||||||
**/.gitignore
|
**/.gitignore
|
||||||
**/.project
|
**/.project
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
REACT_APP_AUTH_SERVICE_URL = https://dev-auth.fiskerdps.com
|
REACT_APP_AUTH_SERVICE_URL = http://localhost/compute_auth
|
||||||
REACT_APP_UPLOAD_SERVICE_URL = https://gw-dev.fiskerdps.com
|
REACT_APP_UPLOAD_SERVICE_URL = http://localhost/ota_update
|
||||||
REACT_APP_AUTH_CALLBACK_URL = https://dev-ota-admin.fiskerdps.com/
|
REACT_APP_AUTH_CALLBACK_URL = http://localhost:3000
|
||||||
@@ -8,4 +8,5 @@ RUN npm run build
|
|||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
|
|
||||||
COPY --from=builder build /usr/share/nginx/html
|
COPY --from=builder build /usr/share/nginx/html
|
||||||
|
COPY .env /usr/share/nginx/html/.env
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
17
README.md
17
README.md
@@ -1,16 +1,23 @@
|
|||||||
# Fisker Admin Portal
|
# Fisker Admin Portal
|
||||||
|
|
||||||
Front-end web application for administarting OTA services
|
Front-end web application for administrating services
|
||||||
|
|
||||||
# Setup
|
# Setup
|
||||||
|
|
||||||
Run `./run.sh` from the terminal or
|
Running locally
|
||||||
|
|
||||||
1. Install Node 12
|
1. Install Node 12
|
||||||
2. Run `npm install`
|
2. Run `npm install`
|
||||||
3. Setup environment variables listed in .env.template
|
3. Copy .env.template to .env and edit the service urls for authentication and api services
|
||||||
4. Or copy .env.template to .env
|
4. Run `./run.sh` from the terminal
|
||||||
5. Edit .env with the service urls for authentication and api services
|
5. Access portal at localhost:3000
|
||||||
|
|
||||||
|
Running Docker container
|
||||||
|
|
||||||
|
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 .`
|
||||||
|
3. Start the container `docker run -p 3000:80 fiskerinc/portal`
|
||||||
|
4. Access portal at localhost:3000
|
||||||
|
|
||||||
## Available Scripts
|
## Available Scripts
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ describe("App", () => {
|
|||||||
|
|
||||||
it("Route /package-upload authenticated", async () => {
|
it("Route /package-upload authenticated", async () => {
|
||||||
setToken(TEST_AUTH_OBJECT);
|
setToken(TEST_AUTH_OBJECT);
|
||||||
await check("/package-upload", "h1", "Upload Update Package");
|
await check("/package-upload", "h1", "Create Update Package");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Route /vehicle-add authenticated", async () => {
|
it("Route /vehicle-add authenticated", async () => {
|
||||||
@@ -109,17 +109,17 @@ describe("App", () => {
|
|||||||
|
|
||||||
it("Route /updates authenticated", async () => {
|
it("Route /updates authenticated", async () => {
|
||||||
setToken(TEST_AUTH_OBJECT);
|
setToken(TEST_AUTH_OBJECT);
|
||||||
await check("/updates", "h1", "Updates");
|
await check("/updates", "h1", "Update Packages");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Route /update authenticated", async () => {
|
it("Route /update authenticated", async () => {
|
||||||
setToken(TEST_AUTH_OBJECT);
|
setToken(TEST_AUTH_OBJECT);
|
||||||
await check("/update/1", "h1", "Update Package 1");
|
await check("/update/1", "h1", "Edit Update Package 1");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Route /carupdate-deploy authenticated", async () => {
|
it("Route /carupdate-deploy authenticated", async () => {
|
||||||
setToken(TEST_AUTH_OBJECT);
|
setToken(TEST_AUTH_OBJECT);
|
||||||
await check("/carupdate-deploy/1", "h1", "[1] ");
|
await check("/carupdate-deploy/1", "h1", "Deploy [1]");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Route /carupdate-status authenticated", async () => {
|
it("Route /carupdate-status authenticated", async () => {
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ exports[`App Route / authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
View Updates
|
View Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -156,7 +156,7 @@ exports[`App Route / authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
Create Updates
|
Create Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -427,7 +427,7 @@ exports[`App Route /carupdate-deploy authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
View Updates
|
View Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -449,7 +449,7 @@ exports[`App Route /carupdate-deploy authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
Create Updates
|
Create Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -525,6 +525,7 @@ exports[`App Route /carupdate-deploy authenticated 1`] = `
|
|||||||
<h1
|
<h1
|
||||||
class="MuiTypography-root MuiTypography-h5"
|
class="MuiTypography-root MuiTypography-h5"
|
||||||
>
|
>
|
||||||
|
Deploy
|
||||||
[1]
|
[1]
|
||||||
</h1>
|
</h1>
|
||||||
<form
|
<form
|
||||||
@@ -891,7 +892,7 @@ exports[`App Route /carupdate-status authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
View Updates
|
View Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -913,7 +914,7 @@ exports[`App Route /carupdate-status authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
Create Updates
|
Create Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -1356,7 +1357,7 @@ exports[`App Route /home authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
View Updates
|
View Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -1378,7 +1379,7 @@ exports[`App Route /home authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
Create Updates
|
Create Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -1649,7 +1650,7 @@ exports[`App Route /package-upload authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
View Updates
|
View Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -1671,7 +1672,7 @@ exports[`App Route /package-upload authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
Create Updates
|
Create Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -1744,7 +1745,7 @@ exports[`App Route /package-upload authenticated 1`] = `
|
|||||||
<h1
|
<h1
|
||||||
class="MuiTypography-root MuiTypography-h5"
|
class="MuiTypography-root MuiTypography-h5"
|
||||||
>
|
>
|
||||||
Upload Update Package
|
Create Update Package
|
||||||
</h1>
|
</h1>
|
||||||
<form
|
<form
|
||||||
action="{onSubmit}"
|
action="{onSubmit}"
|
||||||
@@ -1847,12 +1848,19 @@ exports[`App Route /package-upload authenticated 1`] = `
|
|||||||
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
|
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-outlined"
|
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-outlined Mui-required Mui-required"
|
||||||
data-shrink="false"
|
data-shrink="false"
|
||||||
for="description"
|
for="description"
|
||||||
id="description-label"
|
id="description-label"
|
||||||
>
|
>
|
||||||
Description
|
Description
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiFormLabel-asterisk MuiInputLabel-asterisk"
|
||||||
|
>
|
||||||
|
|
||||||
|
*
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div
|
||||||
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-fullWidth MuiInputBase-formControl MuiInputBase-multiline MuiOutlinedInput-multiline"
|
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-fullWidth MuiInputBase-formControl MuiInputBase-multiline MuiOutlinedInput-multiline"
|
||||||
@@ -1864,6 +1872,7 @@ exports[`App Route /package-upload authenticated 1`] = `
|
|||||||
maxlength="5120"
|
maxlength="5120"
|
||||||
name="description"
|
name="description"
|
||||||
placeholder="Package description"
|
placeholder="Package description"
|
||||||
|
required=""
|
||||||
rows="4"
|
rows="4"
|
||||||
/>
|
/>
|
||||||
<fieldset
|
<fieldset
|
||||||
@@ -1875,6 +1884,7 @@ exports[`App Route /package-upload authenticated 1`] = `
|
|||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
Description
|
Description
|
||||||
|
*
|
||||||
</span>
|
</span>
|
||||||
</legend>
|
</legend>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -1884,12 +1894,19 @@ exports[`App Route /package-upload authenticated 1`] = `
|
|||||||
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
|
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-outlined"
|
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-outlined Mui-required Mui-required"
|
||||||
data-shrink="false"
|
data-shrink="false"
|
||||||
for="releasenotes"
|
for="releasenotes"
|
||||||
id="releasenotes-label"
|
id="releasenotes-label"
|
||||||
>
|
>
|
||||||
Release Notes URL
|
Release Notes URL
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiFormLabel-asterisk MuiInputLabel-asterisk"
|
||||||
|
>
|
||||||
|
|
||||||
|
*
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div
|
||||||
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-fullWidth MuiInputBase-formControl"
|
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-fullWidth MuiInputBase-formControl"
|
||||||
@@ -1901,6 +1918,7 @@ exports[`App Route /package-upload authenticated 1`] = `
|
|||||||
maxlength="1024"
|
maxlength="1024"
|
||||||
name="releasenotes"
|
name="releasenotes"
|
||||||
placeholder="Release Notes URL"
|
placeholder="Release Notes URL"
|
||||||
|
required=""
|
||||||
type="text"
|
type="text"
|
||||||
value=""
|
value=""
|
||||||
/>
|
/>
|
||||||
@@ -1913,6 +1931,7 @@ exports[`App Route /package-upload authenticated 1`] = `
|
|||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
Release Notes URL
|
Release Notes URL
|
||||||
|
*
|
||||||
</span>
|
</span>
|
||||||
</legend>
|
</legend>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -2164,7 +2183,7 @@ exports[`App Route /page-not-found authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
View Updates
|
View Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -2186,7 +2205,7 @@ exports[`App Route /page-not-found authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
Create Updates
|
Create Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -2446,7 +2465,7 @@ exports[`App Route /update authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
View Updates
|
View Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -2468,7 +2487,7 @@ exports[`App Route /update authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
Create Updates
|
Create Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -2541,7 +2560,7 @@ exports[`App Route /update authenticated 1`] = `
|
|||||||
<h1
|
<h1
|
||||||
class="MuiTypography-root MuiTypography-h5"
|
class="MuiTypography-root MuiTypography-h5"
|
||||||
>
|
>
|
||||||
Update Package
|
Edit Update Package
|
||||||
1
|
1
|
||||||
</h1>
|
</h1>
|
||||||
<form
|
<form
|
||||||
@@ -2999,7 +3018,7 @@ exports[`App Route /updates authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
View Updates
|
View Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -3021,7 +3040,7 @@ exports[`App Route /updates authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
Create Updates
|
Create Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -3095,7 +3114,7 @@ exports[`App Route /updates authenticated 1`] = `
|
|||||||
<h1
|
<h1
|
||||||
class="MuiTypography-root MuiTypography-h5"
|
class="MuiTypography-root MuiTypography-h5"
|
||||||
>
|
>
|
||||||
Updates
|
Update Packages
|
||||||
</h1>
|
</h1>
|
||||||
<div
|
<div
|
||||||
class="MuiTableContainer-root"
|
class="MuiTableContainer-root"
|
||||||
@@ -3465,7 +3484,7 @@ exports[`App Route /vehicle-add authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
View Updates
|
View Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -3487,7 +3506,7 @@ exports[`App Route /vehicle-add authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
Create Updates
|
Create Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -3921,7 +3940,7 @@ exports[`App Route /vehicle-status authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
View Updates
|
View Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -3943,7 +3962,7 @@ exports[`App Route /vehicle-status authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
Create Updates
|
Create Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -4388,7 +4407,7 @@ exports[`App Route /vehicles authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
View Updates
|
View Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -4410,7 +4429,7 @@ exports[`App Route /vehicles authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
Create Updates
|
Create Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useParams } from "react-router";
|
import { useParams, Redirect } from "react-router";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Chip,
|
Chip,
|
||||||
@@ -44,6 +44,7 @@ const MainForm = () => {
|
|||||||
const [releaseNotesLink, setReleaseNotesLink] = useState("");
|
const [releaseNotesLink, setReleaseNotesLink] = useState("");
|
||||||
const [createDate, setCreateDate] = useState("");
|
const [createDate, setCreateDate] = useState("");
|
||||||
const [selectedVehicles, setSelectedVehicles] = useState([]);
|
const [selectedVehicles, setSelectedVehicles] = useState([]);
|
||||||
|
const [redirect, setRedirect] = useState("");
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const handleVehiclesChange = (event) => {
|
const handleVehiclesChange = (event) => {
|
||||||
@@ -60,7 +61,7 @@ const MainForm = () => {
|
|||||||
setMessage(
|
setMessage(
|
||||||
`Deployed ${packageName} ${version} to ${selectedVehicles.length} cars`
|
`Deployed ${packageName} ${version} to ${selectedVehicles.length} cars`
|
||||||
);
|
);
|
||||||
setSelectedVehicles([]);
|
setRedirect(`/carupdate-status/${packageid}`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setMessage(e.message);
|
setMessage(e.message);
|
||||||
}
|
}
|
||||||
@@ -95,10 +96,14 @@ const MainForm = () => {
|
|||||||
setCreateDate(tsLocalDateTimeString(data.timestamp));
|
setCreateDate(tsLocalDateTimeString(data.timestamp));
|
||||||
}, [packages]);
|
}, [packages]);
|
||||||
|
|
||||||
|
if (redirect.length > 0) {
|
||||||
|
return <Redirect to={redirect} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.paper}>
|
<div className={classes.paper}>
|
||||||
<Typography component="h1" variant="h5">
|
<Typography component="h1" variant="h5">
|
||||||
{`[${packageid}] ${packageName} ${version}`}
|
Deploy {`${packageName} ${version} [${packageid}]`}
|
||||||
</Typography>
|
</Typography>
|
||||||
<form className={classes.form} noValidate action="{onSubmit}">
|
<form className={classes.form} noValidate action="{onSubmit}">
|
||||||
<TextField
|
<TextField
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useParams } from "react-router";
|
import { useParams } from "react-router";
|
||||||
import {
|
import {
|
||||||
|
LinearProgress,
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
@@ -25,16 +26,17 @@ import VehicleStatus from "../../Cars/StatusModal";
|
|||||||
const MainForm = () => {
|
const MainForm = () => {
|
||||||
const { packageid } = useParams();
|
const { packageid } = useParams();
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [pageSize, setPageSize] = useState(10);
|
const [pageSize, setPageSize] = useState(25);
|
||||||
const [pageIndex, setPageIndex] = useState(0);
|
const [pageIndex, setPageIndex] = useState(0);
|
||||||
const [viewVIN, setViewVIN] = useState(null);
|
const [viewVIN, setViewVIN] = useState(null);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getCarUpdates,
|
getCarUpdates,
|
||||||
carUpdates,
|
carUpdates,
|
||||||
totalCarUpdates,
|
totalCarUpdates,
|
||||||
getPackages,
|
getPackages,
|
||||||
packages,
|
packages,
|
||||||
|
startMonitor,
|
||||||
|
stopMonitor,
|
||||||
} = useUpdatesContext();
|
} = useUpdatesContext();
|
||||||
const { setMessage } = useStatusContext();
|
const { setMessage } = useStatusContext();
|
||||||
const {
|
const {
|
||||||
@@ -54,6 +56,7 @@ const MainForm = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
try {
|
try {
|
||||||
|
stopMonitor();
|
||||||
getCarUpdates(
|
getCarUpdates(
|
||||||
{
|
{
|
||||||
packageid,
|
packageid,
|
||||||
@@ -68,6 +71,19 @@ const MainForm = () => {
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [pageIndex, pageSize, token]);
|
}, [pageIndex, pageSize, token]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
try {
|
||||||
|
if (carUpdates.length === 0) return;
|
||||||
|
startMonitor(token);
|
||||||
|
} catch (e) {
|
||||||
|
setMessage(e.message);
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
stopMonitor();
|
||||||
|
};
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, [carUpdates]);
|
||||||
|
|
||||||
const handleChangePageIndex = (event, newIndex) => {
|
const handleChangePageIndex = (event, newIndex) => {
|
||||||
setPageIndex(newIndex);
|
setPageIndex(newIndex);
|
||||||
};
|
};
|
||||||
@@ -113,7 +129,15 @@ const MainForm = () => {
|
|||||||
{row.vin}
|
{row.vin}
|
||||||
</span>
|
</span>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="center">{row.status}</TableCell>
|
<TableCell align="center">
|
||||||
|
{row.status}
|
||||||
|
{row.progress > 0 && (
|
||||||
|
<LinearProgress
|
||||||
|
variant="determinate"
|
||||||
|
value={row.progress}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{LocalDateTimeString(row.created)}
|
{LocalDateTimeString(row.created)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { LocalDateTimeString } from "../../../utils/dates";
|
|||||||
|
|
||||||
const MainForm = () => {
|
const MainForm = () => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [pageSize, setPageSize] = useState(5);
|
const [pageSize, setPageSize] = useState(25);
|
||||||
const [pageIndex, setPageIndex] = useState(0);
|
const [pageIndex, setPageIndex] = useState(0);
|
||||||
const { getVehicles, vehicles, totalVehicles } = useVehicleContext();
|
const { getVehicles, vehicles, totalVehicles } = useVehicleContext();
|
||||||
const { setMessage } = useStatusContext();
|
const { setMessage } = useStatusContext();
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ export const FileUploadProvider = ({ children }) => {
|
|||||||
const [progress, setProgress] = useState(0);
|
const [progress, setProgress] = useState(0);
|
||||||
const [status, setStatus] = useState(null);
|
const [status, setStatus] = useState(null);
|
||||||
const [cancelUpload, setCancelUpload] = useState(null);
|
const [cancelUpload, setCancelUpload] = useState(null);
|
||||||
const [linkURL, setLinkURL] = useState(null);
|
|
||||||
const [files, setFiles] = useState(null);
|
const [files, setFiles] = useState(null);
|
||||||
|
|
||||||
const done = () => {
|
const done = () => {
|
||||||
@@ -45,6 +44,14 @@ export const FileUploadProvider = ({ children }) => {
|
|||||||
if (!accessToken || accessToken.length === 0) {
|
if (!accessToken || accessToken.length === 0) {
|
||||||
throw new Error("Access token required");
|
throw new Error("Access token required");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!formData.description || formData.description.length === 0) {
|
||||||
|
throw new Error("Package update description required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!formData.releasenotes || formData.releasenotes.length === 0) {
|
||||||
|
throw new Error("Package update release notes link required");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const upload = async (formData, accessToken, uploadFiles) => {
|
const upload = async (formData, accessToken, uploadFiles) => {
|
||||||
@@ -55,7 +62,6 @@ export const FileUploadProvider = ({ children }) => {
|
|||||||
const filename = file.name;
|
const filename = file.name;
|
||||||
|
|
||||||
setUploading(true);
|
setUploading(true);
|
||||||
setLinkURL(null);
|
|
||||||
setProgress(0);
|
setProgress(0);
|
||||||
setStatus(`Uploading ${filename}`);
|
setStatus(`Uploading ${filename}`);
|
||||||
setCancelUpload(getCancelToken());
|
setCancelUpload(getCancelToken());
|
||||||
@@ -70,11 +76,11 @@ export const FileUploadProvider = ({ children }) => {
|
|||||||
if (data.message) {
|
if (data.message) {
|
||||||
throw new Error(`${data.error}. ${data.message}`);
|
throw new Error(`${data.error}. ${data.message}`);
|
||||||
}
|
}
|
||||||
const url = data && data.link ? data.link : "No URL available";
|
|
||||||
setLinkURL(url);
|
|
||||||
setStatus(`Uploaded ${filename}`);
|
setStatus(`Uploaded ${filename}`);
|
||||||
setCancelUpload(null);
|
setCancelUpload(null);
|
||||||
setProgress(100);
|
setProgress(100);
|
||||||
|
|
||||||
|
return data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setUploading(true);
|
setUploading(true);
|
||||||
setStatus(`Error occured: ${e.message}`);
|
setStatus(`Error occured: ${e.message}`);
|
||||||
@@ -88,7 +94,6 @@ export const FileUploadProvider = ({ children }) => {
|
|||||||
uploading,
|
uploading,
|
||||||
progress,
|
progress,
|
||||||
status,
|
status,
|
||||||
linkURL,
|
|
||||||
files,
|
files,
|
||||||
upload,
|
upload,
|
||||||
cancel,
|
cancel,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
fireEvent,
|
fireEvent,
|
||||||
waitFor,
|
waitFor,
|
||||||
} from "@testing-library/react";
|
} from "@testing-library/react";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
import { setUploadFileDelay } from "../../services/uploadFile";
|
import { setUploadFileDelay } from "../../services/uploadFile";
|
||||||
import {
|
import {
|
||||||
@@ -30,21 +31,26 @@ describe("FileUploadContext", () => {
|
|||||||
progress,
|
progress,
|
||||||
uploading,
|
uploading,
|
||||||
status,
|
status,
|
||||||
linkURL,
|
|
||||||
upload,
|
upload,
|
||||||
cancel,
|
cancel,
|
||||||
} = useFileUploadContext();
|
} = useFileUploadContext();
|
||||||
const { message, setMessage } = useStatusContext();
|
const { message, setMessage } = useStatusContext();
|
||||||
|
const [link, setLink] = useState(null);
|
||||||
const TEST_FILE = [{ name: "test.jpg", size: 0 }];
|
const TEST_FILE = [{ name: "test.jpg", size: 0 }];
|
||||||
const TEST_ACCESSTOKEN = "ACCESSTOKEN";
|
const TEST_ACCESSTOKEN = "ACCESSTOKEN";
|
||||||
const TEST_FORMDATA = {
|
const TEST_FORMDATA = {
|
||||||
packagename: "TEST",
|
packagename: "TEST",
|
||||||
version: "VERSION",
|
version: "VERSION",
|
||||||
vehicles: ["VIN"],
|
vehicles: ["VIN"],
|
||||||
|
description: "TEST DESC",
|
||||||
|
releasenotes: "http://releasenotes.com",
|
||||||
};
|
};
|
||||||
const exec = async (form, token, file) => {
|
const exec = async (form, token, file) => {
|
||||||
try {
|
try {
|
||||||
await upload(form, token, file);
|
const data = await upload(form, token, file);
|
||||||
|
if (data.link) {
|
||||||
|
setLink(data.link);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setMessage(e.message);
|
setMessage(e.message);
|
||||||
}
|
}
|
||||||
@@ -56,7 +62,7 @@ describe("FileUploadContext", () => {
|
|||||||
<div data-testid="progress">{progress.toString()}</div>
|
<div data-testid="progress">{progress.toString()}</div>
|
||||||
<div data-testid="status">{status}</div>
|
<div data-testid="status">{status}</div>
|
||||||
<div data-testid="message">{message}</div>
|
<div data-testid="message">{message}</div>
|
||||||
<div data-testid="linkURL">{linkURL}</div>
|
<div data-testid="linkURL">{link}</div>
|
||||||
<button
|
<button
|
||||||
data-testid="uploadNoFile"
|
data-testid="uploadNoFile"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ export const UpdatesProvider = ({ children }) => {
|
|||||||
const [carUpdates, setCarUpdates] = useState([]);
|
const [carUpdates, setCarUpdates] = useState([]);
|
||||||
const [totalPackages, setTotalPackages] = useState(0);
|
const [totalPackages, setTotalPackages] = useState(0);
|
||||||
const [totalCarUpdates, setTotalCarUpdates] = useState(0);
|
const [totalCarUpdates, setTotalCarUpdates] = useState(0);
|
||||||
|
const [delayCount, setDelayCount] = useState(0);
|
||||||
|
let progressTimer = 0;
|
||||||
|
|
||||||
const getPackages = async (search, token) => {
|
const getPackages = async (search, token) => {
|
||||||
let result;
|
let result;
|
||||||
@@ -96,6 +98,86 @@ export const UpdatesProvider = ({ children }) => {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const applyProgressStatus = (item, status) => {
|
||||||
|
if (status.msg === "DONE") {
|
||||||
|
delete item.progress;
|
||||||
|
item.status = "downloaded";
|
||||||
|
} else if (status.msg === "downloading" && status.total > 0) {
|
||||||
|
let progress = Math.floor((100 * status.bytes) / status.total);
|
||||||
|
if (progress > 99) progress = 0;
|
||||||
|
item.progress = progress;
|
||||||
|
item.status = `downloading ${progress}%`;
|
||||||
|
} else if (status.error > 0) {
|
||||||
|
item.status = "download error";
|
||||||
|
} else {
|
||||||
|
item.status = "downloading";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const applyProgressStatuses = (statuses) => {
|
||||||
|
let items = JSON.parse(JSON.stringify(carUpdates));
|
||||||
|
|
||||||
|
statuses.forEach((status) => {
|
||||||
|
let item = items.find((item) => status.id === item.id);
|
||||||
|
if (!item || status.id === 0) return;
|
||||||
|
applyProgressStatus(item, status);
|
||||||
|
});
|
||||||
|
|
||||||
|
setCarUpdates(items);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateStatusProgress = async (token) => {
|
||||||
|
stopMonitor();
|
||||||
|
|
||||||
|
if (!token || carUpdates.length === 0) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setBusy(true);
|
||||||
|
const carupdateids = carUpdates.reduce((accum, update) => {
|
||||||
|
if (update.status !== "downloaded") accum.push(update.id);
|
||||||
|
return accum;
|
||||||
|
}, []);
|
||||||
|
if (carupdateids.length === 0) return;
|
||||||
|
|
||||||
|
const result = await api.getCarUpdateProgress(
|
||||||
|
carupdateids.join(","),
|
||||||
|
token
|
||||||
|
);
|
||||||
|
if (result.error)
|
||||||
|
throw new Error(`Get update progress error. ${result.message}`);
|
||||||
|
|
||||||
|
applyProgressStatuses(result.statuses);
|
||||||
|
} catch (e) {
|
||||||
|
} finally {
|
||||||
|
setBusy(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDelay = () => {
|
||||||
|
if (delayCount < 3) {
|
||||||
|
setDelayCount(delayCount + 1);
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
for (let i = 0, len = carUpdates.length; i < len; i++) {
|
||||||
|
if (carUpdates[i].status.indexOf("downloading") > -1) return 1000;
|
||||||
|
}
|
||||||
|
return 10000;
|
||||||
|
};
|
||||||
|
|
||||||
|
const startMonitor = async (token) => {
|
||||||
|
const delay = getDelay();
|
||||||
|
stopMonitor();
|
||||||
|
progressTimer = setTimeout(() => {
|
||||||
|
updateStatusProgress(token);
|
||||||
|
}, delay);
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopMonitor = async () => {
|
||||||
|
if (progressTimer === 0) return;
|
||||||
|
clearTimeout(progressTimer);
|
||||||
|
progressTimer = 0;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UpdatesContext.Provider
|
<UpdatesContext.Provider
|
||||||
value={{
|
value={{
|
||||||
@@ -109,6 +191,8 @@ export const UpdatesProvider = ({ children }) => {
|
|||||||
createCarUpdates,
|
createCarUpdates,
|
||||||
getCarUpdates,
|
getCarUpdates,
|
||||||
getVINUpdates,
|
getVINUpdates,
|
||||||
|
startMonitor,
|
||||||
|
stopMonitor,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -23,4 +23,6 @@ export const useUpdatesContext = () => ({
|
|||||||
createCarUpdates: jest.fn((data) => data),
|
createCarUpdates: jest.fn((data) => data),
|
||||||
getCarUpdates: jest.fn(() => carUpdates),
|
getCarUpdates: jest.fn(() => carUpdates),
|
||||||
getVINUpdates: jest.fn(() => carUpdates),
|
getVINUpdates: jest.fn(() => carUpdates),
|
||||||
|
startMonitor: jest.fn(),
|
||||||
|
stopMonitor: jest.fn(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ const menuData = [
|
|||||||
roles: [],
|
roles: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "View Updates",
|
label: "View Packages",
|
||||||
to: "/updates",
|
to: "/updates",
|
||||||
roles: [Roles.CREATE, Roles.READ],
|
roles: [Roles.CREATE, Roles.READ],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Create Updates",
|
label: "Create Packages",
|
||||||
to: "/package-upload",
|
to: "/package-upload",
|
||||||
roles: [Roles.CREATE],
|
roles: [Roles.CREATE],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ exports[`SideMenu Authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
View Updates
|
View Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -66,7 +66,7 @@ exports[`SideMenu Authenticated 1`] = `
|
|||||||
<span
|
<span
|
||||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
>
|
>
|
||||||
Create Updates
|
Create Packages
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ exports[`File Upload Form Should render 1`] = `
|
|||||||
<h1
|
<h1
|
||||||
class="MuiTypography-root MuiTypography-h5"
|
class="MuiTypography-root MuiTypography-h5"
|
||||||
>
|
>
|
||||||
Upload Update Package
|
Create Update Package
|
||||||
</h1>
|
</h1>
|
||||||
<form
|
<form
|
||||||
action="{onSubmit}"
|
action="{onSubmit}"
|
||||||
@@ -114,12 +114,19 @@ exports[`File Upload Form Should render 1`] = `
|
|||||||
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
|
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-outlined"
|
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-outlined Mui-required Mui-required"
|
||||||
data-shrink="false"
|
data-shrink="false"
|
||||||
for="description"
|
for="description"
|
||||||
id="description-label"
|
id="description-label"
|
||||||
>
|
>
|
||||||
Description
|
Description
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiFormLabel-asterisk MuiInputLabel-asterisk"
|
||||||
|
>
|
||||||
|
|
||||||
|
*
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div
|
||||||
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-fullWidth MuiInputBase-formControl MuiInputBase-multiline MuiOutlinedInput-multiline"
|
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-fullWidth MuiInputBase-formControl MuiInputBase-multiline MuiOutlinedInput-multiline"
|
||||||
@@ -131,6 +138,7 @@ exports[`File Upload Form Should render 1`] = `
|
|||||||
maxlength="5120"
|
maxlength="5120"
|
||||||
name="description"
|
name="description"
|
||||||
placeholder="Package description"
|
placeholder="Package description"
|
||||||
|
required=""
|
||||||
rows="4"
|
rows="4"
|
||||||
/>
|
/>
|
||||||
<fieldset
|
<fieldset
|
||||||
@@ -142,6 +150,7 @@ exports[`File Upload Form Should render 1`] = `
|
|||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
Description
|
Description
|
||||||
|
*
|
||||||
</span>
|
</span>
|
||||||
</legend>
|
</legend>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -151,12 +160,19 @@ exports[`File Upload Form Should render 1`] = `
|
|||||||
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
|
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-outlined"
|
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-outlined Mui-required Mui-required"
|
||||||
data-shrink="false"
|
data-shrink="false"
|
||||||
for="releasenotes"
|
for="releasenotes"
|
||||||
id="releasenotes-label"
|
id="releasenotes-label"
|
||||||
>
|
>
|
||||||
Release Notes URL
|
Release Notes URL
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiFormLabel-asterisk MuiInputLabel-asterisk"
|
||||||
|
>
|
||||||
|
|
||||||
|
*
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div
|
||||||
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-fullWidth MuiInputBase-formControl"
|
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-fullWidth MuiInputBase-formControl"
|
||||||
@@ -168,6 +184,7 @@ exports[`File Upload Form Should render 1`] = `
|
|||||||
maxlength="1024"
|
maxlength="1024"
|
||||||
name="releasenotes"
|
name="releasenotes"
|
||||||
placeholder="Release Notes URL"
|
placeholder="Release Notes URL"
|
||||||
|
required=""
|
||||||
type="text"
|
type="text"
|
||||||
value=""
|
value=""
|
||||||
/>
|
/>
|
||||||
@@ -180,6 +197,7 @@ exports[`File Upload Form Should render 1`] = `
|
|||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
Release Notes URL
|
Release Notes URL
|
||||||
|
*
|
||||||
</span>
|
</span>
|
||||||
</legend>
|
</legend>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useRef } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import { Button, TextField, Typography } from "@material-ui/core";
|
import { Button, TextField, Typography } from "@material-ui/core";
|
||||||
import { DropzoneArea } from "material-ui-dropzone";
|
import { DropzoneArea } from "material-ui-dropzone";
|
||||||
import { useUserContext } from "../../Contexts/UserContext";
|
import { useUserContext } from "../../Contexts/UserContext";
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
} from "../../Contexts/FileUploadContext";
|
} from "../../Contexts/FileUploadContext";
|
||||||
import ModalProgressBar from "../../ModalProgressBar";
|
import ModalProgressBar from "../../ModalProgressBar";
|
||||||
import useStyles from "../../useStyles";
|
import useStyles from "../../useStyles";
|
||||||
|
import { Redirect } from "react-router";
|
||||||
|
|
||||||
const FileUploadZone = ({ classes, token }) => {
|
const FileUploadZone = ({ classes, token }) => {
|
||||||
const { setFiles } = useFileUploadContext();
|
const { setFiles } = useFileUploadContext();
|
||||||
@@ -39,9 +40,10 @@ const FileUploadZone = ({ classes, token }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const MainForm = () => {
|
const MainForm = () => {
|
||||||
const { uploading, upload, files } = useFileUploadContext();
|
const { uploading, upload, files, cancel } = useFileUploadContext();
|
||||||
const { token } = useUserContext();
|
const { token } = useUserContext();
|
||||||
const { setMessage } = useStatusContext();
|
const { setMessage } = useStatusContext();
|
||||||
|
const [redirect, setRedirect] = useState(null);
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const packagenameEl = useRef(null);
|
const packagenameEl = useRef(null);
|
||||||
const versionEl = useRef(null);
|
const versionEl = useRef(null);
|
||||||
@@ -59,17 +61,26 @@ const MainForm = () => {
|
|||||||
description: descEl.current.value,
|
description: descEl.current.value,
|
||||||
releasenotes: releasenotesEl.current.value,
|
releasenotes: releasenotesEl.current.value,
|
||||||
};
|
};
|
||||||
|
const result = await upload(formData, authToken, files);
|
||||||
|
|
||||||
await upload(formData, authToken, files);
|
if (!result || result.error) return;
|
||||||
|
|
||||||
|
cancel();
|
||||||
|
setMessage(`Package uploaded`);
|
||||||
|
setRedirect(`/carupdate-deploy/${result.id}`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setMessage(e.message);
|
setMessage(e.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (redirect && redirect.length > 0) {
|
||||||
|
return <Redirect to={redirect} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.paper}>
|
<div className={classes.paper}>
|
||||||
<Typography component="h1" variant="h5">
|
<Typography component="h1" variant="h5">
|
||||||
Upload Update Package
|
Create Update Package
|
||||||
</Typography>
|
</Typography>
|
||||||
<form className={classes.form} noValidate action="{onSubmit}">
|
<form className={classes.form} noValidate action="{onSubmit}">
|
||||||
<TextField
|
<TextField
|
||||||
@@ -107,6 +118,7 @@ const MainForm = () => {
|
|||||||
inputProps={{
|
inputProps={{
|
||||||
maxLength: "5120",
|
maxLength: "5120",
|
||||||
}}
|
}}
|
||||||
|
required
|
||||||
fullWidth
|
fullWidth
|
||||||
multiline
|
multiline
|
||||||
rows={4}
|
rows={4}
|
||||||
@@ -122,6 +134,7 @@ const MainForm = () => {
|
|||||||
inputProps={{
|
inputProps={{
|
||||||
maxLength: "1024",
|
maxLength: "1024",
|
||||||
}}
|
}}
|
||||||
|
required
|
||||||
fullWidth
|
fullWidth
|
||||||
placeholder="Release Notes URL"
|
placeholder="Release Notes URL"
|
||||||
inputRef={releasenotesEl}
|
inputRef={releasenotesEl}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ const MainForm = () => {
|
|||||||
return (
|
return (
|
||||||
<div className={classes.paper}>
|
<div className={classes.paper}>
|
||||||
<Typography component="h1" variant="h5">
|
<Typography component="h1" variant="h5">
|
||||||
Update Package {id}
|
Edit Update Package {id}
|
||||||
</Typography>
|
</Typography>
|
||||||
<form className={classes.form} noValidate action="{onSubmit}">
|
<form className={classes.form} noValidate action="{onSubmit}">
|
||||||
<TextField
|
<TextField
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { Roles, hasRole } from "../../../utils/roles";
|
|||||||
|
|
||||||
const UpdatePackagesList = () => {
|
const UpdatePackagesList = () => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [pageSize, setPageSize] = useState(5);
|
const [pageSize, setPageSize] = useState(25);
|
||||||
const [pageIndex, setPageIndex] = useState(0);
|
const [pageIndex, setPageIndex] = useState(0);
|
||||||
const { getPackages, packages, totalPackages } = useUpdatesContext();
|
const { getPackages, packages, totalPackages } = useUpdatesContext();
|
||||||
const {
|
const {
|
||||||
@@ -98,7 +98,7 @@ const UpdatePackagesList = () => {
|
|||||||
return (
|
return (
|
||||||
<div className={classes.paper} style={{ height: 700, width: "100%" }}>
|
<div className={classes.paper} style={{ height: 700, width: "100%" }}>
|
||||||
<Typography component="h1" variant="h5">
|
<Typography component="h1" variant="h5">
|
||||||
Updates
|
Update Packages
|
||||||
</Typography>
|
</Typography>
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
<Table>
|
<Table>
|
||||||
|
|||||||
@@ -41,11 +41,15 @@ const updatesAPI = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getCarUpdates: async (filter, token) => {
|
getCarUpdates: async (filter, token) => {
|
||||||
return { data:[] };
|
return { data: [] };
|
||||||
},
|
},
|
||||||
|
|
||||||
getVINUpdates: async (vin, token) => {
|
getVINUpdates: async (vin, token) => {
|
||||||
return { data:[] };
|
return { data: [] };
|
||||||
|
},
|
||||||
|
|
||||||
|
getCarUpdateProgress: async (carupdateids, token) => {
|
||||||
|
return { statuses: [] };
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,15 @@ const updatesAPI = {
|
|||||||
})
|
})
|
||||||
.then(fetchRespHandler);
|
.then(fetchRespHandler);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getCarUpdateProgress: async (carupdateids, token) => {
|
||||||
|
var u = `${API_ENDPOINT}/carupdatesstatuses?carupdateids=${carupdateids}`;
|
||||||
|
return fetch(u, {
|
||||||
|
method: "GET",
|
||||||
|
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
|
||||||
|
})
|
||||||
|
.then(fetchRespHandler);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default updatesAPI;
|
export default updatesAPI;
|
||||||
|
|||||||
Reference in New Issue
Block a user