mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2024-12-24 22:25:55 -05:00
ADD react router and reading from query params
Signed-off-by: Damian Krysta <damian@krysta.dev>
This commit is contained in:
parent
c9b1e49f3d
commit
2d517c28dc
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.DS_Store
|
||||
*.swp
|
||||
/server/target
|
||||
.idea
|
||||
|
1
ui/.gitignore
vendored
1
ui/.gitignore
vendored
@ -4,6 +4,7 @@
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
/.idea
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
25
ui/package-lock.json
generated
25
ui/package-lock.json
generated
@ -8518,6 +8518,14 @@
|
||||
"resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
|
||||
"integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
|
||||
},
|
||||
"history": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz",
|
||||
"integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.7.6"
|
||||
}
|
||||
},
|
||||
"hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||
@ -14857,6 +14865,23 @@
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
|
||||
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg=="
|
||||
},
|
||||
"react-router": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz",
|
||||
"integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==",
|
||||
"requires": {
|
||||
"history": "^5.2.0"
|
||||
}
|
||||
},
|
||||
"react-router-dom": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz",
|
||||
"integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==",
|
||||
"requires": {
|
||||
"history": "^5.2.0",
|
||||
"react-router": "6.2.1"
|
||||
}
|
||||
},
|
||||
"react-scripts": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-4.0.3.tgz",
|
||||
|
@ -6,9 +6,9 @@
|
||||
"@emotion/react": "^11.1.5",
|
||||
"@emotion/styled": "^11.1.5",
|
||||
"@fontsource/roboto": "^4.2.1",
|
||||
"@mui/material": "^5.0.1",
|
||||
"@mui/icons-material": "^5.0.1",
|
||||
"@mui/lab": "^5.0.0-alpha.48",
|
||||
"@mui/material": "^5.0.1",
|
||||
"@mui/styles": "^5.0.1",
|
||||
"@react-hook/resize-observer": "^1.2.0",
|
||||
"@types/jest": "^26.0.20",
|
||||
@ -20,6 +20,7 @@
|
||||
"gzipper": "^5.0.0",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-router-dom": "^6.2.1",
|
||||
"react-scripts": "^4.0.3",
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
|
@ -11,6 +11,7 @@ import { useSnackbars } from "./snackbars";
|
||||
import { Camera, Session } from "./types";
|
||||
import ListActivity from "./List";
|
||||
import AppBar from "@mui/material/AppBar";
|
||||
import {BrowserRouter, Routes, Route, Link} from "react-router-dom";
|
||||
import LiveActivity, { MultiviewChooser } from "./Live";
|
||||
import Drawer from "@mui/material/Drawer";
|
||||
import List from "@mui/material/List";
|
||||
@ -80,6 +81,20 @@ function App() {
|
||||
}
|
||||
};
|
||||
|
||||
function fetchedCameras(cameras: Camera[] | null) {
|
||||
if (cameras !== null && cameras.length >0) {
|
||||
return (
|
||||
<>
|
||||
<Route path="" element={ <ListActivity cameras={cameras}
|
||||
showSelectors={showListSelectors}
|
||||
timeZoneName={timeZoneName!}
|
||||
/>} />
|
||||
<Route path="live" element={<LiveActivity cameras={cameras} layoutIndex={multiviewLayoutIndex} />} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const abort = new AbortController();
|
||||
const doFetch = async (signal: AbortSignal) => {
|
||||
@ -112,7 +127,6 @@ function App() {
|
||||
};
|
||||
}, [fetchSeq]);
|
||||
let activityMenu = null;
|
||||
let activityMain = null;
|
||||
if (error === null && cameras !== null && cameras.length > 0) {
|
||||
switch (activity) {
|
||||
case "list":
|
||||
@ -126,13 +140,6 @@ function App() {
|
||||
<FilterList />
|
||||
</IconButton>
|
||||
);
|
||||
activityMain = (
|
||||
<ListActivity
|
||||
cameras={cameras}
|
||||
showSelectors={showListSelectors}
|
||||
timeZoneName={timeZoneName!}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "live":
|
||||
activityMenu = (
|
||||
@ -141,14 +148,11 @@ function App() {
|
||||
onChoice={setMultiviewLayoutIndex}
|
||||
/>
|
||||
);
|
||||
activityMain = (
|
||||
<LiveActivity cameras={cameras} layoutIndex={multiviewLayoutIndex} />
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<BrowserRouter>
|
||||
<AppBar position="static">
|
||||
<MoonfireMenu
|
||||
loginState={loginState}
|
||||
@ -174,13 +178,14 @@ function App() {
|
||||
<ListItemIcon>
|
||||
<ListIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="List view" />
|
||||
<Link to="/"><ListItemText primary="List view" /></Link>
|
||||
</ListItem>
|
||||
<ListItem button key="live" onClick={() => clickActivity("live")}>
|
||||
<ListItemIcon>
|
||||
<Videocam />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Live view (experimental)" />
|
||||
|
||||
<Link to="/live"><ListItemText primary="Live view (experimental)" /></Link>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Drawer>
|
||||
@ -206,8 +211,10 @@ function App() {
|
||||
</p>
|
||||
</Container>
|
||||
)}
|
||||
{activityMain}
|
||||
</>
|
||||
<Routes >
|
||||
{fetchedCameras(cameras)}
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import React, { useReducer } from "react";
|
||||
import { Camera } from "../types";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import {useSearchParams} from "react-router-dom";
|
||||
|
||||
export interface Layout {
|
||||
className: string;
|
||||
@ -150,6 +151,7 @@ function selectedReducer(old: SelectedCameras, op: SelectOp): SelectedCameras {
|
||||
* as possible.
|
||||
*/
|
||||
const Multiview = (props: MultiviewProps) => {
|
||||
|
||||
const [selected, updateSelected] = useReducer(
|
||||
selectedReducer,
|
||||
Array(MAX_CAMERAS).fill(null)
|
||||
@ -198,15 +200,18 @@ interface MonoviewProps {
|
||||
|
||||
/** A single pane of a Multiview, including its camera chooser. */
|
||||
const Monoview = (props: MonoviewProps) => {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const handleChange = (event: SelectChangeEvent<number | null>) => {
|
||||
const {
|
||||
target: { value },
|
||||
} = event;
|
||||
props.onSelect(typeof value === "string" ? parseInt(value) : value);
|
||||
};
|
||||
|
||||
const fromQueryOrFirst = searchParams.has('cam') ? Number.parseInt(searchParams.get('cam') as string, 10) : 0;
|
||||
const chooser = (
|
||||
<Select
|
||||
value={props.cameraIndex == null ? undefined : props.cameraIndex}
|
||||
value={props.cameraIndex == null ? fromQueryOrFirst: props.cameraIndex}
|
||||
onChange={handleChange}
|
||||
displayEmpty
|
||||
size="small"
|
||||
@ -227,7 +232,7 @@ const Monoview = (props: MonoviewProps) => {
|
||||
</Select>
|
||||
);
|
||||
return props.renderCamera(
|
||||
props.cameraIndex === null ? null : props.cameras[props.cameraIndex],
|
||||
props.cameraIndex === null ? props.cameras[fromQueryOrFirst] : props.cameras[props.cameraIndex],
|
||||
chooser
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user