First pass diagnostics display.

This commit is contained in:
James Pace 2026-08-16 20:51:31 -04:00
parent 9d3767d68c
commit 1e16d0e482
5 changed files with 4892 additions and 2844 deletions

4422
.pnp.cjs generated

File diff suppressed because one or more lines are too long

1201
.pnp.loader.mjs generated

File diff suppressed because it is too large Load Diff

View File

@ -58,7 +58,8 @@ export function Autonomy() {
const statusString = useAtomValue(statusStringAtom); const statusString = useAtomValue(statusStringAtom);
const latLong = useAtomValue(latLongAtom); const latLong = useAtomValue(latLongAtom);
const imageStreamURI = "http://" + window.location.hostname + ":8889/image/whep"; const imageStreamURI =
"http://" + window.location.hostname + ":8889/image/whep";
return ( return (
<div> <div>

View File

@ -38,30 +38,26 @@ const diagAtom = atom((get) => {
if (!diag.data.status) { if (!diag.data.status) {
return "Failed to get diagnostic information."; return "Failed to get diagnostic information.";
} }
return diag.data.message return diag.data.message;
}); });
export function Diagnostics() { export function Diagnostics() {
const diagnostics = useAtomValue(diagAtom); const diagnostics = useAtomValue(diagAtom);
const diagContent = () => { const diagContent = () => {
if (typeof diagnostics === 'string' || diagnostics instanceof String) if (typeof diagnostics === "string" || diagnostics instanceof String) {
{ return <pre> {diagnostics} </pre>;
return (<pre> {diagnostics} </pre>);
} }
return (<TreeView data={diagnostics}/>); return <TreeView data={diagnostics} />;
}; };
return ( return (
<div> <div>
<AppNav /> <AppNav />
<Container className="vert-padded"> <Container className="vert-padded">
<Card className="padded"> <Card className="padded">
<Card.Title>Diagnostics</Card.Title> <Card.Title>Diagnostics</Card.Title>
<Card.Body> <Card.Body>{diagContent()}</Card.Body>
{diagContent()}
</Card.Body>
</Card> </Card>
</Container> </Container>
<Footer /> <Footer />

View File

@ -1,50 +1,127 @@
import React, { useState } from 'react'; import React, { useState } from "react";
import { ListGroup, Collapse } from 'react-bootstrap'; import { Button, ListGroup, Collapse, Card } from "react-bootstrap";
import {
Dash,
ChevronDown,
ChevronRight,
CircleFill,
} from "react-bootstrap-icons";
import Table from "react-bootstrap/Table";
import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
/* export function TreeView(props: Any) {
const treeData = [ const data = props.data;
{
id: 1,
label: "Documents",
children: [
{ id: 2, label: "Resume.pdf" },
{ id: 3, label: "CoverLetter.pdf" }
]
},
{
id: 4,
label: "Pictures",
children: [
{ id: 5, label: "Vacation.jpg" }
]
}
];
*/
export function TreeView({ data })
{
return ( return (
<ListGroup className="border-0"> <ListGroup className="border-0">
{data.children.map(node => ( {data.children.map((node) => (
<TreeNode key={node.id} node={node} /> <SingleNode key={node.id} node={node} />
))} ))}
</ListGroup> </ListGroup>
); );
}; }
function SingleNode({ node }) { function LevelIndicator(props: Any) {
console.log(node); const level = props.level;
if (level == "ERROR") {
return <CircleFill color="red" />;
}
if (level == "WARN") {
return <CircleFill color="orange" />;
}
if (level == "OK") {
return <CircleFill color="green" />;
}
return <CircleFill color="grey" />;
}
function MessageText(props: Any) {
if (props.message === "") {
return <div></div>;
}
return <div>Message: {props.message}</div>;
}
function ValuesTable(props: Any) {
const values = props.values;
if (Object.keys(values).length === 0) {
return <div></div>;
}
return ( return (
<div> <Table>
{node.name} {node.level} <thead>
</div> <th>Key</th>
<th>Value</th>
</thead>
<tbody>
{Object.entries(values).map(([key, value]) => (
<tr key={key}>
<td>{key}</td>
<td>{value}</td>
</tr>
))}
</tbody>
</Table>
); );
} }
function TreeNode({ node }) { function StatusContent(props: Any) {
const status = props.status;
console.log(status);
return (
<Card.Body>
<Card.Title>
<LevelIndicator level={status.level} /> {status.name}
</Card.Title>
<Card.Text>
<MessageText message={status.message} />
</Card.Text>
<Card.Text>
<ValuesTable values={status.values} />
</Card.Text>
</Card.Body>
);
}
function DirectionIcon(props: Any) {
let icon = <ChevronRight />;
if (props.isOpen) {
icon = <ChevronDown />;
}
if (!props.hasChildren) {
icon = <Dash />;
}
return (
<Button variant="link" onClick={props.onClick}>
{icon}
</Button>
);
}
function ChildStatuses(props: Any) {
const isOpen = props.isOpen;
const node = props.node;
return (
<Collapse in={isOpen}>
<div>
<ListGroup className="ms-2 border-start">
{node.children.map((child) => (
<SingleNode key={child.id} node={child} />
))}
</ListGroup>
</div>
</Collapse>
);
}
function SingleNode(props: Any) {
const node = props.node;
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const hasChildren = node.children && node.children.length > 0; const hasChildren = node.children && node.children.length > 0;
const onClick = () => { const openFunction = () => {
if (hasChildren) { if (hasChildren) {
setIsOpen(!isOpen); setIsOpen(!isOpen);
} }
@ -52,20 +129,25 @@ function TreeNode({ node }) {
return ( return (
<ListGroup.Item className="border-0 ps-3 py-1"> <ListGroup.Item className="border-0 ps-3 py-1">
<div onClick={onClick}> <Card>
<SingleNode node={node.status} /> <Container>
</div> <Row>
<Col xs={1}>
<Collapse in={isOpen}> <DirectionIcon
<div> isOpen={isOpen}
<ListGroup className="ms-2 border-start"> hasChildren={hasChildren}
{node.children.map(child => ( onClick={openFunction}
<TreeNode key={child.id} node={child} /> />
))} </Col>
</ListGroup> <Col xs={"auto"}>
</div> <StatusContent status={node.status} />
</Collapse> </Col>
</Row>
<Row>
<ChildStatuses isOpen={isOpen} node={node} />
</Row>
</Container>
</Card>
</ListGroup.Item> </ListGroup.Item>
); );
}; }