implemented web sockets

This commit is contained in:
Carter 2026-03-06 12:23:34 -06:00
parent e4fe48025e
commit 7939d540ac
2 changed files with 42 additions and 2 deletions

View file

@ -6,7 +6,7 @@ import { useDeviceAPI, useGlobalState, useSnackbar } from "providers";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useLocation, useParams } from "react-router-dom"; import { useLocation, useParams } from "react-router-dom";
import PageContainer from "./PageContainer"; import PageContainer from "./PageContainer";
import { useMobile } from "hooks"; import { useHTTP, useMobile } from "hooks";
import LoadingScreen from "app/LoadingScreen"; import LoadingScreen from "app/LoadingScreen";
import SmartBreadcrumb from "common/SmartBreadcrumb"; import SmartBreadcrumb from "common/SmartBreadcrumb";
import DeviceActions from "device/DeviceActions"; import DeviceActions from "device/DeviceActions";
@ -21,6 +21,7 @@ import { or } from "utils";
import ComponentDiagnostics from "component/ComponentDiagnostics"; import ComponentDiagnostics from "component/ComponentDiagnostics";
import DeviceWizard from "device/DeviceWizard"; import DeviceWizard from "device/DeviceWizard";
import DeviceScannedComponents from "device/autoDetect/DeviceScannedComponents"; import DeviceScannedComponents from "device/autoDetect/DeviceScannedComponents";
import { useWebSocket } from "hooks/useWebSocket";
export interface DevicePageData { export interface DevicePageData {
device: Device; device: Device;
@ -65,6 +66,8 @@ export default function DevicePage() {
// const [devicePageData, setDevicePageData] = useState(pond.GetDevicePageDataResponse.create()) // const [devicePageData, setDevicePageData] = useState(pond.GetDevicePageDataResponse.create())
const { token } = useHTTP();
const loadDevice = () => { const loadDevice = () => {
if (loading) return if (loading) return
if (state?.devicePageData) { if (state?.devicePageData) {
@ -165,6 +168,41 @@ export default function DevicePage() {
.finally(() => setLoading(false)); .finally(() => setLoading(false));
} }
// --- Real-time component updates ---
// Streams all component changes for this device.
// When the backend receives a new reading and updates a component,
// this fires and updates the component in state without a page refresh.
useWebSocket<{ key: string; component: Component }>({
path: `/v1/live/devices/${deviceID}/components`,
parse: (e) => {
const raw = JSON.parse(e.data);
const comp = Component.any(raw);
return { key: comp.key(), component: comp };
},
onMessage: ({ key, component }) => {
// Functional update so we always work with the latest state
setComponents((prev) => {
const updated = new Map(prev);
updated.set(key, component);
return updated;
});
},
token,
enabled: !!deviceID,
});
// --- Real-time device updates (optional) ---
// Updates device-level info (name, status, lastActive, etc.)
useWebSocket<Device>({
path: `/v1/live/devices/${deviceID}`,
parse: (e) => Device.any(JSON.parse(e.data)),
onMessage: (updatedDevice) => {
setDevice(updatedDevice);
},
token,
enabled: !!deviceID,
});
const loadPortScan = () => { const loadPortScan = () => {
deviceAPI.listFoundComponents(parseInt(deviceID)) deviceAPI.listFoundComponents(parseInt(deviceID))
.then(resp => { .then(resp => {

View file

@ -19,6 +19,7 @@ interface IHTTPContext {
) => Promise<AxiosResponse<T>>; ) => Promise<AxiosResponse<T>>;
del: <T>(url: string, spreadOptions?: AxiosRequestConfig) => Promise<AxiosResponse<T>>; del: <T>(url: string, spreadOptions?: AxiosRequestConfig) => Promise<AxiosResponse<T>>;
options: (demo?: boolean) => AxiosRequestConfig; options: (demo?: boolean) => AxiosRequestConfig;
token: string;
} }
interface Props extends PropsWithChildren<any>{ interface Props extends PropsWithChildren<any>{
@ -104,7 +105,8 @@ export default function HTTPProvider(props: Props) {
put, put,
post, post,
del, del,
options: defaultOptions options: defaultOptions,
token
}}> }}>
{/* <BillingProvider> */} {/* <BillingProvider> */}
<PondProvider> <PondProvider>