Compare commits

..

No commits in common. "86870c4d2af5ece3d711add526765f57ee1ae50c" and "bb35a80e97912a40bdb228275a0e960aebde469a" have entirely different histories.

6 changed files with 55 additions and 139 deletions

View File

@ -2,9 +2,8 @@ import { useState } from "react";
import { createBrowserRouter, RouterProvider } from "react-router-dom"; import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { Provider as JotaiProvider } from "jotai"; import { Provider as JotaiProvider } from "jotai";
import { Home } from "./Home.tsx"; import { Home } from "./Home.tsx";
import { Autonomy } from "./Autonomy.tsx";
import { Version } from "./Version.tsx"; import { Version } from "./Version.tsx";
import { WhoAmI } from "./WhoAmI.tsx"; import { Network } from "./Network.tsx";
import "./App.css"; import "./App.css";
function App() { function App() {
@ -27,17 +26,13 @@ const router = createBrowserRouter([
element: <Home />, element: <Home />,
}, },
{ {
path: "/whoami", path: "/network",
element: <WhoAmI />, element: <Network />,
}, },
{ {
path: "/version", path: "/version",
element: <Version />, element: <Version />,
}, },
{
path: "/autonomy",
element: <Autonomy />,
},
]); ]);
export default App; export default App;

View File

