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:
John Wu
2021-04-30 12:58:31 -07:00
committed by GitHub
parent 7a1125cb1f
commit 4280191e49
21 changed files with 268 additions and 72 deletions

View File

@@ -1,6 +1,5 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project

View File

@@ -1,3 +1,3 @@
REACT_APP_AUTH_SERVICE_URL = https://dev-auth.fiskerdps.com
REACT_APP_UPLOAD_SERVICE_URL = https://gw-dev.fiskerdps.com
REACT_APP_AUTH_CALLBACK_URL = https://dev-ota-admin.fiskerdps.com/
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

View File

@@ -8,4 +8,5 @@ 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

View File

@@ -1,16 +1,23 @@
# Fisker Admin Portal
Front-end web application for administarting OTA services
Front-end web application for administrating services
# Setup
Run `./run.sh` from the terminal or
Running locally
1. Install Node 12
2. Run `npm install`
3. Setup environment variables listed in .env.template
4. Or copy .env.template to .env
5. Edit .env with the service urls for authentication and api services
3. Copy .env.template to .env and edit the service urls for authentication and api services
4. Run `./run.sh` from the terminal
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

View File

@@ -99,7 +99,7 @@ describe("App", () => {
it("Route /package-upload authenticated", async () => {
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 () => {
@@ -109,17 +109,17 @@ describe("App", () => {
it("Route /updates authenticated", async () => {
setToken(TEST_AUTH_OBJECT);
await check("/updates", "h1", "Updates");
await check("/updates", "h1", "Update Packages");
});
it("Route /update authenticated", async () => {
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 () => {
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 () => {

View File

@@ -134,7 +134,7 @@ exports[`App Route / authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
View Updates
View Packages
</span>
</div>
<span
@@ -156,7 +156,7 @@ exports[`App Route / authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Create Updates
Create Packages
</span>
</div>
<span
@@ -427,7 +427,7 @@ exports[`App Route /carupdate-deploy authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
View Updates
View Packages
</span>
</div>
<span
@@ -449,7 +449,7 @@ exports[`App Route /carupdate-deploy authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Create Updates
Create Packages
</span>
</div>
<span
@@ -525,7 +525,8 @@ exports[`App Route /carupdate-deploy authenticated 1`] = `
<h1
class="MuiTypography-root MuiTypography-h5"
>
[1]
Deploy
[1]
</h1>
<form
action="{onSubmit}"
@@ -891,7 +892,7 @@ exports[`App Route /carupdate-status authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
View Updates
View Packages
</span>
</div>
<span
@@ -913,7 +914,7 @@ exports[`App Route /carupdate-status authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Create Updates
Create Packages
</span>
</div>
<span
@@ -1356,7 +1357,7 @@ exports[`App Route /home authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
View Updates
View Packages
</span>
</div>
<span
@@ -1378,7 +1379,7 @@ exports[`App Route /home authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Create Updates
Create Packages
</span>
</div>
<span
@@ -1649,7 +1650,7 @@ exports[`App Route /package-upload authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
View Updates
View Packages
</span>
</div>
<span
@@ -1671,7 +1672,7 @@ exports[`App Route /package-upload authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Create Updates
Create Packages
</span>
</div>
<span
@@ -1744,7 +1745,7 @@ exports[`App Route /package-upload authenticated 1`] = `
<h1
class="MuiTypography-root MuiTypography-h5"
>
Upload Update Package
Create Update Package
</h1>
<form
action="{onSubmit}"
@@ -1847,12 +1848,19 @@ exports[`App Route /package-upload authenticated 1`] = `
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
>
<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"
for="description"
id="description-label"
>
Description
<span
aria-hidden="true"
class="MuiFormLabel-asterisk MuiInputLabel-asterisk"
>
*
</span>
</label>
<div
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"
name="description"
placeholder="Package description"
required=""
rows="4"
/>
<fieldset
@@ -1875,6 +1884,7 @@ exports[`App Route /package-upload authenticated 1`] = `
>
<span>
Description
 *
</span>
</legend>
</fieldset>
@@ -1884,12 +1894,19 @@ exports[`App Route /package-upload authenticated 1`] = `
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
>
<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"
for="releasenotes"
id="releasenotes-label"
>
Release Notes URL
<span
aria-hidden="true"
class="MuiFormLabel-asterisk MuiInputLabel-asterisk"
>
*
</span>
</label>
<div
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-fullWidth MuiInputBase-formControl"
@@ -1901,6 +1918,7 @@ exports[`App Route /package-upload authenticated 1`] = `
maxlength="1024"
name="releasenotes"
placeholder="Release Notes URL"
required=""
type="text"
value=""
/>
@@ -1913,6 +1931,7 @@ exports[`App Route /package-upload authenticated 1`] = `
>
<span>
Release Notes URL
 *
</span>
</legend>
</fieldset>
@@ -2164,7 +2183,7 @@ exports[`App Route /page-not-found authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
View Updates
View Packages
</span>
</div>
<span
@@ -2186,7 +2205,7 @@ exports[`App Route /page-not-found authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Create Updates
Create Packages
</span>
</div>
<span
@@ -2446,7 +2465,7 @@ exports[`App Route /update authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
View Updates
View Packages
</span>
</div>
<span
@@ -2468,7 +2487,7 @@ exports[`App Route /update authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Create Updates
Create Packages
</span>
</div>
<span
@@ -2541,7 +2560,7 @@ exports[`App Route /update authenticated 1`] = `
<h1
class="MuiTypography-root MuiTypography-h5"
>
Update Package
Edit Update Package
1
</h1>
<form
@@ -2999,7 +3018,7 @@ exports[`App Route /updates authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
View Updates
View Packages
</span>
</div>
<span
@@ -3021,7 +3040,7 @@ exports[`App Route /updates authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Create Updates
Create Packages
</span>
</div>
<span
@@ -3095,7 +3114,7 @@ exports[`App Route /updates authenticated 1`] = `
<h1
class="MuiTypography-root MuiTypography-h5"
>
Updates
Update Packages
</h1>
<div
class="MuiTableContainer-root"
@@ -3465,7 +3484,7 @@ exports[`App Route /vehicle-add authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
View Updates
View Packages
</span>
</div>
<span
@@ -3487,7 +3506,7 @@ exports[`App Route /vehicle-add authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Create Updates
Create Packages
</span>
</div>
<span
@@ -3921,7 +3940,7 @@ exports[`App Route /vehicle-status authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
View Updates
View Packages
</span>
</div>
<span
@@ -3943,7 +3962,7 @@ exports[`App Route /vehicle-status authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Create Updates
Create Packages
</span>
</div>
<span
@@ -4388,7 +4407,7 @@ exports[`App Route /vehicles authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
View Updates
View Packages
</span>
</div>
<span
@@ -4410,7 +4429,7 @@ exports[`App Route /vehicles authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Create Updates
Create Packages
</span>
</div>
<span

View File

@@ -1,5 +1,5 @@
import React, { useEffect, useState } from "react";
import { useParams } from "react-router";
import { useParams, Redirect } from "react-router";
import {
Button,
Chip,
@@ -44,6 +44,7 @@ const MainForm = () => {
const [releaseNotesLink, setReleaseNotesLink] = useState("");
const [createDate, setCreateDate] = useState("");
const [selectedVehicles, setSelectedVehicles] = useState([]);
const [redirect, setRedirect] = useState("");
const classes = useStyles();
const theme = useTheme();
const handleVehiclesChange = (event) => {
@@ -60,7 +61,7 @@ const MainForm = () => {
setMessage(
`Deployed ${packageName} ${version} to ${selectedVehicles.length} cars`
);
setSelectedVehicles([]);
setRedirect(`/carupdate-status/${packageid}`);
} catch (e) {
setMessage(e.message);
}
@@ -95,10 +96,14 @@ const MainForm = () => {
setCreateDate(tsLocalDateTimeString(data.timestamp));
}, [packages]);
if (redirect.length > 0) {
return <Redirect to={redirect} />;
}
return (
<div className={classes.paper}>
<Typography component="h1" variant="h5">
{`[${packageid}] ${packageName} ${version}`}
Deploy {`${packageName} ${version} [${packageid}]`}
</Typography>
<form className={classes.form} noValidate action="{onSubmit}">
<TextField

View File

@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import { useParams } from "react-router";
import {
LinearProgress,
Table,
TableBody,
TableCell,
@@ -25,16 +26,17 @@ import VehicleStatus from "../../Cars/StatusModal";
const MainForm = () => {
const { packageid } = useParams();
const classes = useStyles();
const [pageSize, setPageSize] = useState(10);
const [pageSize, setPageSize] = useState(25);
const [pageIndex, setPageIndex] = useState(0);
const [viewVIN, setViewVIN] = useState(null);
const {
getCarUpdates,
carUpdates,
totalCarUpdates,
getPackages,
packages,
startMonitor,
stopMonitor,
} = useUpdatesContext();
const { setMessage } = useStatusContext();
const {
@@ -54,6 +56,7 @@ const MainForm = () => {
useEffect(() => {
try {
stopMonitor();
getCarUpdates(
{
packageid,
@@ -68,6 +71,19 @@ const MainForm = () => {
// eslint-disable-next-line
}, [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) => {
setPageIndex(newIndex);
};
@@ -113,7 +129,15 @@ const MainForm = () => {
{row.vin}
</span>
</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">
{LocalDateTimeString(row.created)}
</TableCell>

View File

@@ -23,7 +23,7 @@ import { LocalDateTimeString } from "../../../utils/dates";
const MainForm = () => {
const classes = useStyles();
const [pageSize, setPageSize] = useState(5);
const [pageSize, setPageSize] = useState(25);
const [pageIndex, setPageIndex] = useState(0);
const { getVehicles, vehicles, totalVehicles } = useVehicleContext();
const { setMessage } = useStatusContext();

View File

@@ -8,7 +8,6 @@ export const FileUploadProvider = ({ children }) => {
const [progress, setProgress] = useState(0);
const [status, setStatus] = useState(null);
const [cancelUpload, setCancelUpload] = useState(null);
const [linkURL, setLinkURL] = useState(null);
const [files, setFiles] = useState(null);
const done = () => {
@@ -45,6 +44,14 @@ export const FileUploadProvider = ({ children }) => {
if (!accessToken || accessToken.length === 0) {
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) => {
@@ -55,7 +62,6 @@ export const FileUploadProvider = ({ children }) => {
const filename = file.name;
setUploading(true);
setLinkURL(null);
setProgress(0);
setStatus(`Uploading ${filename}`);
setCancelUpload(getCancelToken());
@@ -70,11 +76,11 @@ export const FileUploadProvider = ({ children }) => {
if (data.message) {
throw new Error(`${data.error}. ${data.message}`);
}
const url = data && data.link ? data.link : "No URL available";
setLinkURL(url);
setStatus(`Uploaded ${filename}`);
setCancelUpload(null);
setProgress(100);
return data;
} catch (e) {
setUploading(true);
setStatus(`Error occured: ${e.message}`);
@@ -88,7 +94,6 @@ export const FileUploadProvider = ({ children }) => {
uploading,
progress,
status,
linkURL,
files,
upload,
cancel,

View File

@@ -7,6 +7,7 @@ import {
fireEvent,
waitFor,
} from "@testing-library/react";
import { useState } from "react";
import { setUploadFileDelay } from "../../services/uploadFile";
import {
@@ -30,21 +31,26 @@ describe("FileUploadContext", () => {
progress,
uploading,
status,
linkURL,
upload,
cancel,
} = useFileUploadContext();
const { message, setMessage } = useStatusContext();
const [link, setLink] = useState(null);
const TEST_FILE = [{ name: "test.jpg", size: 0 }];
const TEST_ACCESSTOKEN = "ACCESSTOKEN";
const TEST_FORMDATA = {
packagename: "TEST",
version: "VERSION",
vehicles: ["VIN"],
description: "TEST DESC",
releasenotes: "http://releasenotes.com",
};
const exec = async (form, token, file) => {
try {
await upload(form, token, file);
const data = await upload(form, token, file);
if (data.link) {
setLink(data.link);
}
} catch (e) {
setMessage(e.message);
}
@@ -56,7 +62,7 @@ describe("FileUploadContext", () => {
<div data-testid="progress">{progress.toString()}</div>
<div data-testid="status">{status}</div>
<div data-testid="message">{message}</div>
<div data-testid="linkURL">{linkURL}</div>
<div data-testid="linkURL">{link}</div>
<button
data-testid="uploadNoFile"
onClick={() => {

View File

@@ -10,6 +10,8 @@ export const UpdatesProvider = ({ children }) => {
const [carUpdates, setCarUpdates] = useState([]);
const [totalPackages, setTotalPackages] = useState(0);
const [totalCarUpdates, setTotalCarUpdates] = useState(0);
const [delayCount, setDelayCount] = useState(0);
let progressTimer = 0;
const getPackages = async (search, token) => {
let result;
@@ -96,6 +98,86 @@ export const UpdatesProvider = ({ children }) => {
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 (
<UpdatesContext.Provider
value={{
@@ -109,6 +191,8 @@ export const UpdatesProvider = ({ children }) => {
createCarUpdates,
getCarUpdates,
getVINUpdates,
startMonitor,
stopMonitor,
}}
>
{children}

View File

@@ -23,4 +23,6 @@ export const useUpdatesContext = () => ({
createCarUpdates: jest.fn((data) => data),
getCarUpdates: jest.fn(() => carUpdates),
getVINUpdates: jest.fn(() => carUpdates),
startMonitor: jest.fn(),
stopMonitor: jest.fn(),
});

View File

@@ -11,12 +11,12 @@ const menuData = [
roles: [],
},
{
label: "View Updates",
label: "View Packages",
to: "/updates",
roles: [Roles.CREATE, Roles.READ],
},
{
label: "Create Updates",
label: "Create Packages",
to: "/package-upload",
roles: [Roles.CREATE],
},

View File

@@ -44,7 +44,7 @@ exports[`SideMenu Authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
View Updates
View Packages
</span>
</div>
<span
@@ -66,7 +66,7 @@ exports[`SideMenu Authenticated 1`] = `
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Create Updates
Create Packages
</span>
</div>
<span

View File

@@ -11,7 +11,7 @@ exports[`File Upload Form Should render 1`] = `
<h1
class="MuiTypography-root MuiTypography-h5"
>
Upload Update Package
Create Update Package
</h1>
<form
action="{onSubmit}"
@@ -114,12 +114,19 @@ exports[`File Upload Form Should render 1`] = `
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
>
<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"
for="description"
id="description-label"
>
Description
<span
aria-hidden="true"
class="MuiFormLabel-asterisk MuiInputLabel-asterisk"
>
*
</span>
</label>
<div
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"
name="description"
placeholder="Package description"
required=""
rows="4"
/>
<fieldset
@@ -142,6 +150,7 @@ exports[`File Upload Form Should render 1`] = `
>
<span>
Description
 *
</span>
</legend>
</fieldset>
@@ -151,12 +160,19 @@ exports[`File Upload Form Should render 1`] = `
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
>
<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"
for="releasenotes"
id="releasenotes-label"
>
Release Notes URL
<span
aria-hidden="true"
class="MuiFormLabel-asterisk MuiInputLabel-asterisk"
>
*
</span>
</label>
<div
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-fullWidth MuiInputBase-formControl"
@@ -168,6 +184,7 @@ exports[`File Upload Form Should render 1`] = `
maxlength="1024"
name="releasenotes"
placeholder="Release Notes URL"
required=""
type="text"
value=""
/>
@@ -180,6 +197,7 @@ exports[`File Upload Form Should render 1`] = `
>
<span>
Release Notes URL
 *
</span>
</legend>
</fieldset>

View File

@@ -1,4 +1,4 @@
import React, { useRef } from "react";
import React, { useRef, useState } from "react";
import { Button, TextField, Typography } from "@material-ui/core";
import { DropzoneArea } from "material-ui-dropzone";
import { useUserContext } from "../../Contexts/UserContext";
@@ -9,6 +9,7 @@ import {
} from "../../Contexts/FileUploadContext";
import ModalProgressBar from "../../ModalProgressBar";
import useStyles from "../../useStyles";
import { Redirect } from "react-router";
const FileUploadZone = ({ classes, token }) => {
const { setFiles } = useFileUploadContext();
@@ -39,9 +40,10 @@ const FileUploadZone = ({ classes, token }) => {
};
const MainForm = () => {
const { uploading, upload, files } = useFileUploadContext();
const { uploading, upload, files, cancel } = useFileUploadContext();
const { token } = useUserContext();
const { setMessage } = useStatusContext();
const [redirect, setRedirect] = useState(null);
const classes = useStyles();
const packagenameEl = useRef(null);
const versionEl = useRef(null);
@@ -59,17 +61,26 @@ const MainForm = () => {
description: descEl.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) {
setMessage(e.message);
}
};
if (redirect && redirect.length > 0) {
return <Redirect to={redirect} />;
}
return (
<div className={classes.paper}>
<Typography component="h1" variant="h5">
Upload Update Package
Create Update Package
</Typography>
<form className={classes.form} noValidate action="{onSubmit}">
<TextField
@@ -107,6 +118,7 @@ const MainForm = () => {
inputProps={{
maxLength: "5120",
}}
required
fullWidth
multiline
rows={4}
@@ -122,6 +134,7 @@ const MainForm = () => {
inputProps={{
maxLength: "1024",
}}
required
fullWidth
placeholder="Release Notes URL"
inputRef={releasenotesEl}

View File

@@ -87,7 +87,7 @@ const MainForm = () => {
return (
<div className={classes.paper}>
<Typography component="h1" variant="h5">
Update Package {id}
Edit Update Package {id}
</Typography>
<form className={classes.form} noValidate action="{onSubmit}">
<TextField

View File

@@ -26,7 +26,7 @@ import { Roles, hasRole } from "../../../utils/roles";
const UpdatePackagesList = () => {
const classes = useStyles();
const [pageSize, setPageSize] = useState(5);
const [pageSize, setPageSize] = useState(25);
const [pageIndex, setPageIndex] = useState(0);
const { getPackages, packages, totalPackages } = useUpdatesContext();
const {
@@ -98,7 +98,7 @@ const UpdatePackagesList = () => {
return (
<div className={classes.paper} style={{ height: 700, width: "100%" }}>
<Typography component="h1" variant="h5">
Updates
Update Packages
</Typography>
<TableContainer>
<Table>

View File

@@ -41,11 +41,15 @@ const updatesAPI = {
},
getCarUpdates: async (filter, token) => {
return { data:[] };
return { data: [] };
},
getVINUpdates: async (vin, token) => {
return { data:[] };
return { data: [] };
},
getCarUpdateProgress: async (carupdateids, token) => {
return { statuses: [] };
},
};

View File

@@ -45,6 +45,15 @@ const updatesAPI = {
})
.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;