mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-25 09:38:22 +03:00
tweaks
This commit is contained in:
parent
98e9e79881
commit
18d413fbee
@ -1067,6 +1067,33 @@ export default function Settings() {
|
|||||||
setNewProfiles((prev) => (prev.includes(name) ? prev : [...prev, name]));
|
setNewProfiles((prev) => (prev.includes(name) ? prev : [...prev, name]));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleRemoveNewProfile = useCallback((name: string) => {
|
||||||
|
setNewProfiles((prev) => prev.filter((p) => p !== name));
|
||||||
|
// Clear any editing state for this profile
|
||||||
|
setEditingProfile((prev) => {
|
||||||
|
const updated = { ...prev };
|
||||||
|
for (const key of Object.keys(updated)) {
|
||||||
|
if (updated[key] === name) {
|
||||||
|
delete updated[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
|
});
|
||||||
|
// Clear any pending data for this profile
|
||||||
|
setPendingDataBySection((prev) => {
|
||||||
|
const profileSegment = `profiles.${name}.`;
|
||||||
|
const updated = { ...prev };
|
||||||
|
let changed = false;
|
||||||
|
for (const key of Object.keys(updated)) {
|
||||||
|
if (key.includes(profileSegment)) {
|
||||||
|
delete updated[key];
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed ? updated : prev;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleDeleteProfileSection = useCallback(
|
const handleDeleteProfileSection = useCallback(
|
||||||
async (camera: string, section: string, profile: string) => {
|
async (camera: string, section: string, profile: string) => {
|
||||||
try {
|
try {
|
||||||
@ -1105,6 +1132,7 @@ export default function Settings() {
|
|||||||
allProfileNames,
|
allProfileNames,
|
||||||
onSelectProfile: handleSelectProfile,
|
onSelectProfile: handleSelectProfile,
|
||||||
onAddProfile: handleAddProfile,
|
onAddProfile: handleAddProfile,
|
||||||
|
onRemoveNewProfile: handleRemoveNewProfile,
|
||||||
onDeleteProfileSection: handleDeleteProfileSection,
|
onDeleteProfileSection: handleDeleteProfileSection,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
@ -1113,6 +1141,7 @@ export default function Settings() {
|
|||||||
allProfileNames,
|
allProfileNames,
|
||||||
handleSelectProfile,
|
handleSelectProfile,
|
||||||
handleAddProfile,
|
handleAddProfile,
|
||||||
|
handleRemoveNewProfile,
|
||||||
handleDeleteProfileSection,
|
handleDeleteProfileSection,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -1780,6 +1809,8 @@ export default function Settings() {
|
|||||||
pendingDataBySection={pendingDataBySection}
|
pendingDataBySection={pendingDataBySection}
|
||||||
onPendingDataChange={handlePendingDataChange}
|
onPendingDataChange={handlePendingDataChange}
|
||||||
profileState={profileState}
|
profileState={profileState}
|
||||||
|
profilesUIEnabled={profilesUIEnabled}
|
||||||
|
setProfilesUIEnabled={setProfilesUIEnabled}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export type ProfileState = {
|
|||||||
profile: string | null,
|
profile: string | null,
|
||||||
) => void;
|
) => void;
|
||||||
onAddProfile: (name: string) => void;
|
onAddProfile: (name: string) => void;
|
||||||
|
onRemoveNewProfile: (name: string) => void;
|
||||||
onDeleteProfileSection: (
|
onDeleteProfileSection: (
|
||||||
camera: string,
|
camera: string,
|
||||||
section: string,
|
section: string,
|
||||||
|
|||||||
@ -142,6 +142,15 @@ export default function ProfilesView({
|
|||||||
|
|
||||||
const handleDeleteProfile = useCallback(async () => {
|
const handleDeleteProfile = useCallback(async () => {
|
||||||
if (!deleteProfile || !config) return;
|
if (!deleteProfile || !config) return;
|
||||||
|
|
||||||
|
// If this is an unsaved (new) profile, just remove it from local state
|
||||||
|
const isNewProfile = profileState?.newProfiles.includes(deleteProfile);
|
||||||
|
if (isNewProfile) {
|
||||||
|
profileState?.onRemoveNewProfile(deleteProfile);
|
||||||
|
setDeleteProfile(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setDeleting(true);
|
setDeleting(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -184,7 +193,15 @@ export default function ProfilesView({
|
|||||||
setDeleting(false);
|
setDeleting(false);
|
||||||
setDeleteProfile(null);
|
setDeleteProfile(null);
|
||||||
}
|
}
|
||||||
}, [deleteProfile, activeProfile, config, updateConfig, updateProfiles, t]);
|
}, [
|
||||||
|
deleteProfile,
|
||||||
|
activeProfile,
|
||||||
|
config,
|
||||||
|
profileState,
|
||||||
|
updateConfig,
|
||||||
|
updateProfiles,
|
||||||
|
t,
|
||||||
|
]);
|
||||||
|
|
||||||
if (!config || !profilesData) {
|
if (!config || !profilesData) {
|
||||||
return null;
|
return null;
|
||||||
@ -193,14 +210,15 @@ export default function ProfilesView({
|
|||||||
const hasProfiles = allProfileNames.length > 0;
|
const hasProfiles = allProfileNames.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex size-full flex-col lg:pr-2">
|
<div className="flex size-full max-w-5xl flex-col lg:pr-2">
|
||||||
<Heading as="h4" className="mb-5">
|
<Heading as="h4">{t("profiles.title", { ns: "views/settings" })}</Heading>
|
||||||
{t("profiles.title", { ns: "views/settings" })}
|
<div className="my-1 text-sm text-muted-foreground">
|
||||||
</Heading>
|
{t("profiles.disabledDescription", { ns: "views/settings" })}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Enable Profiles Toggle — shown only when no profiles exist */}
|
{/* Enable Profiles Toggle — shown only when no profiles exist */}
|
||||||
{!hasProfiles && setProfilesUIEnabled && (
|
{!hasProfiles && setProfilesUIEnabled && (
|
||||||
<div className="mb-6 rounded-lg border border-border/70 bg-card/30 p-4">
|
<div className="my-6 max-w-xl rounded-lg border border-border/70 bg-card/30 p-4">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<Label htmlFor="profiles-toggle" className="cursor-pointer">
|
<Label htmlFor="profiles-toggle" className="cursor-pointer">
|
||||||
{t("profiles.enableSwitch", { ns: "views/settings" })}
|
{t("profiles.enableSwitch", { ns: "views/settings" })}
|
||||||
@ -211,14 +229,15 @@ export default function ProfilesView({
|
|||||||
onCheckedChange={setProfilesUIEnabled}
|
onCheckedChange={setProfilesUIEnabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-3 text-sm text-muted-foreground">
|
|
||||||
{profilesUIEnabled
|
|
||||||
? t("profiles.enabledDescription", { ns: "views/settings" })
|
|
||||||
: t("profiles.disabledDescription", { ns: "views/settings" })}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{profilesUIEnabled && (
|
||||||
|
<p className="mb-5 max-w-xl text-sm text-primary-variant">
|
||||||
|
{t("profiles.enabledDescription", { ns: "views/settings" })}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Active Profile Section — only when profiles exist */}
|
{/* Active Profile Section — only when profiles exist */}
|
||||||
{hasProfiles && (
|
{hasProfiles && (
|
||||||
<div className="mb-6 rounded-lg border border-border/70 bg-card/30 p-4">
|
<div className="mb-6 rounded-lg border border-border/70 bg-card/30 p-4">
|
||||||
@ -275,11 +294,13 @@ export default function ProfilesView({
|
|||||||
|
|
||||||
{/* Profile Cards */}
|
{/* Profile Cards */}
|
||||||
{!hasProfiles ? (
|
{!hasProfiles ? (
|
||||||
<div className="flex flex-col items-center justify-center py-12 text-muted-foreground">
|
profilesUIEnabled ? (
|
||||||
{!profilesUIEnabled && (
|
<p className="text-sm text-muted-foreground">
|
||||||
<p>{t("profiles.noProfiles", { ns: "views/settings" })}</p>
|
{t("profiles.noProfiles", { ns: "views/settings" })}
|
||||||
)}
|
</p>
|
||||||
</div>
|
) : (
|
||||||
|
<div />
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
{allProfileNames.map((profile) => {
|
{allProfileNames.map((profile) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user