diff --git a/central_backend/src/server/servers.rs b/central_backend/src/server/servers.rs index e272246..446b2b9 100644 --- a/central_backend/src/server/servers.rs +++ b/central_backend/src/server/servers.rs @@ -139,6 +139,10 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()> "/web_api/devices/list_validated", web::get().to(devices_controller::list_validated), ) + .route( + "/web_api/device/{id}", + web::get().to(devices_controller::get_single), + ) .route( "/web_api/device/{id}/validate", web::post().to(devices_controller::validate_device), diff --git a/central_backend/src/server/web_api/devices_controller.rs b/central_backend/src/server/web_api/devices_controller.rs index 1ab0db2..a072b48 100644 --- a/central_backend/src/server/web_api/devices_controller.rs +++ b/central_backend/src/server/web_api/devices_controller.rs @@ -33,6 +33,18 @@ pub struct DeviceInPath { id: DeviceId, } +/// Get a single device information +pub async fn get_single(actor: WebEnergyActor, id: web::Path) -> HttpResult { + let Some(dev) = actor + .send(energy_actor::GetSingleDevice(id.id.clone())) + .await? + else { + return Ok(HttpResponse::NotFound().json("Requested device was not found!")); + }; + + Ok(HttpResponse::Ok().json(dev)) +} + /// Validate a device pub async fn validate_device(actor: WebEnergyActor, id: web::Path) -> HttpResult { actor diff --git a/central_frontend/src/App.tsx b/central_frontend/src/App.tsx index db625d8..9f7c016 100644 --- a/central_frontend/src/App.tsx +++ b/central_frontend/src/App.tsx @@ -12,6 +12,7 @@ import { HomeRoute } from "./routes/HomeRoute"; import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage"; import { PendingDevicesRoute } from "./routes/PendingDevicesRoute"; import { DevicesRoute } from "./routes/DevicesRoute"; +import { DeviceRoute } from "./routes/DeviceRoute"; export function App() { if (!AuthApi.SignedIn && !ServerApi.Config.auth_disabled) @@ -21,8 +22,9 @@ export function App() { createRoutesFromElements( }> } /> - } /> } /> + } /> + } /> } /> ) diff --git a/central_frontend/src/api/DeviceApi.ts b/central_frontend/src/api/DeviceApi.ts index 47ab1b7..0362283 100644 --- a/central_frontend/src/api/DeviceApi.ts +++ b/central_frontend/src/api/DeviceApi.ts @@ -37,8 +37,8 @@ export interface Device { relays: DeviceRelay[]; } -export function DeviceURL(d: Device, edit: boolean = false): string { - return `/dev/${d.id}${edit ? "/edit" : ""}`; +export function DeviceURL(d: Device): string { + return `/dev/${encodeURIComponent(d.id)}`; } export class DeviceApi { @@ -76,6 +76,18 @@ export class DeviceApi { }); } + /** + * Get the information about a single device + */ + static async GetSingle(id: string): Promise { + return ( + await APIClient.exec({ + uri: `/device/${encodeURIComponent(id)}`, + method: "GET", + }) + ).data; + } + /** * Delete a device */ diff --git a/central_frontend/src/routes/DeviceRoute.tsx b/central_frontend/src/routes/DeviceRoute.tsx new file mode 100644 index 0000000..d4d4349 --- /dev/null +++ b/central_frontend/src/routes/DeviceRoute.tsx @@ -0,0 +1,102 @@ +import { useParams } from "react-router-dom"; +import { Device, DeviceApi } from "../api/DeviceApi"; +import React from "react"; +import { AsyncWidget } from "../widgets/AsyncWidget"; +import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer"; +import { + Card, + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableRow, + Typography, +} from "@mui/material"; + +export function DeviceRoute(): React.ReactElement { + const { id } = useParams(); + const [device, setDevice] = React.useState(); + + const loadKey = React.useRef(1); + + const load = async () => { + setDevice(await DeviceApi.GetSingle(id!)); + }; + + const reload = () => { + loadKey.current += 1; + setDevice(undefined); + }; + + return ( + } + /> + ); +} + +function DeviceRouteInner(p: { + device: Device; + onReload: () => void; +}): React.ReactElement { + return ( + + + + ); +} + +function GeneralDeviceInfo(p: { device: Device }): React.ReactElement { + return ( + + + General device information + + + + + + + + + + + + +
+
+ ); +} + +function DeviceInfoProperty(p: { + icon?: React.ReactElement; + label: string; + value: string; +}): React.ReactElement { + return ( + + {p.label} + {p.value} + + ); +}