@ -6,7 +6,7 @@ export function AppNav() {
<Navbar bg="dark" variant="dark" expand="sm" className="py-0"> <Navbar bg="dark" variant="dark" expand="sm" className="py-0">
<Container className="me-auto"> <Container className="me-auto">
<Navbar.Brand as={Link} to="/"> <Navbar.Brand as={Link} to="/">
J7s-Bridge N-DRIVE
</Navbar.Brand> </Navbar.Brand>
<Navbar.Toggle aria-controls="collapse-navbar-nav" /> <Navbar.Toggle aria-controls="collapse-navbar-nav" />
<Navbar.Collapse id="collapse-navbar-nav"> <Navbar.Collapse id="collapse-navbar-nav">
@ -17,11 +17,8 @@ export function AppNav() {
<Nav.Link as={Link} to="/version"> <Nav.Link as={Link} to="/version">
Version Version
</Nav.Link> </Nav.Link>
<Nav.Link as={Link} to="/whoami"> <Nav.Link as={Link} to="/network">
WhoAmI Network
</Nav.Link>
<Nav.Link as={Link} to="/autonomy">
Autonomy
</Nav.Link> </Nav.Link>
</Nav> </Nav>
</Navbar.Collapse> </Navbar.Collapse>
@ -31,5 +28,5 @@ export function AppNav() {
} }
export function Footer() { export function Footer() {
return <p className="footer">Copyright 2026 James Pace</p>; return <p className="footer">Made with {"<3"} by James Pace.</p>;
} }

View File

@ -1,97 +0,0 @@
import { AppNav, Footer } from "./AppNav.tsx";
import { Container, Row, Col, Image, Card } from "react-bootstrap";
import { atom, useAtomValue } from "jotai";
import { atomWithQuery } from "jotai-tanstack-query";
const costmapImageQuery = async () => {
const resp = await fetch("api/costmap_image");
if (!resp.ok) {
throw new Error("Network response was not ok");
}
const blob = await resp.blob();
return URL.createObjectURL(blob);
};
const costmapImageQueryAtom = atomWithQuery(() => ({
queryKey: ["costmap_image"],
queryFn: costmapImageQuery,
refetchInterval: 1000, // 1s
}));
const costmapImageAtom = atom((get) => {
const response = get(costmapImageQueryAtom);
if (response.isPending) {
return <p>"Loading..."</p>;
}
if (response.isError) {
return <p>"Error loading!"</p>;
}
const costmapStyle = {
minHeight: "65svb",
};
return <Image src={response.data} fluid style={costmapStyle} />;
});
const statusStringQuery = async () => {
const resp = await fetch("api/status");
if (!resp.ok) {
throw new Error("Network response was not ok");
}
return resp.json();
};
const statusStringQueryAtom = atomWithQuery(() => ({
queryKey: ["status_string"],
queryFn: statusStringQuery,
refetchInterval: 500, // 0.5s
}));
const statusStringAtom = atom((get) => {
const response = get(statusStringQueryAtom);
if (response.isPending || response.isError || !response.data.status) {
return "N/A";
}
return response.data.message;
});
const latLongQuery = async () => {
const resp = await fetch("api/position");
if (!resp.ok) {
throw new Error("Network response was not ok");
}
return resp.json();
};
const latLongQueryAtom = atomWithQuery(() => ({
queryKey: ["latlong"],
queryFn: latLongQuery,
refetchInterval: 500, // 0.5s
}));
const latLongAtom = atom((get) => {
const response = get(latLongQueryAtom);
if (response.isPending || response.isError || !response.data.status) {
return "N/A";
}
return `(${response.data.latitude}, ${response.data.longitude})`;
});
export function Autonomy() {
const costmapImage = useAtomValue(costmapImageAtom);
const statusString = useAtomValue(statusStringAtom);
const latLong = useAtomValue(latLongAtom);
return (
<div>
<AppNav />
<Container className="vert-padded">
<Card className="padded">
<Row>
<Col lg={8}>{costmapImage}</Col>
<Col lg={4}>
<p>Status:</p>
<pre>{statusString}</pre>
<p>Latitude, Longitude:</p>
<pre>{latLong}</pre>
</Col>
</Row>
</Card>
</Container>
<Footer />
</div>
);
}

View File

@ -1,18 +1,40 @@
import { AppNav, Footer } from "./AppNav.tsx"; import { AppNav, Footer } from "./AppNav.tsx";
import { Container, Row, Col, Image, Card } from "react-bootstrap"; import { Container, Row, Col, Image } from "react-bootstrap";
import { atom, useAtomValue } from "jotai"; import { atom, useAtom } from "jotai";
import { atomWithQuery } from "jotai-tanstack-query"; import { atomWithQuery } from "jotai-tanstack-query";
const costmapImageQuery = async () => {
const resp = await fetch("api/costmap_image");
if (!resp.ok) {
throw new Error("Network response was not ok");
}
const blob = await resp.blob();
return URL.createObjectURL(blob);
};
const costmapImageAtom = atomWithQuery(() => ({
queryKey: ["costmap_image"],
queryFn: costmapImageQuery,
refetchInterval: 1000 // 1s
}));
export function Home() { export function Home() {
const [{ data, isPending, isError }] = useAtom(costmapImageAtom);
let costmapImage = () => {
if (isPending) {
return (<p>"Loading..."</p>);
}
if (isError) {
return(<p>"Error!"</p>);
}
return (<Image src={data} />);
};
return ( return (
<div> <div>
<AppNav /> <AppNav />
<Container className="vert-padded"> <Container>
<Card className="padded"> { costmapImage() }
<Row>
<p>Hello World!</p>
</Row>
</Card>
</Container> </Container>
<Footer /> <Footer />
</div> </div>

View File

@ -1,7 +1,7 @@
import { AppNav, Footer } from "./AppNav.tsx"; import { AppNav, Footer } from "./AppNav.tsx";
import { Container, Row, Col, Image } from "react-bootstrap"; import { Container, Row, Col, Image } from "react-bootstrap";
export function WhoAmI() { export function Network() {
return ( return (
<div> <div>
<AppNav /> <AppNav />

View File

@ -1,6 +1,6 @@
import { AppNav, Footer } from "./AppNav.tsx"; import { AppNav, Footer } from "./AppNav.tsx";
import { Container, Row, Col, Card } from "react-bootstrap"; import { Container, Row, Col, Card } from "react-bootstrap";
import { atom, useAtomValue } from "jotai"; import { atom, useAtom } from "jotai";
import { atomWithQuery } from "jotai-tanstack-query"; import { atomWithQuery } from "jotai-tanstack-query";
import YAML from "yaml"; import YAML from "yaml";
@ -12,27 +12,26 @@ const versionQueryFn = async () => {
return resp.json(); return resp.json();
}; };
const versionQueryAtom = atomWithQuery(() => ({ const versionAtom = atomWithQuery(() => ({
queryKey: ["version"], queryKey: ["version"],
queryFn: versionQueryFn, queryFn: versionQueryFn,
})); }));
const versionAtom = atom((get) => { export function Version() {
const version = get(versionQueryAtom); const [{ data, isPending, isError }] = useAtom(versionAtom);
if (version.isPending) {
let versionText = () => {
if (isPending) {
return "Loading..."; return "Loading...";
} }
if (version.isError) { if (isError) {
return "Error loading!"; return "Error loading!";
} }
if (!version.data.status) { if (!data.status) {
return "Can not find version"; return "Can not find version";
} }
return YAML.stringify(version.data.message); return YAML.stringify(data.message);
}); };
export function Version() {
let versionText = useAtomValue(versionAtom);
return ( return (
<div> <div>
@ -41,7 +40,7 @@ export function Version() {
<Card className="padded"> <Card className="padded">
<Card.Title>project.yaml</Card.Title> <Card.Title>project.yaml</Card.Title>
<Card.Body> <Card.Body>
<pre>{versionText}</pre> <pre>{versionText()}</pre>
</Card.Body> </Card.Body>
</Card> </Card>
</Container> </Container>