manage persistent group streaming settings

This commit is contained in:
Josh Hawkins 2024-11-13 07:40:18 -06:00
parent 685ef20fd5
commit a6cf755529
5 changed files with 92 additions and 14 deletions

View File

@ -1,7 +1,8 @@
import {
AllGroupsStreamingSettings,
CameraGroupConfig,
FrigateConfig,
GroupStreamingSettingsType,
GroupStreamingSettings,
} from "@/types/frigateConfig";
import { isDesktop, isMobile } from "react-device-detect";
import useSWR from "swr";
@ -75,8 +76,14 @@ import { CameraStreamingDialog } from "../settings/CameraStreamingDialog";
type CameraGroupSelectorProps = {
className?: string;
setAllGroupsStreamingSettings: React.Dispatch<
React.SetStateAction<AllGroupsStreamingSettings>
>;
};
export function CameraGroupSelector({ className }: CameraGroupSelectorProps) {
export function CameraGroupSelector({
className,
setAllGroupsStreamingSettings,
}: CameraGroupSelectorProps) {
const { data: config } = useSWR<FrigateConfig>("config");
// tooltip
@ -130,6 +137,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) {
activeGroup={group}
setGroup={setGroup}
deleteGroup={deleteGroup}
setAllGroupsStreamingSettings={setAllGroupsStreamingSettings}
/>
<Scroller className={`${isMobile ? "whitespace-nowrap" : ""}`}>
<div
@ -219,6 +227,9 @@ type NewGroupDialogProps = {
activeGroup?: string;
setGroup: (value: string | undefined, replace?: boolean | undefined) => void;
deleteGroup: () => void;
setAllGroupsStreamingSettings: React.Dispatch<
React.SetStateAction<AllGroupsStreamingSettings>
>;
};
function NewGroupDialog({
open,
@ -227,6 +238,7 @@ function NewGroupDialog({
activeGroup,
setGroup,
deleteGroup,
setAllGroupsStreamingSettings,
}: NewGroupDialogProps) {
const { mutate: updateConfig } = useSWR<FrigateConfig>("config");
@ -409,6 +421,7 @@ function NewGroupDialog({
setIsLoading={setIsLoading}
onSave={onSave}
onCancel={onCancel}
setAllGroupsStreamingSettings={setAllGroupsStreamingSettings}
/>
</>
)}
@ -423,12 +436,16 @@ type EditGroupDialogProps = {
setOpen: (open: boolean) => void;
currentGroups: [string, CameraGroupConfig][];
activeGroup?: string;
setAllGroupsStreamingSettings: React.Dispatch<
React.SetStateAction<AllGroupsStreamingSettings>
>;
};
export function EditGroupDialog({
open,
setOpen,
currentGroups,
activeGroup,
setAllGroupsStreamingSettings,
}: EditGroupDialogProps) {
const Overlay = isDesktop ? Dialog : MobilePage;
const Content = isDesktop ? DialogContent : MobilePageContent;
@ -480,6 +497,7 @@ export function EditGroupDialog({
setIsLoading={setIsLoading}
onSave={() => setOpen(false)}
onCancel={() => setOpen(false)}
setAllGroupsStreamingSettings={setAllGroupsStreamingSettings}
/>
</div>
</Content>
@ -600,6 +618,9 @@ type CameraGroupEditProps = {
setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
onSave?: () => void;
onCancel?: () => void;
setAllGroupsStreamingSettings: React.Dispatch<
React.SetStateAction<AllGroupsStreamingSettings>
>;
};
export function CameraGroupEdit({
@ -609,17 +630,16 @@ export function CameraGroupEdit({
setIsLoading,
onSave,
onCancel,
setAllGroupsStreamingSettings,
}: CameraGroupEditProps) {
const { data: config, mutate: updateConfig } =
useSWR<FrigateConfig>("config");
const [groupStreamingSettings, setGroupStreamingSettings] =
useState<GroupStreamingSettingsType>({});
useState<GroupStreamingSettings>({});
const [persistedGroupStreamingSettings, setPersistedGroupStreamingSettings] =
usePersistence<{ [groupName: string]: GroupStreamingSettingsType }>(
"streaming-settings",
);
usePersistence<AllGroupsStreamingSettings>("streaming-settings");
const birdseyeConfig = useMemo(() => config?.birdseye, [config]);
@ -671,9 +691,7 @@ export function CameraGroupEdit({
setIsLoading(true);
// update streaming settings
const updatedSettings: {
[groupName: string]: GroupStreamingSettingsType;
} = {
const updatedSettings: AllGroupsStreamingSettings = {
...Object.fromEntries(
Object.entries(persistedGroupStreamingSettings || {}).filter(
([key]) => key !== editingGroup?.[0],
@ -715,6 +733,7 @@ export function CameraGroupEdit({
onSave();
}
await setPersistedGroupStreamingSettings(updatedSettings);
setAllGroupsStreamingSettings(updatedSettings);
} else {
toast.error(`Failed to save config changes: ${res.statusText}`, {
position: "top-center",
@ -740,6 +759,7 @@ export function CameraGroupEdit({
groupStreamingSettings,
setPersistedGroupStreamingSettings,
persistedGroupStreamingSettings,
setAllGroupsStreamingSettings,
],
);

View File

@ -6,7 +6,9 @@ import GeneralSettings from "../menu/GeneralSettings";
import AccountSettings from "../menu/AccountSettings";
import useNavigation from "@/hooks/use-navigation";
import { baseUrl } from "@/api/baseUrl";
import { useMemo } from "react";
import { useEffect, useMemo, useState } from "react";
import { usePersistence } from "@/hooks/use-persistence";
import { AllGroupsStreamingSettings } from "@/types/frigateConfig";
function Sidebar() {
const basePath = useMemo(() => new URL(baseUrl).pathname, []);
@ -16,6 +18,18 @@ function Sidebar() {
const navbarLinks = useNavigation();
const [, setAllGroupsStreamingSettings] =
useState<AllGroupsStreamingSettings>({});
const [persistedStreamingSettings, _, isStreamingSettingsLoaded] =
usePersistence<AllGroupsStreamingSettings>("streaming-settings");
useEffect(() => {
if (isStreamingSettingsLoaded) {
setAllGroupsStreamingSettings(persistedStreamingSettings ?? {});
}
}, [isStreamingSettingsLoaded, persistedStreamingSettings]);
return (
<aside className="scrollbar-container scrollbar-hidden absolute inset-y-0 left-0 z-10 flex w-[52px] flex-col justify-between overflow-y-auto border-r border-secondary-highlight bg-background_alt py-4">
<span tabIndex={0} className="sr-only" />
@ -34,7 +48,12 @@ function Sidebar() {
item={item}
Icon={item.icon}
/>
{showCameraGroups && <CameraGroupSelector className="mb-4" />}
{showCameraGroups && (
<CameraGroupSelector
setAllGroupsStreamingSettings={setAllGroupsStreamingSettings}
className="mb-4"
/>
)}
</div>
);
})}

View File

@ -235,10 +235,14 @@ export type CameraStreamingSettings = {
compatibilityMode: boolean;
};
export type GroupStreamingSettingsType = {
export type GroupStreamingSettings = {
[cameraName: string]: CameraStreamingSettings;
};
export type AllGroupsStreamingSettings = {
[groupName: string]: GroupStreamingSettings;
};
export interface FrigateConfig {
audio: {
enabled: boolean;

View File

@ -1,5 +1,6 @@
import { usePersistence } from "@/hooks/use-persistence";
import {
AllGroupsStreamingSettings,
BirdseyeConfig,
CameraConfig,
FrigateConfig,
@ -56,6 +57,9 @@ type DraggableGridLayoutProps = {
setIsEditMode: React.Dispatch<React.SetStateAction<boolean>>;
fullscreen: boolean;
toggleFullscreen: () => void;
setAllGroupsStreamingSettings: React.Dispatch<
React.SetStateAction<AllGroupsStreamingSettings>
>;
};
export default function DraggableGridLayout({
cameras,
@ -70,6 +74,7 @@ export default function DraggableGridLayout({
setIsEditMode,
fullscreen,
toggleFullscreen,
setAllGroupsStreamingSettings,
}: DraggableGridLayoutProps) {
const { data: config } = useSWR<FrigateConfig>("config");
const birdseyeConfig = useMemo(() => config?.birdseye, [config]);
@ -372,6 +377,7 @@ export default function DraggableGridLayout({
setOpen={setEditGroup}
currentGroups={groups}
activeGroup={group}
setAllGroupsStreamingSettings={setAllGroupsStreamingSettings}
/>
<ResponsiveGridLayout
className="grid-layout"

View File

@ -14,7 +14,11 @@ import {
TooltipTrigger,
} from "@/components/ui/tooltip";
import { usePersistence } from "@/hooks/use-persistence";
import { CameraConfig, FrigateConfig } from "@/types/frigateConfig";
import {
AllGroupsStreamingSettings,
CameraConfig,
FrigateConfig,
} from "@/types/frigateConfig";
import { ReviewSegment } from "@/types/review";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
@ -187,6 +191,28 @@ export default function LiveDashboardView({
const { preferredLiveModes, setPreferredLiveModes, resetPreferredLiveMode } =
useCameraLiveMode(cameras, windowVisible);
const [allGroupsStreamingSettings, setAllGroupsStreamingSettings] =
useState<AllGroupsStreamingSettings>({});
const [persistedStreamingSettings, _, isStreamingSettingsLoaded] =
usePersistence<AllGroupsStreamingSettings>("streaming-settings");
const currentGroupStreamingSettings = useMemo(() => {
if (cameraGroup && cameraGroup != "default" && allGroupsStreamingSettings) {
return allGroupsStreamingSettings[cameraGroup];
}
}, [allGroupsStreamingSettings, cameraGroup]);
useEffect(() => {
if (isStreamingSettingsLoaded) {
setAllGroupsStreamingSettings(persistedStreamingSettings ?? {});
}
}, [isStreamingSettingsLoaded, persistedStreamingSettings]);
useEffect(() => {
// console.log("group settings", cameraGroup, currentGroupStreamingSettings);
}, [currentGroupStreamingSettings, cameraGroup]);
const cameraRef = useCallback(
(node: HTMLElement | null) => {
if (!visibleCameraObserver.current) {
@ -230,7 +256,9 @@ export default function LiveDashboardView({
<div className="relative flex h-11 items-center justify-between">
<Logo className="absolute inset-x-1/2 h-8 -translate-x-1/2" />
<div className="max-w-[45%]">
<CameraGroupSelector />
<CameraGroupSelector
setAllGroupsStreamingSettings={setAllGroupsStreamingSettings}
/>
</div>
{(!cameraGroup || cameraGroup == "default" || isMobileOnly) && (
<div className="flex items-center gap-1">
@ -408,6 +436,7 @@ export default function LiveDashboardView({
setIsEditMode={setIsEditMode}
fullscreen={fullscreen}
toggleFullscreen={toggleFullscreen}
setAllGroupsStreamingSettings={setAllGroupsStreamingSettings}
/>
)}
</div>