From 6cf7c2cae13d13e4bfa048cf8e240cf230bff613 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Tue, 8 Oct 2024 21:53:21 +0200 Subject: [PATCH] Display the list of OTA updates in the frontend --- central_backend/src/ota/ota_manager.rs | 11 ++++ central_backend/src/ota/ota_update.rs | 7 +++ central_backend/src/server/servers.rs | 2 +- .../src/server/web_api/ota_controller.rs | 7 ++- central_frontend/package-lock.json | 10 +++ central_frontend/package.json | 1 + central_frontend/src/api/OTAApi.ts | 18 ++++++ central_frontend/src/routes/OTARoute.tsx | 62 ++++++++++++++++++- 8 files changed, 113 insertions(+), 5 deletions(-) diff --git a/central_backend/src/ota/ota_manager.rs b/central_backend/src/ota/ota_manager.rs index ff38728..6e70516 100644 --- a/central_backend/src/ota/ota_manager.rs +++ b/central_backend/src/ota/ota_manager.rs @@ -49,3 +49,14 @@ pub fn get_ota_updates_for_platform(platform: OTAPlatform) -> anyhow::Result anyhow::Result> { + let mut out = vec![]; + + for p in OTAPlatform::supported_platforms() { + out.append(&mut get_ota_updates_for_platform(*p)?) + } + + Ok(out) +} diff --git a/central_backend/src/ota/ota_update.rs b/central_backend/src/ota/ota_update.rs index 2de832e..59ddccd 100644 --- a/central_backend/src/ota/ota_update.rs +++ b/central_backend/src/ota/ota_update.rs @@ -7,6 +7,13 @@ pub enum OTAPlatform { Wt32Eth01, } +impl OTAPlatform { + /// Get the list of supported platforms + pub fn supported_platforms() -> &'static [Self] { + &[OTAPlatform::Wt32Eth01] + } +} + impl Display for OTAPlatform { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let s = serde_json::to_string(&self).unwrap().replace('"', ""); diff --git a/central_backend/src/server/servers.rs b/central_backend/src/server/servers.rs index a2d6c66..700a1aa 100644 --- a/central_backend/src/server/servers.rs +++ b/central_backend/src/server/servers.rs @@ -191,7 +191,7 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()> "/web_api/ota/{platform}/{version}", 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( "/web_api/ota/{platform}", web::get().to(ota_controller::list_updates_platform), diff --git a/central_backend/src/server/web_api/ota_controller.rs b/central_backend/src/server/web_api/ota_controller.rs index c709449..e619288 100644 --- a/central_backend/src/server/web_api/ota_controller.rs +++ b/central_backend/src/server/web_api/ota_controller.rs @@ -10,7 +10,7 @@ use actix_multipart::form::MultipartForm; use actix_web::{web, HttpResponse}; pub async fn supported_platforms() -> HttpResult { - Ok(HttpResponse::Ok().json(vec![OTAPlatform::Wt32Eth01])) + Ok(HttpResponse::Ok().json(OTAPlatform::supported_platforms())) } #[derive(Debug, MultipartForm)] @@ -53,6 +53,11 @@ pub async fn upload_firmware( 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)] pub struct ListOTAPath { platform: OTAPlatform, diff --git a/central_frontend/package-lock.json b/central_frontend/package-lock.json index 564b209..2faf1a3 100644 --- a/central_frontend/package-lock.json +++ b/central_frontend/package-lock.json @@ -20,6 +20,7 @@ "@types/semver": "^7.5.8", "date-and-time": "^3.6.0", "dayjs": "^1.11.13", + "filesize": "^10.1.6", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.26.2", @@ -3232,6 +3233,15 @@ "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": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", diff --git a/central_frontend/package.json b/central_frontend/package.json index b3e03c9..78090e9 100644 --- a/central_frontend/package.json +++ b/central_frontend/package.json @@ -22,6 +22,7 @@ "@types/semver": "^7.5.8", "date-and-time": "^3.6.0", "dayjs": "^1.11.13", + "filesize": "^10.1.6", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.26.2", diff --git a/central_frontend/src/api/OTAApi.ts b/central_frontend/src/api/OTAApi.ts index 0e2d9b2..962c761 100644 --- a/central_frontend/src/api/OTAApi.ts +++ b/central_frontend/src/api/OTAApi.ts @@ -1,5 +1,11 @@ import { APIClient } from "./ApiClient"; +export interface OTAUpdate { + platform: string; + version: string; + file_size: number; +} + export class OTAAPI { /** * Get the list of supported OTA platforms @@ -30,4 +36,16 @@ export class OTAAPI { formData: fd, }); } + + /** + * Get the list of OTA updates + */ + static async ListOTAUpdates(): Promise { + return ( + await APIClient.exec({ + method: "GET", + uri: "/ota", + }) + ).data; + } } diff --git a/central_frontend/src/routes/OTARoute.tsx b/central_frontend/src/routes/OTARoute.tsx index c0728ed..d248c7a 100644 --- a/central_frontend/src/routes/OTARoute.tsx +++ b/central_frontend/src/routes/OTARoute.tsx @@ -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 FileUploadIcon from "@mui/icons-material/FileUpload"; import { UploadUpdateDialog } from "../dialogs/UploadUpdateDialog"; import React from "react"; -import { OTAAPI } from "../api/OTAApi"; +import { OTAAPI, OTAUpdate } from "../api/OTAApi"; import { AsyncWidget } from "../widgets/AsyncWidget"; +import { filesize } from "filesize"; export function OTARoute(): React.ReactElement { const [list, setList] = React.useState(); @@ -24,10 +35,23 @@ export function OTARoute(): React.ReactElement { } function _OTARoute(p: { platforms: Array }): React.ReactElement { + const key = React.useRef(1); const [showUploadDialog, setShowUploadDialog] = React.useState(false); + const [list, setList] = React.useState(); + + 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 () => { - /*todo*/ + key.current += 1; + setList(undefined); }; return ( @@ -53,6 +77,38 @@ function _OTARoute(p: { platforms: Array }): React.ReactElement { }} /> )} + <_OTAList list={list!} />} + /> ); } + +function _OTAList(p: { list: OTAUpdate[] }): React.ReactElement { + return ( + + + + + Platform + Version + File size + + + + {p.list.map((row, num) => ( + + {row.platform} + {row.version} + {filesize(row.file_size)} + + ))} + +
+
+ ); +}