diff --git a/web/public/locales/en/views/settings.json b/web/public/locales/en/views/settings.json index 92eb3b5ba..7f2ce01e0 100644 --- a/web/public/locales/en/views/settings.json +++ b/web/public/locales/en/views/settings.json @@ -1461,7 +1461,10 @@ "deleteProfileConfirm": "Delete profile \"{{profile}}\" from all cameras? This cannot be undone.", "deleteSuccess": "Profile '{{profile}}' deleted", "deleteSection": "Delete Section Overrides", - "deleteSectionConfirm": "Remove {{profile}}'s overrides for {{section}} on {{camera}}?" + "deleteSectionConfirm": "Remove {{profile}}'s overrides for {{section}} on {{camera}}?", + "enableSwitch": "Enable Profiles", + "enabledDescription": "Profiles are enabled. Navigate to a camera config section, create a new profile from the dropdown in the header, and save for changes to take effect.", + "disabledDescription": "Profiles allow you to define named sets of camera config overrides (e.g., armed, away, night) that can be activated on demand. Enable profiles to get started." }, "unsavedChanges": "You have unsaved changes", "confirmReset": "Confirm Reset", diff --git a/web/src/pages/Settings.tsx b/web/src/pages/Settings.tsx index 701009da1..e70a0b691 100644 --- a/web/src/pages/Settings.tsx +++ b/web/src/pages/Settings.tsx @@ -659,6 +659,7 @@ export default function Settings() { Record >({}); const [newProfiles, setNewProfiles] = useState([]); + const [profilesUIEnabled, setProfilesUIEnabled] = useState(false); const allProfileNames = useMemo(() => { if (!config) return []; @@ -1127,7 +1128,7 @@ export default function Settings() { const showProfileDropdown = PROFILE_DROPDOWN_PAGES.has(pageToggle) && !!selectedCamera && - allProfileNames.length > 0; + (allProfileNames.length > 0 || profilesUIEnabled); const headerHasProfileData = useCallback( (profileName: string): boolean => { @@ -1527,6 +1528,8 @@ export default function Settings() { pendingDataBySection={pendingDataBySection} onPendingDataChange={handlePendingDataChange} profileState={profileState} + profilesUIEnabled={profilesUIEnabled} + setProfilesUIEnabled={setProfilesUIEnabled} /> ); })()} diff --git a/web/src/views/settings/ProfilesView.tsx b/web/src/views/settings/ProfilesView.tsx index 60f8e1694..07883ab38 100644 --- a/web/src/views/settings/ProfilesView.tsx +++ b/web/src/views/settings/ProfilesView.tsx @@ -29,6 +29,8 @@ import { AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; +import { Switch } from "@/components/ui/switch"; +import { Label } from "@/components/ui/label"; type ProfilesApiResponse = { profiles: string[]; @@ -38,9 +40,15 @@ type ProfilesApiResponse = { type ProfilesViewProps = { setUnsavedChanges?: React.Dispatch>; profileState?: ProfileState; + profilesUIEnabled?: boolean; + setProfilesUIEnabled?: React.Dispatch>; }; -export default function ProfilesView({ profileState }: ProfilesViewProps) { +export default function ProfilesView({ + profileState, + profilesUIEnabled, + setProfilesUIEnabled, +}: ProfilesViewProps) { const { t } = useTranslation(["views/settings", "common"]); const { data: config, mutate: updateConfig } = useSWR("config"); @@ -182,68 +190,95 @@ export default function ProfilesView({ profileState }: ProfilesViewProps) { return null; } + const hasProfiles = allProfileNames.length > 0; + return (
{t("profiles.title", { ns: "views/settings" })} - {/* Active Profile Section */} -
-
- {t("profiles.activeProfile", { ns: "views/settings" })} + {/* Enable Profiles Toggle — shown only when no profiles exist */} + {!hasProfiles && setProfilesUIEnabled && ( +
+
+ + +
+

+ {profilesUIEnabled + ? t("profiles.enabledDescription", { ns: "views/settings" }) + : t("profiles.disabledDescription", { ns: "views/settings" })} +

-
- - {activeProfile && ( - +
+ {t("profiles.activeProfile", { ns: "views/settings" })} +
+
+ + {activeProfile && ( + + {t("profiles.active", { ns: "views/settings" })} + + )} +
-
+ )} {/* Profile Cards */} - {allProfileNames.length === 0 ? ( + {!hasProfiles ? (
-

{t("profiles.noProfiles", { ns: "views/settings" })}

+ {!profilesUIEnabled && ( +

{t("profiles.noProfiles", { ns: "views/settings" })}

+ )}
) : (
diff --git a/web/src/views/settings/SingleSectionPage.tsx b/web/src/views/settings/SingleSectionPage.tsx index b72b97a3e..82c1f3a29 100644 --- a/web/src/views/settings/SingleSectionPage.tsx +++ b/web/src/views/settings/SingleSectionPage.tsx @@ -28,6 +28,8 @@ export type SettingsPageProps = { data: ConfigSectionData | null, ) => void; profileState?: ProfileState; + profilesUIEnabled?: boolean; + setProfilesUIEnabled?: React.Dispatch>; }; export type SectionStatus = {