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
This commit is contained in:
@@ -750,7 +750,7 @@ exports[`App Route /carupdate-deploy authenticated 1`] = `
|
|||||||
class="MuiGrid-root MuiGrid-item MuiGrid-grid-md-10"
|
class="MuiGrid-root MuiGrid-item MuiGrid-grid-md-10"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiFormControl-root makeStyles-margin-1195 makeStyles-textField-1196"
|
class="MuiFormControl-root makeStyles-margin-1195 makeStyles-fullWidth-1218"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated"
|
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated"
|
||||||
@@ -4233,7 +4233,7 @@ exports[`App Route /package-deploy authenticated 1`] = `
|
|||||||
class="MuiGrid-root makeStyles-root-1464 MuiGrid-container MuiGrid-spacing-xs-2"
|
class="MuiGrid-root makeStyles-root-1464 MuiGrid-container MuiGrid-spacing-xs-2"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiGrid-root MuiGrid-item MuiGrid-grid-md-2"
|
class="MuiGrid-root MuiGrid-item MuiGrid-grid-md-4"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-labelInline-1459"
|
class="makeStyles-labelInline-1459"
|
||||||
@@ -4242,10 +4242,10 @@ exports[`App Route /package-deploy authenticated 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiGrid-root makeStyles-textCenterAlign-1499 MuiGrid-item MuiGrid-grid-md-8"
|
class="MuiGrid-root makeStyles-textCenterAlign-1499 MuiGrid-item MuiGrid-grid-md-4"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiFormControl-root makeStyles-margin-1478 makeStyles-textField-1479"
|
class="MuiFormControl-root makeStyles-margin-1478 makeStyles-fullWidth-1501"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated"
|
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated"
|
||||||
@@ -4296,10 +4296,10 @@ exports[`App Route /package-deploy authenticated 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="MuiGrid-root makeStyles-textRightAlign-1500 MuiGrid-item MuiGrid-grid-md-2"
|
class="MuiGrid-root makeStyles-textRightAlign-1500 MuiGrid-item MuiGrid-grid-md-4"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiButton-root MuiButton-contained makeStyles-formControl-1457 MuiButton-containedPrimary Mui-disabled Mui-disabled"
|
class="MuiButtonBase-root MuiButton-root MuiButton-contained makeStyles-formControl-1457 makeStyles-textField-1479 MuiButton-containedPrimary Mui-disabled Mui-disabled"
|
||||||
disabled=""
|
disabled=""
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
type="submit"
|
type="submit"
|
||||||
@@ -5595,7 +5595,7 @@ exports[`App Route /packages authenticated 1`] = `
|
|||||||
class="MuiGrid-root makeStyles-textCenterAlign-1389 MuiGrid-item MuiGrid-grid-md-4"
|
class="MuiGrid-root makeStyles-textCenterAlign-1389 MuiGrid-item MuiGrid-grid-md-4"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiFormControl-root makeStyles-margin-1368 makeStyles-textField-1369"
|
class="MuiFormControl-root makeStyles-margin-1368 makeStyles-fullWidth-1391"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated"
|
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated"
|
||||||
@@ -7300,11 +7300,15 @@ exports[`App Route /vehicle-status authenticated 1`] = `
|
|||||||
data-testid="mocked-vehicleprovider"
|
data-testid="mocked-vehicleprovider"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
data-testid="mocked-updatesprovider"
|
class="makeStyles-paper-1005 makeStyles-tableSize-1056"
|
||||||
>
|
>
|
||||||
|
<h6
|
||||||
|
class="MuiTypography-root MuiTypography-h6"
|
||||||
|
>
|
||||||
|
Car Updates
|
||||||
|
</h6>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-paper-1005"
|
data-testid="mocked-updatesprovider"
|
||||||
style="height: 700px; width: 100%;"
|
|
||||||
>
|
>
|
||||||
<table
|
<table
|
||||||
class="MuiTable-root"
|
class="MuiTable-root"
|
||||||
@@ -7568,6 +7572,529 @@ exports[`App Route /vehicle-status authenticated 1`] = `
|
|||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="MuiGrid-root makeStyles-root-1016 MuiGrid-container MuiGrid-spacing-xs-2"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiGrid-root makeStyles-textJustifyAlign-1050 MuiGrid-item MuiGrid-grid-md-4"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="MuiGrid-root makeStyles-textCenterAlign-1051 MuiGrid-item MuiGrid-grid-md-4"
|
||||||
|
>
|
||||||
|
<h6
|
||||||
|
class="MuiTypography-root makeStyles-labelInline-1011 MuiTypography-h6"
|
||||||
|
>
|
||||||
|
Car ECUs
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="MuiGrid-root makeStyles-textRightAlign-1052 MuiGrid-item MuiGrid-grid-md-4"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="MuiButtonBase-root MuiButton-root MuiButton-contained makeStyles-formControl-1009 makeStyles-textField-1031 MuiButton-containedPrimary"
|
||||||
|
tabindex="0"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiButton-label"
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="MuiTouchRipple-root"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="makeStyles-paper-1005 makeStyles-tableSize-1056"
|
||||||
|
>
|
||||||
|
<table
|
||||||
|
class="MuiTable-root"
|
||||||
|
>
|
||||||
|
<thead
|
||||||
|
class="MuiTableHead-root"
|
||||||
|
>
|
||||||
|
<tr
|
||||||
|
class="MuiTableRow-root MuiTableRow-head"
|
||||||
|
>
|
||||||
|
<th
|
||||||
|
aria-sort="descending"
|
||||||
|
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||||
|
scope="col"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiTableSortLabel-root MuiTableSortLabel-active"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
ECU
|
||||||
|
<span
|
||||||
|
class="makeStyles-hiddenSortSpan-1029"
|
||||||
|
>
|
||||||
|
sorted descending
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionDesc"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||||
|
scope="col"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
SW Version
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||||
|
scope="col"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
BL Version
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||||
|
scope="col"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
HW Version
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||||
|
scope="col"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
Vendor
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||||
|
scope="col"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
Config
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||||
|
scope="col"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
Fingerprint
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||||
|
scope="col"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
Serial
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||||
|
scope="col"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
Created
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||||
|
scope="col"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
Updated
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody
|
||||||
|
class="MuiTableBody-root"
|
||||||
|
>
|
||||||
|
<tr
|
||||||
|
class="MuiTableRow-root"
|
||||||
|
>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
ECUA
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
SWVERSION
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
BLVERSION
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
HWVERSION
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
VENDOR
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
CONFIG
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
FINGERPRINT
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
SERIAL
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
7/14/2021 8:09:40 PM
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
7/14/2021 8:09:40 PM
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr
|
||||||
|
class="MuiTableRow-root"
|
||||||
|
>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
ECUB
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
SWVERSION
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
BLVERSION
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
HWVERSION
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
VENDOR
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
CONFIG
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
FINGERPRINT
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
SERIAL
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
7/14/2021 8:09:40 PM
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||||
|
>
|
||||||
|
7/14/2021 8:09:40 PM
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot
|
||||||
|
class="MuiTableFooter-root"
|
||||||
|
>
|
||||||
|
<tr
|
||||||
|
class="MuiTableRow-root MuiTableRow-footer"
|
||||||
|
>
|
||||||
|
<td
|
||||||
|
class="MuiTableCell-root MuiTableCell-footer MuiTablePagination-root"
|
||||||
|
colspan="10"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiToolbar-root MuiToolbar-regular MuiTablePagination-toolbar MuiToolbar-gutters"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTablePagination-spacer"
|
||||||
|
/>
|
||||||
|
<p
|
||||||
|
class="MuiTypography-root MuiTablePagination-caption MuiTypography-body2 MuiTypography-colorInherit"
|
||||||
|
id="mui-00000"
|
||||||
|
>
|
||||||
|
Rows per page:
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
class="MuiInputBase-root MuiTablePagination-input MuiTablePagination-selectRoot"
|
||||||
|
>
|
||||||
|
<select
|
||||||
|
aria-label="rows per page"
|
||||||
|
class="MuiSelect-root MuiSelect-select MuiTablePagination-select MuiInputBase-input"
|
||||||
|
id="mui-00000"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
class="MuiTablePagination-menuItem"
|
||||||
|
value="5"
|
||||||
|
>
|
||||||
|
5
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
class="MuiTablePagination-menuItem"
|
||||||
|
value="10"
|
||||||
|
>
|
||||||
|
10
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
class="MuiTablePagination-menuItem"
|
||||||
|
value="25"
|
||||||
|
>
|
||||||
|
25
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
class="MuiTablePagination-menuItem"
|
||||||
|
value="100"
|
||||||
|
>
|
||||||
|
100
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root MuiSelect-icon MuiTablePagination-selectIcon"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M7 10l5 5 5-5z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
class="MuiTypography-root MuiTablePagination-caption MuiTypography-body2 MuiTypography-colorInherit"
|
||||||
|
>
|
||||||
|
1-2 of 2
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
class="MuiTablePagination-actions"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-label="Previous page"
|
||||||
|
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit Mui-disabled Mui-disabled"
|
||||||
|
disabled=""
|
||||||
|
tabindex="-1"
|
||||||
|
title="Previous page"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiIconButton-label"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-label="Next page"
|
||||||
|
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit Mui-disabled Mui-disabled"
|
||||||
|
disabled=""
|
||||||
|
tabindex="-1"
|
||||||
|
title="Next page"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiIconButton-label"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="MuiSvgIcon-root"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
@@ -7942,7 +8469,7 @@ exports[`App Route /vehicles authenticated 1`] = `
|
|||||||
class="MuiGrid-root makeStyles-textCenterAlign-988 MuiGrid-item MuiGrid-grid-md-4"
|
class="MuiGrid-root makeStyles-textCenterAlign-988 MuiGrid-item MuiGrid-grid-md-4"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiFormControl-root makeStyles-margin-967 makeStyles-textField-968"
|
class="MuiFormControl-root makeStyles-margin-967 makeStyles-fullWidth-990"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated"
|
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated"
|
||||||
@@ -8038,6 +8565,11 @@ exports[`App Route /vehicles authenticated 1`] = `
|
|||||||
>
|
>
|
||||||
Close window
|
Close window
|
||||||
</option>
|
</option>
|
||||||
|
<option
|
||||||
|
value="ecu"
|
||||||
|
>
|
||||||
|
ECU Versions
|
||||||
|
</option>
|
||||||
<option
|
<option
|
||||||
value="log"
|
value="log"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
TablePagination,
|
TablePagination,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
UpdatesProvider,
|
UpdatesProvider,
|
||||||
@@ -105,7 +106,7 @@ const MainForm = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${classes.paper} ${classes.tableSize}`}>
|
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
|||||||
175
src/components/Cars/CarECUs/index.jsx
Normal file
175
src/components/Cars/CarECUs/index.jsx
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableFooter,
|
||||||
|
TablePagination,
|
||||||
|
TableRow,
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
|
import { LocalDateTimeString } from "../../../utils/dates";
|
||||||
|
import TableHeaderSortable from "../../Table/HeaderSortable";
|
||||||
|
import { useVehicleContext } from "../../Contexts/VehicleContext";
|
||||||
|
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||||
|
import useStyles from "../../useStyles";
|
||||||
|
import { logger } from "../../../services/monitoring";
|
||||||
|
|
||||||
|
const tableColumns = [
|
||||||
|
{
|
||||||
|
id: "ecu",
|
||||||
|
label: "ECU",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "sw_version",
|
||||||
|
label: "SW Version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "boot_loader_version",
|
||||||
|
label: "BL Version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "hw_version",
|
||||||
|
label: "HW Version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "vendor",
|
||||||
|
label: "Vendor",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "config",
|
||||||
|
label: "Config",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "fingerprint",
|
||||||
|
label: "Fingerprint",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "serial_number",
|
||||||
|
label: "Serial",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "created_at",
|
||||||
|
label: "Created",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "updated_at",
|
||||||
|
label: "Updated",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const CarECUs = ({ vin, token }) => {
|
||||||
|
const [ecus, setECUs] = useState([]);
|
||||||
|
const [total, setTotal] = useState(0);
|
||||||
|
const classes = useStyles();
|
||||||
|
const [pageSize, setPageSize] = useState(10);
|
||||||
|
const [pageIndex, setPageIndex] = useState(0);
|
||||||
|
const [orderBy, setOrderBy] = useState("ecu");
|
||||||
|
const [order, setOrder] = useState("desc");
|
||||||
|
const { getECUs } = useVehicleContext();
|
||||||
|
const { setMessage } = useStatusContext();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
if (!vin || !token) return;
|
||||||
|
const result = await getECUs(
|
||||||
|
{
|
||||||
|
vin,
|
||||||
|
limit: pageSize,
|
||||||
|
offset: pageSize * pageIndex,
|
||||||
|
order: `${orderBy} ${order}`,
|
||||||
|
},
|
||||||
|
token
|
||||||
|
);
|
||||||
|
setECUs(result.data);
|
||||||
|
if (result.total > -1) setTotal(result.total);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
setMessage(e.message);
|
||||||
|
logger.warn(e.stack);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [vin, token, pageIndex, pageSize, orderBy, order]);
|
||||||
|
|
||||||
|
const handleChangePageIndex = (event, newIndex) => {
|
||||||
|
setPageIndex(newIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChangePageSize = (event) => {
|
||||||
|
setPageSize(parseInt(event.target.value, 10));
|
||||||
|
setPageIndex(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSort = (event, property) => {
|
||||||
|
try {
|
||||||
|
if (property === orderBy) {
|
||||||
|
if (order === "asc") {
|
||||||
|
setOrder("desc");
|
||||||
|
} else {
|
||||||
|
setOrder("asc");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setOrderBy(property);
|
||||||
|
setOrder("asc");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn(e.stack);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||||
|
<Table>
|
||||||
|
<TableHeaderSortable
|
||||||
|
classes={classes}
|
||||||
|
orderBy={orderBy}
|
||||||
|
order={order}
|
||||||
|
columnData={tableColumns}
|
||||||
|
onSortRequest={handleSort}
|
||||||
|
/>
|
||||||
|
<TableBody>
|
||||||
|
{ecus.map((row) => (
|
||||||
|
<TableRow key={row.ecu}>
|
||||||
|
<TableCell align="center">{row.ecu}</TableCell>
|
||||||
|
<TableCell align="center">{row.sw_version}</TableCell>
|
||||||
|
<TableCell align="center">{row.boot_loader_version}</TableCell>
|
||||||
|
<TableCell align="center">{row.hw_version}</TableCell>
|
||||||
|
<TableCell align="center">{row.vendor}</TableCell>
|
||||||
|
<TableCell align="center">{row.config}</TableCell>
|
||||||
|
<TableCell align="center">{row.fingerprint}</TableCell>
|
||||||
|
<TableCell align="center">{row.serial_number}</TableCell>
|
||||||
|
<TableCell align="center">
|
||||||
|
{LocalDateTimeString(row.created)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="center">
|
||||||
|
{LocalDateTimeString(row.updated)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
<TableFooter>
|
||||||
|
<TableRow>
|
||||||
|
<TablePagination
|
||||||
|
rowsPerPageOptions={[5, 10, 25, 100]}
|
||||||
|
colSpan={10}
|
||||||
|
count={total}
|
||||||
|
rowsPerPage={pageSize}
|
||||||
|
page={pageIndex}
|
||||||
|
SelectProps={{
|
||||||
|
inputProps: { "aria-label": "rows per page" },
|
||||||
|
native: true,
|
||||||
|
}}
|
||||||
|
onPageChange={handleChangePageIndex}
|
||||||
|
onRowsPerPageChange={handleChangePageSize}
|
||||||
|
/>
|
||||||
|
</TableRow>
|
||||||
|
</TableFooter>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CarECUs;
|
||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
TablePagination,
|
TablePagination,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
import { useVehicleContext } from "../../Contexts/VehicleContext";
|
import { useVehicleContext } from "../../Contexts/VehicleContext";
|
||||||
import { useStatusContext } from "../../Contexts/StatusContext";
|
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||||
@@ -114,7 +115,7 @@ const CarSelectionTable = (props) => {
|
|||||||
}, [pageIndex, pageSize, orderBy, order, search, token]);
|
}, [pageIndex, pageSize, orderBy, order, search, token]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${classes.paper} ${classes.tableSize}`}>
|
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeaderSortable
|
<TableHeaderSortable
|
||||||
classes={classes}
|
classes={classes}
|
||||||
@@ -147,7 +148,11 @@ const CarSelectionTable = (props) => {
|
|||||||
{row.ecu_list && (
|
{row.ecu_list && (
|
||||||
<>
|
<>
|
||||||
<br />
|
<br />
|
||||||
<ECUList list={row.ecu_list} search={searchTerm} />
|
<ECUList
|
||||||
|
list={row.ecu_list}
|
||||||
|
search={searchTerm}
|
||||||
|
searchedOnly={true}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
159
src/components/Cars/CarUpdates/index.jsx
Normal file
159
src/components/Cars/CarUpdates/index.jsx
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableFooter,
|
||||||
|
TablePagination,
|
||||||
|
TableRow,
|
||||||
|
} from "@material-ui/core";
|
||||||
|
|
||||||
|
import { LocalDateTimeString } from "../../../utils/dates";
|
||||||
|
import TableHeaderSortable from "../../Table/HeaderSortable";
|
||||||
|
import {
|
||||||
|
UpdatesProvider,
|
||||||
|
useUpdatesContext,
|
||||||
|
} from "../../Contexts/UpdatesContext";
|
||||||
|
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||||
|
import useStyles from "../../useStyles";
|
||||||
|
import { logger } from "../../../services/monitoring";
|
||||||
|
|
||||||
|
const tableColumns = [
|
||||||
|
{
|
||||||
|
id: "id",
|
||||||
|
label: "ID",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "update_package_id",
|
||||||
|
label: "Name",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "status",
|
||||||
|
label: "Status",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "created_at",
|
||||||
|
label: "Created",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "updated_at",
|
||||||
|
label: "Updated",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const MainForm = ({ vin, token }) => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const [pageSize, setPageSize] = useState(10);
|
||||||
|
const [pageIndex, setPageIndex] = useState(0);
|
||||||
|
const [orderBy, setOrderBy] = useState("id");
|
||||||
|
const [order, setOrder] = useState("desc");
|
||||||
|
const { getCarUpdates, carUpdates, totalCarUpdates } = useUpdatesContext();
|
||||||
|
const { setMessage } = useStatusContext();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
if (!vin || !token) return;
|
||||||
|
await getCarUpdates(
|
||||||
|
{
|
||||||
|
vin,
|
||||||
|
limit: pageSize,
|
||||||
|
offset: pageSize * pageIndex,
|
||||||
|
order: `${orderBy} ${order}`,
|
||||||
|
},
|
||||||
|
token
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
setMessage(e.message);
|
||||||
|
logger.warn(e.stack);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [vin, token, pageIndex, pageSize, orderBy, order]);
|
||||||
|
|
||||||
|
const handleChangePageIndex = (event, newIndex) => {
|
||||||
|
setPageIndex(newIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChangePageSize = (event) => {
|
||||||
|
setPageSize(parseInt(event.target.value, 10));
|
||||||
|
setPageIndex(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSort = (event, property) => {
|
||||||
|
try {
|
||||||
|
if (property === orderBy) {
|
||||||
|
if (order === "asc") {
|
||||||
|
setOrder("desc");
|
||||||
|
} else {
|
||||||
|
setOrder("asc");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setOrderBy(property);
|
||||||
|
setOrder("asc");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn(e.stack);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateName = (row) => {
|
||||||
|
if (row.updatepackage)
|
||||||
|
return `${row.updatepackage.package_name} ${row.updatepackage.version}`;
|
||||||
|
if (row.updatemanifest)
|
||||||
|
return `${row.updatemanifest.name} ${row.updatemanifest.version}`;
|
||||||
|
return "None";
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table>
|
||||||
|
<TableHeaderSortable
|
||||||
|
classes={classes}
|
||||||
|
orderBy={orderBy}
|
||||||
|
order={order}
|
||||||
|
columnData={tableColumns}
|
||||||
|
onSortRequest={handleSort}
|
||||||
|
/>
|
||||||
|
<TableBody>
|
||||||
|
{carUpdates.map((row) => (
|
||||||
|
<TableRow key={row.id}>
|
||||||
|
<TableCell align="center">{row.id}</TableCell>
|
||||||
|
<TableCell align="center">{updateName(row)}</TableCell>
|
||||||
|
<TableCell align="center">{row.status}</TableCell>
|
||||||
|
<TableCell align="center">
|
||||||
|
{LocalDateTimeString(row.created)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="center">
|
||||||
|
{LocalDateTimeString(row.updated)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
<TableFooter>
|
||||||
|
<TableRow>
|
||||||
|
<TablePagination
|
||||||
|
rowsPerPageOptions={[5, 10, 25, 100]}
|
||||||
|
colSpan={5}
|
||||||
|
count={totalCarUpdates}
|
||||||
|
rowsPerPage={pageSize}
|
||||||
|
page={pageIndex}
|
||||||
|
SelectProps={{
|
||||||
|
inputProps: { "aria-label": "rows per page" },
|
||||||
|
native: true,
|
||||||
|
}}
|
||||||
|
onPageChange={handleChangePageIndex}
|
||||||
|
onRowsPerPageChange={handleChangePageSize}
|
||||||
|
/>
|
||||||
|
</TableRow>
|
||||||
|
</TableFooter>
|
||||||
|
</Table>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CarUpdates = (props) => (
|
||||||
|
<UpdatesProvider>
|
||||||
|
<MainForm {...props} />
|
||||||
|
</UpdatesProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default CarUpdates;
|
||||||
@@ -75,7 +75,7 @@ const SendCommand = ({ vins }) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${classes.form}`} style={{ marginTop: 20 }}>
|
<div className={classes.form} style={{ marginTop: 20 }}>
|
||||||
<FormControl
|
<FormControl
|
||||||
className={classes.formControlInline}
|
className={classes.formControlInline}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { Grid } from "@material-ui/core";
|
import { Grid } from "@material-ui/core";
|
||||||
import AddCircleIcon from "@material-ui/icons/AddCircle";
|
import AddCircleIcon from "@material-ui/icons/AddCircle";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
import { VehicleProvider } from "../../Contexts/VehicleContext";
|
import { VehicleProvider } from "../../Contexts/VehicleContext";
|
||||||
import { useUserContext } from "../../Contexts/UserContext";
|
import { useUserContext } from "../../Contexts/UserContext";
|
||||||
@@ -54,7 +55,7 @@ const MainForm = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${classes.paper} ${classes.tableSize}`}>
|
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||||
<Grid container className={classes.root} spacing={2}>
|
<Grid container className={classes.root} spacing={2}>
|
||||||
<Grid item md={4} className={classes.textJustifyAlign}>
|
<Grid item md={4} className={classes.textJustifyAlign}>
|
||||||
<Link to="/vehicle-add">
|
<Link to="/vehicle-add">
|
||||||
|
|||||||
@@ -1,63 +1,38 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useParams } from "react-router";
|
import { useParams } from "react-router";
|
||||||
import {
|
import clsx from "clsx";
|
||||||
Table,
|
import { Button, Grid, Typography } from "@material-ui/core";
|
||||||
TableBody,
|
|
||||||
TableCell,
|
|
||||||
TableFooter,
|
|
||||||
TablePagination,
|
|
||||||
TableRow,
|
|
||||||
} from "@material-ui/core";
|
|
||||||
|
|
||||||
|
import CarECUs from "../CarECUs";
|
||||||
|
import CarUpdates from "../CarUpdates";
|
||||||
import {
|
import {
|
||||||
UpdatesProvider,
|
VehicleProvider,
|
||||||
useUpdatesContext,
|
useVehicleContext,
|
||||||
} from "../../Contexts/UpdatesContext";
|
} from "../../Contexts/VehicleContext";
|
||||||
import { VehicleProvider } from "../../Contexts/VehicleContext";
|
|
||||||
import { useUserContext } from "../../Contexts/UserContext";
|
import { useUserContext } from "../../Contexts/UserContext";
|
||||||
import { useStatusContext } from "../../Contexts/StatusContext";
|
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||||
import useStyles from "../../useStyles";
|
import useStyles from "../../useStyles";
|
||||||
import { LocalDateTimeString } from "../../../utils/dates";
|
|
||||||
import TableHeaderSortable from "../../Table/HeaderSortable";
|
|
||||||
import { logger } from "../../../services/monitoring";
|
import { logger } from "../../../services/monitoring";
|
||||||
|
|
||||||
const tableColumns = [
|
|
||||||
{
|
|
||||||
id: "id",
|
|
||||||
label: "ID",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "update_package_id",
|
|
||||||
label: "Name",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "status",
|
|
||||||
label: "Status",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "created_at",
|
|
||||||
label: "Created",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "updated_at",
|
|
||||||
label: "Updated",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const MainForm = () => {
|
const MainForm = () => {
|
||||||
const { vin } = useParams();
|
const { vin } = useParams();
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [pageSize, setPageSize] = useState(10);
|
const { setTitle, setSitePath, setMessage } = useStatusContext();
|
||||||
const [pageIndex, setPageIndex] = useState(0);
|
const { busy, sendCommand } = useVehicleContext();
|
||||||
const [orderBy, setOrderBy] = useState("id");
|
|
||||||
const [order, setOrder] = useState("desc");
|
|
||||||
const { getCarUpdates, carUpdates, totalCarUpdates } = useUpdatesContext();
|
|
||||||
const { setMessage, setTitle, setSitePath } = useStatusContext();
|
|
||||||
const {
|
const {
|
||||||
token: {
|
token: {
|
||||||
idToken: { jwtToken: token },
|
idToken: { jwtToken: token },
|
||||||
},
|
},
|
||||||
} = useUserContext();
|
} = useUserContext();
|
||||||
|
const updateHandler = async (e) => {
|
||||||
|
try {
|
||||||
|
await sendCommand([vin], "ecu", "", token);
|
||||||
|
setMessage(`Sent command to ${vin}`);
|
||||||
|
} catch (e) {
|
||||||
|
setMessage(e.message);
|
||||||
|
logger.error(e.stack);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const title = `Vehicle ${vin} Details`;
|
const title = `Vehicle ${vin} Details`;
|
||||||
@@ -74,113 +49,39 @@ const MainForm = () => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [vin]);
|
}, [vin]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
try {
|
|
||||||
await getCarUpdates(
|
|
||||||
{
|
|
||||||
vin,
|
|
||||||
limit: pageSize,
|
|
||||||
offset: pageSize * pageIndex,
|
|
||||||
order: `${orderBy} ${order}`,
|
|
||||||
},
|
|
||||||
token
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
setMessage(e.message);
|
|
||||||
logger.warn(e.stack);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [pageIndex, pageSize, token, orderBy, order]);
|
|
||||||
|
|
||||||
const handleChangePageIndex = (event, newIndex) => {
|
|
||||||
setPageIndex(newIndex);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChangePageSize = (event) => {
|
|
||||||
setPageSize(parseInt(event.target.value, 10));
|
|
||||||
setPageIndex(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSort = (event, property) => {
|
|
||||||
try {
|
|
||||||
if (property === orderBy) {
|
|
||||||
if (order === "asc") {
|
|
||||||
setOrder("desc");
|
|
||||||
} else {
|
|
||||||
setOrder("asc");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setOrderBy(property);
|
|
||||||
setOrder("asc");
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
logger.warn(e.stack);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateName = (row) => {
|
|
||||||
if (row.updatepackage)
|
|
||||||
return `${row.updatepackage.package_name} ${row.updatepackage.version}`;
|
|
||||||
if (row.updatemanifest)
|
|
||||||
return `${row.updatemanifest.name} ${row.updatemanifest.version}`;
|
|
||||||
return "None";
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.paper} style={{ height: 700, width: "100%" }}>
|
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||||
<Table>
|
<Typography variant="h6">Car Updates</Typography>
|
||||||
<TableHeaderSortable
|
<CarUpdates vin={vin} token={token} />
|
||||||
classes={classes}
|
<Grid container className={classes.root} spacing={2}>
|
||||||
orderBy={orderBy}
|
<Grid item md={4} className={classes.textJustifyAlign}></Grid>
|
||||||
order={order}
|
<Grid item md={4} className={classes.textCenterAlign}>
|
||||||
columnData={tableColumns}
|
<Typography variant="h6" className={classes.labelInline}>
|
||||||
onSortRequest={handleSort}
|
Car ECUs
|
||||||
/>
|
</Typography>
|
||||||
<TableBody>
|
</Grid>
|
||||||
{carUpdates.map((row) => (
|
<Grid item md={4} className={classes.textRightAlign}>
|
||||||
<TableRow key={row.id}>
|
<Button
|
||||||
<TableCell align="center">{row.id}</TableCell>
|
type="submit"
|
||||||
<TableCell align="center">{updateName(row)}</TableCell>
|
disabled={busy}
|
||||||
<TableCell align="center">{row.status}</TableCell>
|
variant="contained"
|
||||||
<TableCell align="center">
|
color="primary"
|
||||||
{LocalDateTimeString(row.created)}
|
className={clsx(classes.formControl, classes.textField)}
|
||||||
</TableCell>
|
onClick={updateHandler}
|
||||||
<TableCell align="center">
|
>
|
||||||
{LocalDateTimeString(row.updated)}
|
{busy ? "Sending..." : "Update"}
|
||||||
</TableCell>
|
</Button>
|
||||||
</TableRow>
|
</Grid>
|
||||||
))}
|
</Grid>
|
||||||
</TableBody>
|
<CarECUs vin={vin} token={token} />
|
||||||
<TableFooter>
|
|
||||||
<TableRow>
|
|
||||||
<TablePagination
|
|
||||||
rowsPerPageOptions={[5, 10, 25, 100]}
|
|
||||||
colSpan={5}
|
|
||||||
count={totalCarUpdates}
|
|
||||||
rowsPerPage={pageSize}
|
|
||||||
page={pageIndex}
|
|
||||||
SelectProps={{
|
|
||||||
inputProps: { "aria-label": "rows per page" },
|
|
||||||
native: true,
|
|
||||||
}}
|
|
||||||
onPageChange={handleChangePageIndex}
|
|
||||||
onRowsPerPageChange={handleChangePageSize}
|
|
||||||
/>
|
|
||||||
</TableRow>
|
|
||||||
</TableFooter>
|
|
||||||
</Table>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const CarUpdates = () => (
|
const CarStatus = () => (
|
||||||
<VehicleProvider>
|
<VehicleProvider>
|
||||||
<UpdatesProvider>
|
<MainForm />
|
||||||
<MainForm />
|
|
||||||
</UpdatesProvider>
|
|
||||||
</VehicleProvider>
|
</VehicleProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default CarUpdates;
|
export default CarStatus;
|
||||||
|
|||||||
@@ -33,21 +33,19 @@ export const VehicleProvider = ({ children }) => {
|
|||||||
const [models, setModels] = useState([]);
|
const [models, setModels] = useState([]);
|
||||||
const [years, setYears] = useState([]);
|
const [years, setYears] = useState([]);
|
||||||
|
|
||||||
const getVehicles = async (search, token) => {
|
const addConnections = async (cars, token) => {
|
||||||
try {
|
try {
|
||||||
setBusy(true);
|
const vins = cars.map((car) => car.vin);
|
||||||
const result = await api.getVehicles(search, token);
|
const result = await api.getConnections(vins, token);
|
||||||
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
setVehicles([]);
|
throw new Error(`Add connections error. ${result.message}`);
|
||||||
throw new Error(`Get vehicles error. ${result.message}`);
|
|
||||||
}
|
}
|
||||||
await addConnections(result.data, token);
|
cars.forEach((car) => {
|
||||||
setVehicles(result.data);
|
car.connected = result[car.vin] || false;
|
||||||
if (result.total) {
|
});
|
||||||
setTotalVehicles(result.total);
|
} catch (e) {
|
||||||
}
|
logger.error(e.stack);
|
||||||
} finally {
|
|
||||||
setBusy(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,6 +61,41 @@ export const VehicleProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getConnections = async (vins, token) => {
|
||||||
|
try {
|
||||||
|
setBusy(true);
|
||||||
|
const result = await api.getConnections(vins, token);
|
||||||
|
if (result.error)
|
||||||
|
throw new Error(`Get connections error. ${result.message}`);
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
setBusy(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getECUs = async (search, token) => {
|
||||||
|
try {
|
||||||
|
setBusy(true);
|
||||||
|
const result = await api.getECUs(search, token);
|
||||||
|
if (result.error) throw new Error(`Get ECUs error. ${result.message}`);
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
setBusy(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getLocations = async (token) => {
|
||||||
|
try {
|
||||||
|
setBusy(true);
|
||||||
|
const result = await api.getLocations(token);
|
||||||
|
if (result.error)
|
||||||
|
throw new Error(`Get locations error. ${result.message}`);
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
setBusy(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getModels = async (token) => {
|
const getModels = async (token) => {
|
||||||
try {
|
try {
|
||||||
setBusy(true);
|
setBusy(true);
|
||||||
@@ -74,6 +107,35 @@ export const VehicleProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getState = async (token, vin) => {
|
||||||
|
try {
|
||||||
|
setBusy(true);
|
||||||
|
const result = await api.getState(token, vin);
|
||||||
|
if (result.error) throw new Error(`Get state error. ${result.message}`);
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
setBusy(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getVehicles = async (search, token) => {
|
||||||
|
try {
|
||||||
|
setBusy(true);
|
||||||
|
const result = await api.getVehicles(search, token);
|
||||||
|
if (result.error) {
|
||||||
|
setVehicles([]);
|
||||||
|
throw new Error(`Get vehicles error. ${result.message}`);
|
||||||
|
}
|
||||||
|
await addConnections(result.data, token);
|
||||||
|
setVehicles(result.data);
|
||||||
|
if (result.total) {
|
||||||
|
setTotalVehicles(result.total);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setBusy(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getYears = async (token) => {
|
const getYears = async (token) => {
|
||||||
try {
|
try {
|
||||||
setBusy(true);
|
setBusy(true);
|
||||||
@@ -97,74 +159,23 @@ export const VehicleProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const addConnections = async (cars, token) => {
|
|
||||||
try {
|
|
||||||
const vins = cars.map((car) => car.vin);
|
|
||||||
const result = await api.getConnections(vins, token);
|
|
||||||
|
|
||||||
if (result.error) {
|
|
||||||
throw new Error(`Add connections error. ${result.message}`);
|
|
||||||
}
|
|
||||||
cars.forEach((car) => {
|
|
||||||
car.connected = result[car.vin] || false;
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
logger.error(e.stack);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getConnections = async (vins, token) => {
|
|
||||||
try {
|
|
||||||
setBusy(true);
|
|
||||||
const result = await api.getConnections(vins, token);
|
|
||||||
if (result.error)
|
|
||||||
throw new Error(`Get connections error. ${result.message}`);
|
|
||||||
return result;
|
|
||||||
} finally {
|
|
||||||
setBusy(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getLocations = async (token) => {
|
|
||||||
try {
|
|
||||||
setBusy(true);
|
|
||||||
const result = await api.getLocations(token);
|
|
||||||
if (result.error)
|
|
||||||
throw new Error(`Get locations error. ${result.message}`);
|
|
||||||
return result;
|
|
||||||
} finally {
|
|
||||||
setBusy(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getState = async (token, vin) => {
|
|
||||||
try {
|
|
||||||
setBusy(true);
|
|
||||||
const result = await api.getState(token, vin);
|
|
||||||
if (result.error)
|
|
||||||
throw new Error(`Get state error. ${result.message}`);
|
|
||||||
return result;
|
|
||||||
} finally {
|
|
||||||
setBusy(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VehicleContext.Provider
|
<VehicleContext.Provider
|
||||||
value={{
|
value={{
|
||||||
busy,
|
busy,
|
||||||
vehicles,
|
vehicles,
|
||||||
totalVehicles,
|
|
||||||
models,
|
models,
|
||||||
years,
|
years,
|
||||||
getVehicles,
|
totalVehicles,
|
||||||
addVehicle,
|
addVehicle,
|
||||||
getModels,
|
|
||||||
getYears,
|
|
||||||
sendCommand,
|
|
||||||
getConnections,
|
getConnections,
|
||||||
|
getECUs,
|
||||||
getLocations,
|
getLocations,
|
||||||
|
getModels,
|
||||||
getState,
|
getState,
|
||||||
|
getYears,
|
||||||
|
getVehicles,
|
||||||
|
sendCommand,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -17,19 +17,7 @@ export const useVehicleContext = () => ({
|
|||||||
totalVehicles,
|
totalVehicles,
|
||||||
models,
|
models,
|
||||||
years,
|
years,
|
||||||
getVehicles: jest.fn(() => vehicles),
|
|
||||||
addVehicle: jest.fn(),
|
addVehicle: jest.fn(),
|
||||||
getModels: jest.fn(() => {
|
|
||||||
models = ["Ocean", "PEAR"];
|
|
||||||
}),
|
|
||||||
getYears: jest.fn(() => {
|
|
||||||
years = [2023, 2024];
|
|
||||||
}),
|
|
||||||
sendCommand: jest.fn((vins, command, parameters, token) => ({
|
|
||||||
vins,
|
|
||||||
command,
|
|
||||||
parameters,
|
|
||||||
})),
|
|
||||||
getConnections: jest.fn((vins, token) => {
|
getConnections: jest.fn((vins, token) => {
|
||||||
const result = {};
|
const result = {};
|
||||||
|
|
||||||
@@ -39,9 +27,54 @@ export const useVehicleContext = () => ({
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}),
|
}),
|
||||||
getLocations: jest.fn().mockResolvedValue([
|
getECUs: jest.fn(() => {
|
||||||
{ "altitude": 5, "longitude": 10, "latitude": 15, "vin": "TESTVIN123" },
|
return {
|
||||||
])
|
data: [
|
||||||
|
{
|
||||||
|
boot_loader_version: "BLVERSION",
|
||||||
|
config: "CONFIG",
|
||||||
|
created: "2021-07-14T20:09:40.98187Z",
|
||||||
|
ecu: "ECUA",
|
||||||
|
fingerprint: "FINGERPRINT",
|
||||||
|
hw_version: "HWVERSION",
|
||||||
|
serial_number: "SERIAL",
|
||||||
|
sw_version: "SWVERSION",
|
||||||
|
updated: "2021-07-14T20:09:40.98187Z",
|
||||||
|
vendor: "VENDOR",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
boot_loader_version: "BLVERSION",
|
||||||
|
config: "CONFIG",
|
||||||
|
created: "2021-07-14T20:09:40.98187Z",
|
||||||
|
ecu: "ECUB",
|
||||||
|
fingerprint: "FINGERPRINT",
|
||||||
|
hw_version: "HWVERSION",
|
||||||
|
serial_number: "SERIAL",
|
||||||
|
sw_version: "SWVERSION",
|
||||||
|
updated: "2021-07-14T20:09:40.98187Z",
|
||||||
|
vendor: "VENDOR",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: 2,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
getModels: jest.fn(() => {
|
||||||
|
models = ["Ocean", "PEAR"];
|
||||||
|
}),
|
||||||
|
getLocations: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue([
|
||||||
|
{ altitude: 5, longitude: 10, latitude: 15, vin: "TESTVIN123" },
|
||||||
|
]),
|
||||||
|
getVehicles: jest.fn(() => vehicles),
|
||||||
|
getYears: jest.fn(() => {
|
||||||
|
years = [2023, 2024];
|
||||||
|
}),
|
||||||
|
sendCommand: jest.fn((vins, command, parameters, token) => ({
|
||||||
|
vins,
|
||||||
|
command,
|
||||||
|
parameters,
|
||||||
|
})),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const setBusy = (val) => {
|
export const setBusy = (val) => {
|
||||||
|
|||||||
@@ -2,16 +2,17 @@ import React from "react";
|
|||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { Chip } from "@material-ui/core";
|
import { Chip } from "@material-ui/core";
|
||||||
|
|
||||||
const ECUList = ({ list, delimiter, search }) => {
|
const ECUList = ({ list, delimiter, search, searchedOnly }) => {
|
||||||
if (!list) return null;
|
if (!list) return null;
|
||||||
if (!delimiter) delimiter = ",";
|
if (!delimiter) delimiter = ",";
|
||||||
|
|
||||||
const items = list.split(delimiter);
|
const items = list.split(delimiter);
|
||||||
|
|
||||||
return items.map((item, index) => {
|
return items.map((item, index) => {
|
||||||
const match = search
|
const match = search
|
||||||
? item.toLowerCase().split(" ").indexOf(search.toLowerCase())
|
? item.toLowerCase().split(" ").indexOf(search.toLowerCase())
|
||||||
: -1;
|
: -1;
|
||||||
|
|
||||||
|
if (searchedOnly && match === -1) return null;
|
||||||
return (
|
return (
|
||||||
<Chip
|
<Chip
|
||||||
key={index}
|
key={index}
|
||||||
@@ -29,6 +30,7 @@ ECUList.propTypes = {
|
|||||||
list: PropTypes.string,
|
list: PropTypes.string,
|
||||||
delimiter: PropTypes.string,
|
delimiter: PropTypes.string,
|
||||||
search: PropTypes.string,
|
search: PropTypes.string,
|
||||||
|
searchedOnly: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ECUList;
|
export default ECUList;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const SearchField = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormControl className={clsx(classes.margin, classes.textField)}>
|
<FormControl className={clsx(classes.margin, classes.fullWidth)}>
|
||||||
<InputLabel htmlFor="search">Search</InputLabel>
|
<InputLabel htmlFor="search">Search</InputLabel>
|
||||||
<Input
|
<Input
|
||||||
id="search"
|
id="search"
|
||||||
|
|||||||
@@ -52,9 +52,7 @@ export default function MenuDrawer({ children }) {
|
|||||||
paper: classes.drawerPaper,
|
paper: classes.drawerPaper,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div className={clsx(classes.drawerHeader, classes.drawerHeaderLogo)}>
|
||||||
className={`${classes.drawerHeader} ${classes.drawerHeaderLogo}`}
|
|
||||||
>
|
|
||||||
<img
|
<img
|
||||||
src={logo}
|
src={logo}
|
||||||
alt="Fisker Admin Portal"
|
alt="Fisker Admin Portal"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useParams, Redirect } from "react-router";
|
import { useParams, Redirect } from "react-router";
|
||||||
import { Button, Grid, Typography } from "@material-ui/core";
|
import { Button, Grid, Typography } from "@material-ui/core";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ManifestsProvider,
|
ManifestsProvider,
|
||||||
@@ -126,21 +127,21 @@ const MainForm = () => {
|
|||||||
<form className={classes.form} noValidate action="{onSubmit}">
|
<form className={classes.form} noValidate action="{onSubmit}">
|
||||||
<Typography variant="body2">Created {createDate}.</Typography>
|
<Typography variant="body2">Created {createDate}.</Typography>
|
||||||
<Grid container className={classes.root} spacing={2}>
|
<Grid container className={classes.root} spacing={2}>
|
||||||
<Grid item md={2}>
|
<Grid item md={4}>
|
||||||
<div
|
<div
|
||||||
className={classes.labelInline}
|
className={classes.labelInline}
|
||||||
>{`${selected.length} Selected`}</div>
|
>{`${selected.length} Selected`}</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={8} className={classes.textCenterAlign}>
|
<Grid item md={4} className={classes.textCenterAlign}>
|
||||||
<SearchField classes={classes} onSearch={handleSearch} />
|
<SearchField classes={classes} onSearch={handleSearch} />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={2} className={classes.textRightAlign}>
|
<Grid item md={4} className={classes.textRightAlign}>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={busy || selected.length === 0}
|
disabled={busy || selected.length === 0}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
className={classes.formControl}
|
className={clsx(classes.formControl, classes.textField)}
|
||||||
onClick={onSubmit}
|
onClick={onSubmit}
|
||||||
>
|
>
|
||||||
{busy ? "Deploying..." : "Deploy"}
|
{busy ? "Deploying..." : "Deploy"}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import AddCircleIcon from "@material-ui/icons/AddCircle";
|
|||||||
import SendIcon from "@material-ui/icons/Send";
|
import SendIcon from "@material-ui/icons/Send";
|
||||||
import VisibilityIcon from "@material-ui/icons/Visibility";
|
import VisibilityIcon from "@material-ui/icons/Visibility";
|
||||||
import DeleteIcon from "@material-ui/icons/Delete";
|
import DeleteIcon from "@material-ui/icons/Delete";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useManifestsContext,
|
useManifestsContext,
|
||||||
@@ -184,7 +185,7 @@ const MainForm = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${classes.paper} ${classes.tableSize}`}>
|
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||||
<Grid container className={classes.root} spacing={2}>
|
<Grid container className={classes.root} spacing={2}>
|
||||||
<Grid item md={4} className={classes.textJustifyAlign}>
|
<Grid item md={4} className={classes.textJustifyAlign}>
|
||||||
<Link to="/package-create" className={classes.labelInline}>
|
<Link to="/package-create" className={classes.labelInline}>
|
||||||
@@ -213,7 +214,11 @@ const MainForm = () => {
|
|||||||
{row.ecu_list && (
|
{row.ecu_list && (
|
||||||
<>
|
<>
|
||||||
<br />
|
<br />
|
||||||
<ECUList list={row.ecu_list} search={search} />
|
<ECUList
|
||||||
|
list={row.ecu_list}
|
||||||
|
search={search}
|
||||||
|
searchedOnly={true}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
TablePagination,
|
TablePagination,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ManifestsProvider,
|
ManifestsProvider,
|
||||||
@@ -119,7 +120,7 @@ const MainForm = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${classes.paper} ${classes.tableSize}`}>
|
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Button } from "@material-ui/core";
|
import { Button } from "@material-ui/core";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
import { useUserContext } from "../Contexts/UserContext";
|
import { useUserContext } from "../Contexts/UserContext";
|
||||||
import useStyles from "../useStyles";
|
import useStyles from "../useStyles";
|
||||||
|
|
||||||
@@ -21,7 +23,7 @@ export default function SignInForm() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${classes.paper} ${classes.textJustifyAlign}`}>
|
<div className={clsx(classes.paper, classes.textJustifyAlign)}>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
|
|||||||
@@ -9,27 +9,37 @@ const data = [
|
|||||||
{ vin: "1G11C5SL9FF153507", year: 2021, model: "Ocean", trim: "Basic" },
|
{ vin: "1G11C5SL9FF153507", year: 2021, model: "Ocean", trim: "Basic" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const ecusData = [{
|
||||||
|
"boot_loader_version": "BLVERSION",
|
||||||
|
"config": "CONFIG",
|
||||||
|
"created": "2021-07-14T20:09:40.98187Z",
|
||||||
|
"ecu": "ECUA",
|
||||||
|
"fingerprint": "FINGERPRINT",
|
||||||
|
"hw_version": "HWVERSION",
|
||||||
|
"serial_number": "SERIAL",
|
||||||
|
"sw_version": "SWVERSION",
|
||||||
|
"updated": "2021-07-14T20:09:40.98187Z",
|
||||||
|
"vendor": "VENDOR",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"boot_loader_version": "BLVERSION",
|
||||||
|
"config": "CONFIG",
|
||||||
|
"created": "2021-07-14T20:09:40.98187Z",
|
||||||
|
"ecu": "ECUB",
|
||||||
|
"fingerprint": "FINGERPRINT",
|
||||||
|
"hw_version": "HWVERSION",
|
||||||
|
"serial_number": "SERIAL",
|
||||||
|
"sw_version": "SWVERSION",
|
||||||
|
"updated": "2021-07-14T20:09:40.98187Z",
|
||||||
|
"vendor": "VENDOR",
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
const vehiclesAPI = {
|
const vehiclesAPI = {
|
||||||
getVehicles: async (search, token) => { return { data }; },
|
|
||||||
addVehicle: async (vehicle, token) => {
|
addVehicle: async (vehicle, token) => {
|
||||||
data.push(vehicle);
|
data.push(vehicle);
|
||||||
return vehicle;
|
return vehicle;
|
||||||
},
|
},
|
||||||
getModels: async (token) => {
|
|
||||||
return {
|
|
||||||
data: ["Ocean", "Pear"],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
getYears: async (token) => {
|
|
||||||
return {
|
|
||||||
data: [2021, 2022],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
sendCommand: async (vin, command, parameters, token) => {
|
|
||||||
return {
|
|
||||||
vin, command, parameters
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getConnections: async (vins, token) => {
|
getConnections: async (vins, token) => {
|
||||||
const result = {};
|
const result = {};
|
||||||
|
|
||||||
@@ -39,9 +49,28 @@ const vehiclesAPI = {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
getECUs: async (vin, token) => {
|
||||||
|
return { data: ecusData, total: ecusData.length};
|
||||||
|
},
|
||||||
|
getModels: async (token) => {
|
||||||
|
return {
|
||||||
|
data: ["Ocean", "Pear"],
|
||||||
|
};
|
||||||
|
},
|
||||||
getLocations: jest.fn().mockResolvedValue([
|
getLocations: jest.fn().mockResolvedValue([
|
||||||
{ "altitude": 5, "longitude": 10, "latitude": 15, "vin": "TESTVIN123" },
|
{ "altitude": 5, "longitude": 10, "latitude": 15, "vin": "TESTVIN123" },
|
||||||
]),
|
]),
|
||||||
|
getVehicles: async (search, token) => { return { data }; },
|
||||||
|
getYears: async (token) => {
|
||||||
|
return {
|
||||||
|
data: [2021, 2022],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
sendCommand: async (vin, command, parameters, token) => {
|
||||||
|
return {
|
||||||
|
vin, command, parameters
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default vehiclesAPI;
|
export default vehiclesAPI;
|
||||||
|
|||||||
@@ -51,7 +51,12 @@ const Commands = [{
|
|||||||
value: "close",
|
value: "close",
|
||||||
label: "Close window",
|
label: "Close window",
|
||||||
parameters: Windows,
|
parameters: Windows,
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
|
value: "ecu",
|
||||||
|
label: "ECU Versions",
|
||||||
|
},
|
||||||
|
{
|
||||||
value: "log",
|
value: "log",
|
||||||
label: "Log level",
|
label: "Log level",
|
||||||
parameters: [
|
parameters: [
|
||||||
|
|||||||
@@ -10,8 +10,17 @@ const vehiclesAPI = {
|
|||||||
})
|
})
|
||||||
.then(fetchRespHandler),
|
.then(fetchRespHandler),
|
||||||
|
|
||||||
getVehicles: async (search, token) => {
|
getConnections: async (vins, token) => {
|
||||||
const u = addQueryParams(`${API_ENDPOINT}/vehicles`, search);
|
const u = `${API_ENDPOINT}/carsconnected?vins=${vins.join(",")}`;
|
||||||
|
return fetch(u, {
|
||||||
|
method: "GET",
|
||||||
|
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
|
||||||
|
})
|
||||||
|
.then(fetchRespHandler)
|
||||||
|
},
|
||||||
|
|
||||||
|
getECUs: async (search, token) => {
|
||||||
|
const u = addQueryParams(`${API_ENDPOINT}/vehicleecus`, 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" }, getAuthHeaderOptions(token)),
|
||||||
@@ -25,6 +34,27 @@ const vehiclesAPI = {
|
|||||||
})
|
})
|
||||||
.then(fetchRespHandler),
|
.then(fetchRespHandler),
|
||||||
|
|
||||||
|
getLocations: async (token) => fetch(`${API_ENDPOINT}/carslocations`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
|
||||||
|
})
|
||||||
|
.then(fetchRespHandler),
|
||||||
|
|
||||||
|
getState: async (token, vin) => fetch(`${API_ENDPOINT}/carstate?vin=${vin}`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
|
||||||
|
})
|
||||||
|
.then(fetchRespHandler),
|
||||||
|
|
||||||
|
getVehicles: async (search, token) => {
|
||||||
|
const u = addQueryParams(`${API_ENDPOINT}/vehicles`, search);
|
||||||
|
return fetch(u, {
|
||||||
|
method: "GET",
|
||||||
|
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
|
||||||
|
})
|
||||||
|
.then(fetchRespHandler)
|
||||||
|
},
|
||||||
|
|
||||||
getYears: async (token) => fetch(`${API_ENDPOINT}/vehicleyears`, {
|
getYears: async (token) => fetch(`${API_ENDPOINT}/vehicleyears`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
|
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
|
||||||
@@ -39,27 +69,6 @@ const vehiclesAPI = {
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.then(fetchRespHandler),
|
.then(fetchRespHandler),
|
||||||
|
|
||||||
getConnections: async (vins, token) => {
|
|
||||||
const u = `${API_ENDPOINT}/carsconnected?vins=${vins.join(",")}`
|
|
||||||
return fetch(u, {
|
|
||||||
method: "GET",
|
|
||||||
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
|
|
||||||
})
|
|
||||||
.then(fetchRespHandler)
|
|
||||||
},
|
|
||||||
|
|
||||||
getLocations: async (token) => fetch(`${API_ENDPOINT}/carslocations`, {
|
|
||||||
method: "GET",
|
|
||||||
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
|
|
||||||
})
|
|
||||||
.then(fetchRespHandler),
|
|
||||||
|
|
||||||
getState: async (token, vin) => fetch(`${API_ENDPOINT}/carstate?vin=${vin}`, {
|
|
||||||
method: "GET",
|
|
||||||
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
|
|
||||||
})
|
|
||||||
.then(fetchRespHandler),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default vehiclesAPI;
|
export default vehiclesAPI;
|
||||||
|
|||||||
Reference in New Issue
Block a user