Display the list of OTA updates in the frontend
This commit is contained in:
parent
2924d14281
commit
6cf7c2cae1
@ -49,3 +49,14 @@ pub fn get_ota_updates_for_platform(platform: OTAPlatform) -> anyhow::Result<Vec
|
|||||||
|
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all the available OTA updates
|
||||||
|
pub fn get_all_ota_updates() -> anyhow::Result<Vec<OTAUpdate>> {
|
||||||
|
let mut out = vec![];
|
||||||
|
|
||||||
|
for p in OTAPlatform::supported_platforms() {
|
||||||
|
out.append(&mut get_ota_updates_for_platform(*p)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
@ -7,6 +7,13 @@ pub enum OTAPlatform {
|
|||||||
Wt32Eth01,
|
Wt32Eth01,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl OTAPlatform {
|
||||||
|
/// Get the list of supported platforms
|
||||||
|
pub fn supported_platforms() -> &'static [Self] {
|
||||||
|
&[OTAPlatform::Wt32Eth01]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for OTAPlatform {
|
impl Display for OTAPlatform {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
let s = serde_json::to_string(&self).unwrap().replace('"', "");
|
let s = serde_json::to_string(&self).unwrap().replace('"', "");
|
||||||
|
@ -191,7 +191,7 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
|
|||||||
"/web_api/ota/{platform}/{version}",
|
"/web_api/ota/{platform}/{version}",
|
||||||
web::post().to(ota_controller::upload_firmware),
|
web::post().to(ota_controller::upload_firmware),
|
||||||
)
|
)
|
||||||
// TODO : list all ota software updates
|
.route("/web_api/ota", web::get().to(ota_controller::list_all_ota))
|
||||||
.route(
|
.route(
|
||||||
"/web_api/ota/{platform}",
|
"/web_api/ota/{platform}",
|
||||||
web::get().to(ota_controller::list_updates_platform),
|
web::get().to(ota_controller::list_updates_platform),
|
||||||
|
@ -10,7 +10,7 @@ use actix_multipart::form::MultipartForm;
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{web, HttpResponse};
|
||||||
|
|
||||||
pub async fn supported_platforms() -> HttpResult {
|
pub async fn supported_platforms() -> HttpResult {
|
||||||
Ok(HttpResponse::Ok().json(vec![OTAPlatform::Wt32Eth01]))
|
Ok(HttpResponse::Ok().json(OTAPlatform::supported_platforms()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, MultipartForm)]
|
#[derive(Debug, MultipartForm)]
|
||||||
@ -53,6 +53,11 @@ pub async fn upload_firmware(
|
|||||||
Ok(HttpResponse::Accepted().body("OTA update successfully saved."))
|
Ok(HttpResponse::Accepted().body("OTA update successfully saved."))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the list of all OTA updates
|
||||||
|
pub async fn list_all_ota() -> HttpResult {
|
||||||
|
Ok(HttpResponse::Ok().json(ota_manager::get_all_ota_updates()?))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub struct ListOTAPath {
|
pub struct ListOTAPath {
|
||||||
platform: OTAPlatform,
|
platform: OTAPlatform,
|
||||||
|
10
central_frontend/package-lock.json
generated
10
central_frontend/package-lock.json
generated
@ -20,6 +20,7 @@
|
|||||||
"@types/semver": "^7.5.8",
|
"@types/semver": "^7.5.8",
|
||||||
"date-and-time": "^3.6.0",
|
"date-and-time": "^3.6.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
|
"filesize": "^10.1.6",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-router-dom": "^6.26.2",
|
"react-router-dom": "^6.26.2",
|
||||||
@ -3232,6 +3233,15 @@
|
|||||||
"node": "^10.12.0 || >=12.0.0"
|
"node": "^10.12.0 || >=12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/filesize": {
|
||||||
|
"version": "10.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz",
|
||||||
|
"integrity": "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"@types/semver": "^7.5.8",
|
"@types/semver": "^7.5.8",
|
||||||
"date-and-time": "^3.6.0",
|
"date-and-time": "^3.6.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
|
"filesize": "^10.1.6",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-router-dom": "^6.26.2",
|
"react-router-dom": "^6.26.2",
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
import { APIClient } from "./ApiClient";
|
import { APIClient } from "./ApiClient";
|
||||||
|
|
||||||
|
export interface OTAUpdate {
|
||||||
|
platform: string;
|
||||||
|
version: string;
|
||||||
|
file_size: number;
|
||||||
|
}
|
||||||
|
|
||||||
export class OTAAPI {
|
export class OTAAPI {
|
||||||
/**
|
/**
|
||||||
* Get the list of supported OTA platforms
|
* Get the list of supported OTA platforms
|
||||||
@ -30,4 +36,16 @@ export class OTAAPI {
|
|||||||
formData: fd,
|
formData: fd,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of OTA updates
|
||||||
|
*/
|
||||||
|
static async ListOTAUpdates(): Promise<OTAUpdate[]> {
|
||||||
|
return (
|
||||||
|
await APIClient.exec({
|
||||||
|
method: "GET",
|
||||||
|
uri: "/ota",
|
||||||
|
})
|
||||||
|
).data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,21 @@
|
|||||||
import { IconButton, Tooltip } from "@mui/material";
|
import {
|
||||||
|
IconButton,
|
||||||
|
Paper,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
Tooltip,
|
||||||
|
} from "@mui/material";
|
||||||
import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer";
|
import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer";
|
||||||
import FileUploadIcon from "@mui/icons-material/FileUpload";
|
import FileUploadIcon from "@mui/icons-material/FileUpload";
|
||||||
import { UploadUpdateDialog } from "../dialogs/UploadUpdateDialog";
|
import { UploadUpdateDialog } from "../dialogs/UploadUpdateDialog";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { OTAAPI } from "../api/OTAApi";
|
import { OTAAPI, OTAUpdate } from "../api/OTAApi";
|
||||||
import { AsyncWidget } from "../widgets/AsyncWidget";
|
import { AsyncWidget } from "../widgets/AsyncWidget";
|
||||||
|
import { filesize } from "filesize";
|
||||||
|
|
||||||
export function OTARoute(): React.ReactElement {
|
export function OTARoute(): React.ReactElement {
|
||||||
const [list, setList] = React.useState<string[] | undefined>();
|
const [list, setList] = React.useState<string[] | undefined>();
|
||||||
@ -24,10 +35,23 @@ export function OTARoute(): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _OTARoute(p: { platforms: Array<string> }): React.ReactElement {
|
function _OTARoute(p: { platforms: Array<string> }): React.ReactElement {
|
||||||
|
const key = React.useRef(1);
|
||||||
const [showUploadDialog, setShowUploadDialog] = React.useState(false);
|
const [showUploadDialog, setShowUploadDialog] = React.useState(false);
|
||||||
|
|
||||||
|
const [list, setList] = React.useState<undefined | OTAUpdate[]>();
|
||||||
|
|
||||||
|
const load = async () => {
|
||||||
|
const list = await OTAAPI.ListOTAUpdates();
|
||||||
|
list.sort((a, b) =>
|
||||||
|
`${a.platform}#${a.version}`.localeCompare(`${b.platform}#${b.version}`)
|
||||||
|
);
|
||||||
|
list.reverse();
|
||||||
|
setList(list);
|
||||||
|
};
|
||||||
|
|
||||||
const reload = async () => {
|
const reload = async () => {
|
||||||
/*todo*/
|
key.current += 1;
|
||||||
|
setList(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -53,6 +77,38 @@ function _OTARoute(p: { platforms: Array<string> }): React.ReactElement {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<AsyncWidget
|
||||||
|
loadKey={key.current}
|
||||||
|
ready={!!list}
|
||||||
|
errMsg="Failed to load the list of OTA updates!"
|
||||||
|
load={load}
|
||||||
|
build={() => <_OTAList list={list!} />}
|
||||||
|
/>
|
||||||
</SolarEnergyRouteContainer>
|
</SolarEnergyRouteContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _OTAList(p: { list: OTAUpdate[] }): React.ReactElement {
|
||||||
|
return (
|
||||||
|
<TableContainer component={Paper}>
|
||||||
|
<Table sx={{ minWidth: 650 }} aria-label="simple table">
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell align="center">Platform</TableCell>
|
||||||
|
<TableCell align="center">Version</TableCell>
|
||||||
|
<TableCell align="center">File size</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{p.list.map((row, num) => (
|
||||||
|
<TableRow hover key={num}>
|
||||||
|
<TableCell align="center">{row.platform}</TableCell>
|
||||||
|
<TableCell align="center">{row.version}</TableCell>
|
||||||
|
<TableCell align="center">{filesize(row.file_size)}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user