Display the list of OTA updates in the frontend
This commit is contained in:
		@@ -49,3 +49,14 @@ pub fn get_ota_updates_for_platform(platform: OTAPlatform) -> anyhow::Result<Vec
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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('"', "");
 | 
			
		||||
 
 | 
			
		||||
@@ -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),
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								central_frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								central_frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -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",
 | 
			
		||||
 
 | 
			
		||||
@@ -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",
 | 
			
		||||
 
 | 
			
		||||
@@ -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<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 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<string[] | undefined>();
 | 
			
		||||
@@ -24,10 +35,23 @@ export function OTARoute(): React.ReactElement {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _OTARoute(p: { platforms: Array<string> }): React.ReactElement {
 | 
			
		||||
  const key = React.useRef(1);
 | 
			
		||||
  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 () => {
 | 
			
		||||
    /*todo*/
 | 
			
		||||
    key.current += 1;
 | 
			
		||||
    setList(undefined);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  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>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user