diff --git a/web/src/AppBar.jsx b/web/src/AppBar.jsx
index f71f4124f..9f4a750ee 100644
--- a/web/src/AppBar.jsx
+++ b/web/src/AppBar.jsx
@@ -8,16 +8,16 @@ import DarkModeIcon from './icons/DarkMode';
import SettingsIcon from './icons/Settings';
import FrigateRestartIcon from './icons/FrigateRestart';
import Prompt from './components/Prompt';
-import { useDarkMode, useViewMode } from './context';
+import { useDarkMode, useUserView } from './context';
import { useCallback, useRef, useState } from 'preact/hooks';
import { useRestart } from './api/ws';
-import { ViewModeTypes } from './components/ViewOptionEnum'
+import { UserViewTypes } from './context/UserViewTypes'
export default function AppBar() {
const [showMoreMenu, setShowMoreMenu] = useState(false);
const [showDialog, setShowDialog] = useState(false);
const [showDialogWait, setShowDialogWait] = useState(false);
- const { currentViewMode, setViewMode } = useViewMode();
+ const { currentUserView, setUserView } = useUserView();
const { setDarkMode } = useDarkMode();
const { send: sendRestart } = useRestart();
@@ -29,12 +29,12 @@ export default function AppBar() {
[setDarkMode, setShowMoreMenu]
);
- const handleSetViewMode = useCallback(
+ const handleSetUserView = useCallback(
(value) => {
- setViewMode(value);
+ setUserView(value);
setShowMoreMenu(false);
},
- [setViewMode, setShowMoreMenu]
+ [setUserView, setShowMoreMenu]
);
const moreRef = useRef(null);
@@ -75,10 +75,10 @@ export default function AppBar() {
diff --git a/web/src/Sidebar.jsx b/web/src/Sidebar.jsx
index c19c9a2f0..38ea4ccc8 100644
--- a/web/src/Sidebar.jsx
+++ b/web/src/Sidebar.jsx
@@ -4,7 +4,7 @@ import { Match } from 'preact-router/match';
import { memo } from 'preact/compat';
import { ENV } from './env';
import { useMemo } from 'preact/hooks'
-import ViewOption from './components/ViewOption'
+import UserViewer from './components/UserViewer'
import useSWR from 'swr';
import NavigationDrawer, { Destination, Separator } from './components/NavigationDrawer';
@@ -47,17 +47,17 @@ export default function Sidebar() {
-
+
-
-
+
+
-
-
+
+
-
+
{ENV !== 'production' ? (
diff --git a/web/src/app.tsx b/web/src/app.tsx
index 95f530982..fd110c74c 100644
--- a/web/src/app.tsx
+++ b/web/src/app.tsx
@@ -6,7 +6,7 @@ import AppBar from './AppBar';
import Cameras from './routes/Cameras';
import { Router } from 'preact-router';
import Sidebar from './Sidebar';
-import { DarkModeProvider, DrawerProvider, ViewModeProvider } from './context';
+import { DarkModeProvider, DrawerProvider, UserViewProvider } from './context';
import useSWR from 'swr';
export default function App() {
@@ -16,7 +16,7 @@ export default function App() {
return (
-
+
{!config ? (
@@ -48,7 +48,7 @@ export default function App() {
)}
-
+
);
diff --git a/web/src/components/UserViewer.jsx b/web/src/components/UserViewer.jsx
new file mode 100644
index 000000000..98fb55da1
--- /dev/null
+++ b/web/src/components/UserViewer.jsx
@@ -0,0 +1,12 @@
+import { h } from 'preact';
+import { useUserView } from '../context';
+import { UserViewTypes } from '../context/UserViewTypes';
+
+export default function UserViewer({children, requiredmode }) {
+ const { currentUserView } = useUserView();
+
+ return currentUserView >= UserViewTypes[requiredmode] ? (
+ <>{children}>
+
+ ) : null;
+}
\ No newline at end of file
diff --git a/web/src/components/ViewOption.jsx b/web/src/components/ViewOption.jsx
deleted file mode 100644
index 3fb3f276a..000000000
--- a/web/src/components/ViewOption.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { h } from 'preact';
-import { useViewMode } from '../context';
-import { ViewModeTypes } from './ViewOptionEnum';
-
-export default function ViewOption({children, requiredmode }) {
- const { currentViewMode } = useViewMode();
-
- return currentViewMode >= ViewModeTypes[requiredmode] ? (
- <>{children}>
-
- ) : null;
-}
\ No newline at end of file
diff --git a/web/src/components/__tests__/ViewOption.test.jsx b/web/src/components/__tests__/UserViewer.test.jsx
similarity index 60%
rename from web/src/components/__tests__/ViewOption.test.jsx
rename to web/src/components/__tests__/UserViewer.test.jsx
index 5592aff41..2ec888d7e 100644
--- a/web/src/components/__tests__/ViewOption.test.jsx
+++ b/web/src/components/__tests__/UserViewer.test.jsx
@@ -1,27 +1,27 @@
import { h } from 'preact';
import { render, screen, waitFor } from '@testing-library/preact';
import { set as setData } from 'idb-keyval';
-import ViewOption from '../ViewOption';
-import { ViewModeProvider } from '../../context';
-import { ViewModeTypes } from '../ViewOptionEnum';
+import UserViewer from '../UserViewer';
+import { UserViewProvider } from '../../context';
+import { UserViewTypes } from '../../context/UserViewTypes';
import * as WS from '../../api/ws';
-describe('ViewOption', () => {
+describe('UserViewer', () => {
beforeEach(() => {
vi.spyOn(WS, 'WsProvider').mockImplementation(({ children }) => children);
});
test('make sure children are visible with same modes', async () => {
- const maxViewMode = (Object.keys(ViewModeTypes).filter(isNaN).length-1);
- const maxViewModeHR = ViewModeTypes[maxViewMode];
+ const maxViewMode = (Object.keys(UserViewTypes).filter(isNaN).length-1);
+ const maxViewModeHR = UserViewTypes[maxViewMode];
setData('view-mode', maxViewMode);
render(
-
-
+
+
stuff
-
-
+
+
);
const el = await screen.findByTestId('children');
@@ -29,16 +29,16 @@ describe('ViewOption', () => {
});
test('make sure children are visible with max viewmode, and a small requiredmode', async () => {
- const maxViewMode = (Object.keys(ViewModeTypes).filter(isNaN).length-1);
- const lowViewModeHR = ViewModeTypes[1];
+ const maxViewMode = (Object.keys(UserViewTypes).filter(isNaN).length-1);
+ const lowViewModeHR = UserViewTypes[1];
setData('view-mode', maxViewMode);
render(
-
-
+
+
stuff
-
-
+
+
);
const el = await screen.findByTestId('children');
@@ -46,17 +46,17 @@ describe('ViewOption', () => {
});
test('make sure children are hidden, due to failed requiredmode', async () => {
- const maxViewMode = (Object.keys(ViewModeTypes).filter(isNaN).length-1);
- const maxViewModeHR = ViewModeTypes[maxViewMode];
+ const maxViewMode = (Object.keys(UserViewTypes).filter(isNaN).length-1);
+ const maxViewModeHR = UserViewTypes[maxViewMode];
setData('view-mode', '0');
render(
-
-
+
+
stuff
-
+
bugfix
-
+
);
//without this, the test will always pass, even if setData('view-mode', '2') ... really strange behavior
diff --git a/web/src/components/ViewOptionEnum.tsx b/web/src/context/UserViewTypes.tsx
similarity index 56%
rename from web/src/components/ViewOptionEnum.tsx
rename to web/src/context/UserViewTypes.tsx
index 5cb9c7a54..1fa51702f 100644
--- a/web/src/components/ViewOptionEnum.tsx
+++ b/web/src/context/UserViewTypes.tsx
@@ -1,5 +1,5 @@
-export enum ViewModeTypes {
+export enum UserViewTypes {
"user",
"advanced",
"admin",
- }
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/web/src/context/__tests__/index.test.jsx b/web/src/context/__tests__/index.test.jsx
index 3c13c2db5..df4a8dbde 100644
--- a/web/src/context/__tests__/index.test.jsx
+++ b/web/src/context/__tests__/index.test.jsx
@@ -1,7 +1,7 @@
import { h } from 'preact';
import { set as setData, get as getData } from 'idb-keyval';
-import { DarkModeProvider, useDarkMode, usePersistence, ViewModeProvider, useViewMode } from '..';
-import { ViewModeTypes } from '../../components/ViewOptionEnum'
+import { DarkModeProvider, useDarkMode, usePersistence, UserViewProvider, useUserView } from '..';
+import { UserViewTypes } from '../../context/UserViewTypes'
import { fireEvent, render, screen } from 'testing-library';
import { useCallback } from 'preact/hooks';
import * as WS from '../../api/ws';
@@ -197,9 +197,9 @@ describe('usePersistence', () => {
});
});
-function ViewModeChecker() {
- const { currentViewMode } = useViewMode();
- return {currentViewMode}
;
+function UserViewChecker() {
+ const { currentUserView } = useUserView();
+ return {currentUserView}
;
}
describe('ViewMode', () => {
@@ -211,24 +211,24 @@ describe('ViewMode', () => {
setData('view-mode', null);
render(
-
-
-
+
+
+
);
- const maxViewMode = (Object.keys(ViewModeTypes).filter(isNaN).length-1);
+ const maxViewMode = (Object.keys(UserViewTypes).filter(isNaN).length-1);
const el = await screen.findByTestId(maxViewMode);
expect(el).toBeInTheDocument();
});
- Object.keys(ViewModeTypes).filter((v) => !isNaN(Number(v))).map(key =>
- test(`uses a viewmode option that is stored in idb - ${ViewModeTypes[key]}`, async () => {
+ Object.keys(UserViewTypes).filter((v) => !isNaN(Number(v))).map(key =>
+ test(`uses a viewmode option that is stored in idb - ${UserViewTypes[key]}`, async () => {
setData('view-mode', key);
render(
-
-
-
+
+
+
);
const el = await screen.findByTestId(key);
@@ -236,26 +236,26 @@ describe('ViewMode', () => {
})
)
- test('update viewmode live, using setViewMode from context and verify idb save', async () => {
+ test('update viewmode live, using setUserView from context and verify idb save', async () => {
setData('view-mode', null);
function Updater() {
- const { setViewMode } = useViewMode();
+ const { setUserView } = useUserView();
const handleClick = useCallback((value) => {
- setViewMode(value.button.toString());
- }, [setViewMode]);
+ setUserView(value.button.toString());
+ }, [setUserView]);
return click me
;
}
render(
-
-
+
+
-
+
);
const button = await screen.findByText('click me');
- const maxViewMode = (Object.keys(ViewModeTypes).filter(isNaN).length-1);
+ const maxViewMode = (Object.keys(UserViewTypes).filter(isNaN).length-1);
fireEvent.click(button, {button: '0'});
const minmode = await screen.findByTestId('0');
diff --git a/web/src/context/index.jsx b/web/src/context/index.jsx
index 18fbf8d1d..46b6cec09 100644
--- a/web/src/context/index.jsx
+++ b/web/src/context/index.jsx
@@ -1,19 +1,19 @@
import { h, createContext } from 'preact';
import { get as getData, set as setData } from 'idb-keyval';
import { useCallback, useContext, useEffect, useLayoutEffect, useState } from 'preact/hooks';
-import { ViewModeTypes } from '../components/ViewOptionEnum';
+import { UserViewTypes } from './UserViewTypes';
-const ViewMode = createContext("");
+const UserView = createContext("");
-export function ViewModeProvider({ children, config }) {
- const [currentViewMode, setCurrentViewMode] = useState(null);
+export function UserViewProvider({ children, config }) {
+ const [currentUserView, setCurrentUserView] = useState(null);
- const setViewMode = useCallback(
+ const setUserView = useCallback(
(value) => {
setData('view-mode', value);
- setCurrentViewMode(value);
+ setCurrentUserView(value);
},
- [setCurrentViewMode]
+ [setCurrentUserView]
);
useEffect(() => {
@@ -21,25 +21,25 @@ export function ViewModeProvider({ children, config }) {
let viewmode = await getData('view-mode');
if(viewmode == null) {
- const maxViewMode = (Object.keys(ViewModeTypes).filter(isNaN).length-1).toString();
- const configValue = config ? ViewModeTypes[config.ui.viewmode].toString() : maxViewMode;
+ const maxViewMode = (Object.keys(UserViewTypes).filter(isNaN).length-1).toString();
+ const configValue = config ? UserViewTypes[config.ui.viewmode].toString() : maxViewMode;
viewmode = configValue;
}
- setViewMode(viewmode);
+ setUserView(viewmode);
}
load();
- }, [config, setViewMode]);
+ }, [config, setUserView]);
- return !currentViewMode ? null : (
- {children}
+ return !currentUserView ? null : (
+ {children}
);
}
-export function useViewMode() {
- return useContext(ViewMode);
+export function useUserView() {
+ return useContext(UserView);
}
const DarkMode = createContext(null);
diff --git a/web/src/routes/Camera.jsx b/web/src/routes/Camera.jsx
index bb580dde6..a02f3c812 100644
--- a/web/src/routes/Camera.jsx
+++ b/web/src/routes/Camera.jsx
@@ -17,7 +17,7 @@ import WebRtcPlayer from '../components/WebRtcPlayer';
import '../components/MsePlayer';
import CameraControlPanel from '../components/CameraControlPanel';
import { baseUrl } from '../api/baseUrl';
-import ViewOption from '../components/ViewOption'
+import UserViewer from '../components/UserViewer'
const emptyObject = Object.freeze({});
@@ -110,9 +110,9 @@ export default function Camera({ camera }) {
label="Regions"
labelPosition="after"
/>
-
+
Mask & Zone creator
-
+
) : null;
diff --git a/web/src/routes/Cameras.jsx b/web/src/routes/Cameras.jsx
index cc3aa658c..980e4402b 100644
--- a/web/src/routes/Cameras.jsx
+++ b/web/src/routes/Cameras.jsx
@@ -8,8 +8,8 @@ import MotionIcon from '../icons/Motion';
import SnapshotIcon from '../icons/Snapshot';
import { useAudioState, useDetectState, useRecordingsState, useSnapshotsState } from '../api/ws';
import { useMemo } from 'preact/hooks';
-import { useViewMode } from '../context'
-import { ViewModeTypes } from '../components/ViewOptionEnum';
+import { useUserView } from '../context'
+import { UserViewTypes } from '../context/UserViewTypes';
import useSWR from 'swr';
export default function Cameras() {
@@ -101,14 +101,14 @@ function Camera({ name, config }) {
[config, audioValue, sendAudio, detectValue, sendDetect, recordValue, sendRecordings, snapshotValue, sendSnapshots]
);
- const { currentViewMode } = useViewMode();
+ const { currentUserView } = useUserView();
return (
= ViewModeTypes["admin"] ? icons : []}
+ icons={!currentUserView || currentUserView >= UserViewTypes["admin"] ? icons : []}
media={}
/>
);
diff --git a/web/src/routes/Events.jsx b/web/src/routes/Events.jsx
index 6d882e090..6a3009066 100644
--- a/web/src/routes/Events.jsx
+++ b/web/src/routes/Events.jsx
@@ -30,7 +30,7 @@ import TimeAgo from '../components/TimeAgo';
import Timepicker from '../components/TimePicker';
import TimelineSummary from '../components/TimelineSummary';
import TimelineEventOverlay from '../components/TimelineEventOverlay';
-import ViewOption from '../components/ViewOption';
+import UserViewer from '../components/UserViewer';
const API_LIMIT = 25;
@@ -658,13 +658,13 @@ export default function Events({ path, ...props }) {
)}
-
+
onDelete(e, event.id, event.retain_indefinitely)}
/>
-
+
go2rtc {go2rtc && `${go2rtc.version} `}
-
+
dashboard
-
+
)}