Compare commits
2 Commits
24281cd491
...
ea7eb45665
| Author | SHA1 | Date |
|---|---|---|
|
|
ea7eb45665 | |
|
|
11e799207e |
36
src/Home.tsx
36
src/Home.tsx
|
|
@ -14,12 +14,12 @@ import { atom, useAtomValue } from "jotai";
|
||||||
import { createQueryAtom } from "./utils/query.ts";
|
import { createQueryAtom } from "./utils/query.ts";
|
||||||
import { DiagnosticsCard } from "./components/DiagnosticsCard.tsx";
|
import { DiagnosticsCard } from "./components/DiagnosticsCard.tsx";
|
||||||
|
|
||||||
const statusStringQueryAtom = createQueryAtom("status_string", "api/status", {
|
const identityStringQueryAtom = createQueryAtom("api/identity", {
|
||||||
refetchInterval: 500,
|
refetchInterval: 500,
|
||||||
});
|
});
|
||||||
const statusStringAtom = atom((get) => {
|
const identityStringAtom = atom((get) => {
|
||||||
const response = get(statusStringQueryAtom);
|
const response = get(identityStringQueryAtom);
|
||||||
if (response.isPending || response.isError || !response.data.status) {
|
if (response.isPending || response.isError) {
|
||||||
return "N/A";
|
return "N/A";
|
||||||
}
|
}
|
||||||
return response.data.message;
|
return response.data.message;
|
||||||
|
|
@ -36,16 +36,14 @@ const uptimeAtom = atom((get) => {
|
||||||
return response.data.uptime.toFixed(1);
|
return response.data.uptime.toFixed(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
function StatusCard() {
|
function IdentityCard() {
|
||||||
const statusString = useAtomValue(statusStringAtom);
|
const identityString = useAtomValue(identityStringAtom);
|
||||||
return (
|
return (
|
||||||
<Card className="padded">
|
<Card className="padded h-100">
|
||||||
<Row>
|
<Card.Title>Identity</Card.Title>
|
||||||
<p>Status:</p>
|
<Card.Body>
|
||||||
</Row>
|
<div style={{ whiteSpace: "pre-line" }}>{identityString}</div>
|
||||||
<Row>
|
</Card.Body>
|
||||||
<p>{statusString}</p>
|
|
||||||
</Row>
|
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -53,13 +51,11 @@ function StatusCard() {
|
||||||
function UptimeCard() {
|
function UptimeCard() {
|
||||||
const uptime = useAtomValue(uptimeAtom);
|
const uptime = useAtomValue(uptimeAtom);
|
||||||
return (
|
return (
|
||||||
<Card className="padded">
|
<Card className="padded h-100">
|
||||||
<Row>
|
<Card.Title>Uptime</Card.Title>
|
||||||
<p>Uptime:</p>
|
<Card.Body>
|
||||||
</Row>
|
|
||||||
<Row>
|
|
||||||
<p>{uptime}s</p>
|
<p>{uptime}s</p>
|
||||||
</Row>
|
</Card.Body>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +70,7 @@ export function Home() {
|
||||||
<UptimeCard />
|
<UptimeCard />
|
||||||
</Col>
|
</Col>
|
||||||
<Col>
|
<Col>
|
||||||
<StatusCard />
|
<IdentityCard />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row className="vert-padded">
|
<Row className="vert-padded">
|
||||||
|
|
|
||||||
|
|
@ -14,35 +14,59 @@ import { atom, useAtomValue } from "jotai";
|
||||||
import { createQueryAtom } from "./utils/query.ts";
|
import { createQueryAtom } from "./utils/query.ts";
|
||||||
import YAML from "yaml";
|
import YAML from "yaml";
|
||||||
|
|
||||||
const versionQueryAtom = createQueryAtom("api/build_info");
|
const buildInfoQueryAtom = createQueryAtom("api/build_info");
|
||||||
|
const buildInfoAtom = atom((get) => {
|
||||||
const versionAtom = atom((get) => {
|
const buildInfo = get(buildInfoQueryAtom);
|
||||||
const version = get(versionQueryAtom);
|
if (buildInfo.isPending) {
|
||||||
if (version.isPending) {
|
|
||||||
return "Loading...";
|
return "Loading...";
|
||||||
}
|
}
|
||||||
if (version.isError) {
|
if (buildInfo.isError) {
|
||||||
return "Error loading!";
|
return "Error loading!";
|
||||||
}
|
}
|
||||||
if (!version.data.status) {
|
if (!buildInfo.data.status) {
|
||||||
return "Can not find version";
|
return "Can not find buildInfo";
|
||||||
}
|
}
|
||||||
return YAML.stringify(version.data.message);
|
return YAML.stringify(buildInfo.data.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
const versionNumberQueryAtom = createQueryAtom("api/version_number");
|
||||||
|
const versionNumberAtom = atom((get) => {
|
||||||
|
const versionNumber = get(versionNumberQueryAtom);
|
||||||
|
if (versionNumber.isPending || versionNumber.isError) {
|
||||||
|
return "...";
|
||||||
|
}
|
||||||
|
if (!versionNumber.data.status) {
|
||||||
|
return "Can not find version number.";
|
||||||
|
}
|
||||||
|
return versionNumber.data.version;
|
||||||
});
|
});
|
||||||
|
|
||||||
export function Version() {
|
export function Version() {
|
||||||
let versionText = useAtomValue(versionAtom);
|
let buildInfoText = useAtomValue(buildInfoAtom);
|
||||||
|
let versionText = useAtomValue(versionNumberAtom);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<AppNav />
|
<AppNav />
|
||||||
<Container className="vert-padded">
|
<Container className="vert-padded">
|
||||||
<Card className="padded">
|
<Row>
|
||||||
<Card.Title>project.yaml</Card.Title>
|
<Col>
|
||||||
<Card.Body>
|
<Card className="padded">
|
||||||
<pre>{versionText}</pre>
|
<Card.Title>Version Number</Card.Title>
|
||||||
</Card.Body>
|
<Card.Body>{versionText}</Card.Body>
|
||||||
</Card>
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row className="vert-padded">
|
||||||
|
<Col>
|
||||||
|
<Card className="padded">
|
||||||
|
<Card.Title>project.yaml</Card.Title>
|
||||||
|
<Card.Body>
|
||||||
|
<pre>{buildInfoText}</pre>
|
||||||
|
</Card.Body>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
</Container>
|
</Container>
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -11,26 +11,67 @@
|
||||||
import { AppNav, Footer } from "./components/AppNav.tsx";
|
import { AppNav, Footer } from "./components/AppNav.tsx";
|
||||||
import { Container, Row, Col, Card } from "react-bootstrap";
|
import { Container, Row, Col, Card } from "react-bootstrap";
|
||||||
import { MediaMtxPlayer } from "./external/MediaMtxPlayer.tsx";
|
import { MediaMtxPlayer } from "./external/MediaMtxPlayer.tsx";
|
||||||
import { atom, useAtomValue } from "jotai";
|
import { atom, useAtomValue, useAtom } from "jotai";
|
||||||
import { createQueryAtom } from "./utils/query.ts";
|
import { createQueryAtom } from "./utils/query.ts";
|
||||||
|
|
||||||
const tokenQueryAtom = createQueryAtom("api/mediamtx/login", { retry: true });
|
const tokenQueryAtom = createQueryAtom("api/mediamtx/login", { retry: true });
|
||||||
const tokenAtom = atom((get) => {
|
const tokenAtom = atom((get) => {
|
||||||
const response = get(tokenQueryAtom);
|
const response = get(tokenQueryAtom);
|
||||||
if (response.isPending || response.isError) {
|
if (response.isPending || response.isError) {
|
||||||
console.log(response);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return response.data.token;
|
return response.data.token;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const streamsQueryAtom = createQueryAtom("api/available_streams");
|
||||||
|
const streamsAtom = atom((get) => {
|
||||||
|
const response = get(streamsQueryAtom);
|
||||||
|
if (response.isPending || response.isError) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return response.data.streams;
|
||||||
|
});
|
||||||
|
const videoDisplayPortAtom = atom((get) => {
|
||||||
|
const response = get(streamsQueryAtom);
|
||||||
|
if (response.isPending || response.isError) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return response.data.port;
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedStreamAtom = atom("image");
|
||||||
|
const imageStreamURIAtom = atom((get) => {
|
||||||
|
const port = get(videoDisplayPortAtom);
|
||||||
|
const selectedStream = get(selectedStreamAtom);
|
||||||
|
if (port === null || selectedStream === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const imageStreamURI =
|
||||||
|
"http://" +
|
||||||
|
window.location.hostname +
|
||||||
|
":" +
|
||||||
|
port +
|
||||||
|
"/" +
|
||||||
|
selectedStream +
|
||||||
|
"/whep";
|
||||||
|
return imageStreamURI;
|
||||||
|
});
|
||||||
|
|
||||||
export function Video() {
|
export function Video() {
|
||||||
const streamName = "image";
|
const streamName = "image";
|
||||||
const imageStreamURI =
|
|
||||||
"http://" + window.location.hostname + ":8889/" + streamName + "/whep";
|
const imageStreamURI = useAtomValue(imageStreamURIAtom);
|
||||||
|
|
||||||
const token = useAtomValue(tokenAtom);
|
const token = useAtomValue(tokenAtom);
|
||||||
|
|
||||||
|
const availableStreams = useAtomValue(streamsAtom);
|
||||||
|
|
||||||
|
const [selectedStream, setSelectedStream] = useAtom(selectedStreamAtom);
|
||||||
|
|
||||||
|
const handleSelect = (event) => {
|
||||||
|
setSelectedStream(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<AppNav />
|
<AppNav />
|
||||||
|
|
@ -40,7 +81,21 @@ export function Video() {
|
||||||
<Col lg={8}>
|
<Col lg={8}>
|
||||||
<MediaMtxPlayer url={imageStreamURI} token={token} />
|
<MediaMtxPlayer url={imageStreamURI} token={token} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col lg={4}>Showing stream: "{streamName}".</Col>
|
<Col lg={4}>
|
||||||
|
<p>Available Streams: </p>
|
||||||
|
{availableStreams.map((stream, index) => (
|
||||||
|
<div style={{ display: "flex", gap: "8px" }}>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="selected_stream"
|
||||||
|
value={stream}
|
||||||
|
checked={selectedStream === stream}
|
||||||
|
onChange={handleSelect}
|
||||||
|
/>
|
||||||
|
{stream}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,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
|
am_i_up
|
||||||
</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">
|
||||||
|
|
|
||||||
|
|
@ -71,11 +71,15 @@ function LevelIndicator(props: Any) {
|
||||||
return <CircleFill color="grey" />;
|
return <CircleFill color="grey" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function MessageText(props: Any) {
|
function TitleText(props: Any) {
|
||||||
if (props.message === "") {
|
if (props.message === "") {
|
||||||
return <div></div>;
|
return <p>{props.name}</p>;
|
||||||
}
|
}
|
||||||
return <div>Message: {props.message}</div>;
|
return (
|
||||||
|
<p>
|
||||||
|
{props.name}: {props.message}
|
||||||
|
</p>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ValuesTable(props: Any) {
|
function ValuesTable(props: Any) {
|
||||||
|
|
@ -103,13 +107,9 @@ function ValuesTable(props: Any) {
|
||||||
|
|
||||||
function StatusContent(props: Any) {
|
function StatusContent(props: Any) {
|
||||||
const status = props.status;
|
const status = props.status;
|
||||||
console.log(status);
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>{status.name}</p>
|
<TitleText name={status.name} message={status.message} />
|
||||||
<p>
|
|
||||||
<MessageText message={status.message} />
|
|
||||||
</p>
|
|
||||||
<p>
|
<p>
|
||||||
<ValuesTable values={status.values} />
|
<ValuesTable values={status.values} />
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue