add profile section dropdown and wire into camera settings pages

This commit is contained in:
Josh Hawkins
2026-03-09 15:20:50 -05:00
parent d5dc77daa4
commit 94dbabd0ef
3 changed files with 365 additions and 1 deletions
+54 -1
View File
@@ -1,16 +1,22 @@
import { useCallback, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import useSWR from "swr";
import type { SectionConfig } from "@/components/config-form/sections";
import { ConfigSectionTemplate } from "@/components/config-form/sections";
import type { PolygonType } from "@/types/canvas";
import type { FrigateConfig } from "@/types/frigateConfig";
import { Badge } from "@/components/ui/badge";
import type { ConfigSectionData } from "@/types/configForm";
import type { ProfileState } from "@/types/profile";
import { getSectionConfig } from "@/utils/configUtil";
import {
getSectionConfig,
PROFILE_ELIGIBLE_SECTIONS,
} from "@/utils/configUtil";
import { useDocDomain } from "@/hooks/use-doc-domain";
import { Link } from "react-router-dom";
import { LuExternalLink } from "react-icons/lu";
import Heading from "@/components/ui/heading";
import { ProfileSectionDropdown } from "@/components/settings/ProfileSectionDropdown";
export type SettingsPageProps = {
selectedCamera?: string;
@@ -58,6 +64,7 @@ export function SingleSectionPage({
onSectionStatusChange,
pendingDataBySection,
onPendingDataChange,
profileState,
}: SingleSectionPageProps) {
const sectionNamespace =
level === "camera" ? "config/cameras" : "config/global";
@@ -67,6 +74,7 @@ export function SingleSectionPage({
"common",
]);
const { getLocaleDocUrl } = useDocDomain();
const { data: config } = useSWR<FrigateConfig>("config");
const [sectionStatus, setSectionStatus] = useState<SectionStatus>({
hasChanges: false,
isOverridden: false,
@@ -80,6 +88,20 @@ export function SingleSectionPage({
? getLocaleDocUrl(resolvedSectionConfig.sectionDocs)
: undefined;
// Profile support: determine if this section supports profiles
const isProfileEligible =
level === "camera" &&
selectedCamera &&
profileState &&
PROFILE_ELIGIBLE_SECTIONS.has(sectionKey);
const profileKey = selectedCamera
? `${selectedCamera}::${sectionKey}`
: undefined;
const currentEditingProfile = profileKey
? (profileState?.editingProfile[profileKey] ?? null)
: null;
const handleSectionStatusChange = useCallback(
(status: SectionStatus) => {
setSectionStatus(status);
@@ -126,6 +148,36 @@ export function SingleSectionPage({
</div>
<div className="flex flex-col items-end gap-2 md:flex-row md:items-center">
<div className="flex flex-wrap items-center justify-end gap-2">
{isProfileEligible && selectedCamera && profileState && (
<ProfileSectionDropdown
cameraName={selectedCamera}
sectionKey={sectionKey}
allProfileNames={profileState.allProfileNames}
editingProfile={currentEditingProfile}
hasProfileData={(profile) => {
const profileData =
config?.cameras?.[selectedCamera]?.profiles?.[profile];
return !!profileData?.[
sectionKey as keyof typeof profileData
];
}}
onSelectProfile={(profile) =>
profileState.onSelectProfile(
selectedCamera,
sectionKey,
profile,
)
}
onAddProfile={profileState.onAddProfile}
onDeleteProfileSection={(profile) =>
profileState.onDeleteProfileSection(
selectedCamera,
sectionKey,
profile,
)
}
/>
)}
{level === "camera" &&
showOverrideIndicator &&
sectionStatus.isOverridden && (
@@ -162,6 +214,7 @@ export function SingleSectionPage({
onPendingDataChange={onPendingDataChange}
requiresRestart={requiresRestart}
onStatusChange={handleSectionStatusChange}
profileName={currentEditingProfile ?? undefined}
/>
</div>
);