Display basic device information
This commit is contained in:
		@@ -139,6 +139,10 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
 | 
				
			|||||||
                "/web_api/devices/list_validated",
 | 
					                "/web_api/devices/list_validated",
 | 
				
			||||||
                web::get().to(devices_controller::list_validated),
 | 
					                web::get().to(devices_controller::list_validated),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					            .route(
 | 
				
			||||||
 | 
					                "/web_api/device/{id}",
 | 
				
			||||||
 | 
					                web::get().to(devices_controller::get_single),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
            .route(
 | 
					            .route(
 | 
				
			||||||
                "/web_api/device/{id}/validate",
 | 
					                "/web_api/device/{id}/validate",
 | 
				
			||||||
                web::post().to(devices_controller::validate_device),
 | 
					                web::post().to(devices_controller::validate_device),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,18 @@ pub struct DeviceInPath {
 | 
				
			|||||||
    id: DeviceId,
 | 
					    id: DeviceId,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Get a single device information
 | 
				
			||||||
 | 
					pub async fn get_single(actor: WebEnergyActor, id: web::Path<DeviceInPath>) -> 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
 | 
					/// Validate a device
 | 
				
			||||||
pub async fn validate_device(actor: WebEnergyActor, id: web::Path<DeviceInPath>) -> HttpResult {
 | 
					pub async fn validate_device(actor: WebEnergyActor, id: web::Path<DeviceInPath>) -> HttpResult {
 | 
				
			||||||
    actor
 | 
					    actor
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ import { HomeRoute } from "./routes/HomeRoute";
 | 
				
			|||||||
import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage";
 | 
					import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage";
 | 
				
			||||||
import { PendingDevicesRoute } from "./routes/PendingDevicesRoute";
 | 
					import { PendingDevicesRoute } from "./routes/PendingDevicesRoute";
 | 
				
			||||||
import { DevicesRoute } from "./routes/DevicesRoute";
 | 
					import { DevicesRoute } from "./routes/DevicesRoute";
 | 
				
			||||||
 | 
					import { DeviceRoute } from "./routes/DeviceRoute";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function App() {
 | 
					export function App() {
 | 
				
			||||||
  if (!AuthApi.SignedIn && !ServerApi.Config.auth_disabled)
 | 
					  if (!AuthApi.SignedIn && !ServerApi.Config.auth_disabled)
 | 
				
			||||||
@@ -21,8 +22,9 @@ export function App() {
 | 
				
			|||||||
    createRoutesFromElements(
 | 
					    createRoutesFromElements(
 | 
				
			||||||
      <Route path="*" element={<BaseAuthenticatedPage />}>
 | 
					      <Route path="*" element={<BaseAuthenticatedPage />}>
 | 
				
			||||||
        <Route path="" element={<HomeRoute />} />
 | 
					        <Route path="" element={<HomeRoute />} />
 | 
				
			||||||
        <Route path="devices" element={<DevicesRoute />} />
 | 
					 | 
				
			||||||
        <Route path="pending_devices" element={<PendingDevicesRoute />} />
 | 
					        <Route path="pending_devices" element={<PendingDevicesRoute />} />
 | 
				
			||||||
 | 
					        <Route path="devices" element={<DevicesRoute />} />
 | 
				
			||||||
 | 
					        <Route path="dev/:id" element={<DeviceRoute />} />
 | 
				
			||||||
        <Route path="*" element={<NotFoundRoute />} />
 | 
					        <Route path="*" element={<NotFoundRoute />} />
 | 
				
			||||||
      </Route>
 | 
					      </Route>
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,8 +37,8 @@ export interface Device {
 | 
				
			|||||||
  relays: DeviceRelay[];
 | 
					  relays: DeviceRelay[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function DeviceURL(d: Device, edit: boolean = false): string {
 | 
					export function DeviceURL(d: Device): string {
 | 
				
			||||||
  return `/dev/${d.id}${edit ? "/edit" : ""}`;
 | 
					  return `/dev/${encodeURIComponent(d.id)}`;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class DeviceApi {
 | 
					export class DeviceApi {
 | 
				
			||||||
@@ -76,6 +76,18 @@ export class DeviceApi {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Get the information about a single device
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static async GetSingle(id: string): Promise<Device> {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      await APIClient.exec({
 | 
				
			||||||
 | 
					        uri: `/device/${encodeURIComponent(id)}`,
 | 
				
			||||||
 | 
					        method: "GET",
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    ).data;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Delete a device
 | 
					   * Delete a device
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										102
									
								
								central_frontend/src/routes/DeviceRoute.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								central_frontend/src/routes/DeviceRoute.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -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<Device | undefined>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const loadKey = React.useRef(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const load = async () => {
 | 
				
			||||||
 | 
					    setDevice(await DeviceApi.GetSingle(id!));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const reload = () => {
 | 
				
			||||||
 | 
					    loadKey.current += 1;
 | 
				
			||||||
 | 
					    setDevice(undefined);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <AsyncWidget
 | 
				
			||||||
 | 
					      loadKey={loadKey.current}
 | 
				
			||||||
 | 
					      errMsg="Failed to load device information"
 | 
				
			||||||
 | 
					      load={load}
 | 
				
			||||||
 | 
					      ready={!!device}
 | 
				
			||||||
 | 
					      build={() => <DeviceRouteInner device={device!} onReload={reload} />}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function DeviceRouteInner(p: {
 | 
				
			||||||
 | 
					  device: Device;
 | 
				
			||||||
 | 
					  onReload: () => void;
 | 
				
			||||||
 | 
					}): React.ReactElement {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <SolarEnergyRouteContainer label={`Device ${p.device.name}`}>
 | 
				
			||||||
 | 
					      <GeneralDeviceInfo {...p} />
 | 
				
			||||||
 | 
					    </SolarEnergyRouteContainer>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function GeneralDeviceInfo(p: { device: Device }): React.ReactElement {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <TableContainer component={Paper}>
 | 
				
			||||||
 | 
					      <Typography variant="h6" style={{ padding: "6px" }}>
 | 
				
			||||||
 | 
					        General device information
 | 
				
			||||||
 | 
					      </Typography>
 | 
				
			||||||
 | 
					      <Table size="small">
 | 
				
			||||||
 | 
					        <TableBody>
 | 
				
			||||||
 | 
					          <DeviceInfoProperty label="ID" value={p.device.id} />
 | 
				
			||||||
 | 
					          <DeviceInfoProperty
 | 
				
			||||||
 | 
					            label="Reference"
 | 
				
			||||||
 | 
					            value={p.device.info.reference}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <DeviceInfoProperty label="Version" value={p.device.info.version} />
 | 
				
			||||||
 | 
					          <DeviceInfoProperty label="Name" value={p.device.name} />
 | 
				
			||||||
 | 
					          <DeviceInfoProperty
 | 
				
			||||||
 | 
					            label="Description"
 | 
				
			||||||
 | 
					            value={p.device.description}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <DeviceInfoProperty
 | 
				
			||||||
 | 
					            label="Enabled"
 | 
				
			||||||
 | 
					            value={p.device.enabled ? "YES" : "NO"}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <DeviceInfoProperty
 | 
				
			||||||
 | 
					            label="Maximum number of relays"
 | 
				
			||||||
 | 
					            value={p.device.info.max_relays.toString()}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <DeviceInfoProperty
 | 
				
			||||||
 | 
					            label="Number of configured relays"
 | 
				
			||||||
 | 
					            value={p.device.relays.length.toString()}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </TableBody>
 | 
				
			||||||
 | 
					      </Table>
 | 
				
			||||||
 | 
					    </TableContainer>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function DeviceInfoProperty(p: {
 | 
				
			||||||
 | 
					  icon?: React.ReactElement;
 | 
				
			||||||
 | 
					  label: string;
 | 
				
			||||||
 | 
					  value: string;
 | 
				
			||||||
 | 
					}): React.ReactElement {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <TableRow hover sx={{ "&:last-child td, &:last-child th": { border: 0 } }}>
 | 
				
			||||||
 | 
					      <TableCell>{p.label}</TableCell>
 | 
				
			||||||
 | 
					      <TableCell>{p.value}</TableCell>
 | 
				
			||||||
 | 
					    </TableRow>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user