forked from Github/frigate
FEAT: Ability to reorder & ability to hide Cameras in UI (#2981)
* Add options for reordering and hiding cameras selectively * Add newline at end of camera file * Make each camera for birdseye togglable as well * Update names to be less ambiguous * Update defaults * Include sidebar change * Remove birdseye toggle (will be added in separate PR) * Remove birdseye toggle (will be added in separate PR) * Remove birdseye toggle (will be added in separate PR) * Update sidebar to only sort cameras once * Simplify sorting logic
This commit is contained in:
@@ -20,6 +20,7 @@ export const handlers = [
|
||||
detect: { width: 1280, height: 720 },
|
||||
snapshots: {},
|
||||
live: { height: 720 },
|
||||
ui: { dashboard: true, order: 0 },
|
||||
},
|
||||
side: {
|
||||
name: 'side',
|
||||
@@ -28,6 +29,7 @@ export const handlers = [
|
||||
detect: { width: 1280, height: 720 },
|
||||
snapshots: {},
|
||||
live: { height: 720 },
|
||||
ui: { dashboard: true, order: 1 },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -3,15 +3,27 @@ import LinkedLogo from './components/LinkedLogo';
|
||||
import { Match } from 'preact-router/match';
|
||||
import { memo } from 'preact/compat';
|
||||
import { ENV } from './env';
|
||||
import { useMemo } from 'preact/hooks'
|
||||
import useSWR from 'swr';
|
||||
import NavigationDrawer, { Destination, Separator } from './components/NavigationDrawer';
|
||||
|
||||
export default function Sidebar() {
|
||||
const { data: config } = useSWR('config');
|
||||
|
||||
const sortedCameras = useMemo(() => {
|
||||
if (!config) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return Object.entries(config.cameras)
|
||||
.filter(([_, conf]) => conf.ui.dashboard)
|
||||
.sort(([_, aConf], [__, bConf]) => aConf.ui.order - bConf.ui.order);
|
||||
}, [config]);
|
||||
|
||||
if (!config) {
|
||||
return null;
|
||||
}
|
||||
const { cameras, birdseye } = config;
|
||||
const { birdseye } = config;
|
||||
|
||||
return (
|
||||
<NavigationDrawer header={<Header />}>
|
||||
@@ -19,31 +31,14 @@ export default function Sidebar() {
|
||||
<Match path="/cameras/:camera/:other?">
|
||||
{({ matches }) =>
|
||||
matches ? (
|
||||
<Fragment>
|
||||
<Separator />
|
||||
{Object.keys(cameras).map((camera) => (
|
||||
<Destination key={camera} href={`/cameras/${camera}`} text={camera} />
|
||||
))}
|
||||
<Separator />
|
||||
</Fragment>
|
||||
<CameraSection sortedCameras={sortedCameras} />
|
||||
) : null
|
||||
}
|
||||
</Match>
|
||||
<Match path="/recording/:camera/:date?/:hour?/:seconds?">
|
||||
{({ matches }) =>
|
||||
matches ? (
|
||||
<Fragment>
|
||||
<Separator />
|
||||
{Object.keys(cameras).map((camera) => (
|
||||
<Destination
|
||||
key={camera}
|
||||
path={`/recording/${camera}/:date?/:hour?/:seconds?`}
|
||||
href={`/recording/${camera}`}
|
||||
text={camera}
|
||||
/>
|
||||
))}
|
||||
<Separator />
|
||||
</Fragment>
|
||||
<RecordingSection sortedCameras={sortedCameras} />
|
||||
) : null
|
||||
}
|
||||
</Match>
|
||||
@@ -64,10 +59,43 @@ export default function Sidebar() {
|
||||
);
|
||||
}
|
||||
|
||||
function CameraSection({ sortedCameras }) {
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Separator />
|
||||
{sortedCameras.map(([camera]) => (
|
||||
<Destination key={camera} href={`/cameras/${camera}`} text={camera} />
|
||||
))}
|
||||
<Separator />
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
function RecordingSection({ sortedCameras }) {
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Separator />
|
||||
{sortedCameras.map(([camera, _]) => {
|
||||
return (
|
||||
<Destination
|
||||
key={camera}
|
||||
path={`/recording/${camera}/:date?/:hour?/:seconds?`}
|
||||
href={`/recording/${camera}`}
|
||||
text={camera}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<Separator />
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
const Header = memo(() => {
|
||||
return (
|
||||
<div className="text-gray-500">
|
||||
<LinkedLogo />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { h } from 'preact';
|
||||
import { h, Fragment } from 'preact';
|
||||
import ActivityIndicator from '../components/ActivityIndicator';
|
||||
import Card from '../components/Card';
|
||||
import CameraImage from '../components/CameraImage';
|
||||
@@ -16,10 +16,25 @@ export default function Cameras() {
|
||||
<ActivityIndicator />
|
||||
) : (
|
||||
<div className="grid grid-cols-1 3xl:grid-cols-3 md:grid-cols-2 gap-4 p-2 px-4">
|
||||
{Object.entries(config.cameras).map(([camera, conf]) => (
|
||||
<SortedCameras unsortedCameras={config.cameras} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SortedCameras({ unsortedCameras }) {
|
||||
|
||||
const sortedCameras = useMemo(() =>
|
||||
Object.entries(unsortedCameras)
|
||||
.filter(([_, conf]) => conf.ui.dashboard)
|
||||
.sort(([_, aConf], [__, bConf]) => aConf.ui.order - bConf.ui.order),
|
||||
[unsortedCameras]);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{sortedCameras.map(([camera, conf]) => (
|
||||
<Camera key={camera} name={camera} conf={conf} />
|
||||
))}
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user