mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-07-05 11:31:13 +03:00
add detection model card with tabs and custom model embed
This commit is contained in:
parent
635409cf23
commit
d776777a9f
@ -12,11 +12,14 @@ import { Badge } from "@/components/ui/badge";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Toaster } from "@/components/ui/sonner";
|
import { Toaster } from "@/components/ui/sonner";
|
||||||
import type { FrigateConfig } from "@/types/frigateConfig";
|
import type { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import type { SettingsPageProps } from "@/views/settings/SingleSectionPage";
|
import type {
|
||||||
import type { SectionStatus } from "@/views/settings/SingleSectionPage";
|
SectionStatus,
|
||||||
|
SettingsPageProps,
|
||||||
|
} from "@/views/settings/SingleSectionPage";
|
||||||
import type { ConfigSectionData } from "@/types/configForm";
|
import type { ConfigSectionData } from "@/types/configForm";
|
||||||
import { SettingsGroupCard } from "@/components/card/SettingsGroupCard";
|
import { SettingsGroupCard } from "@/components/card/SettingsGroupCard";
|
||||||
import { ConfigSectionTemplate } from "@/components/config-form/sections";
|
import { ConfigSectionTemplate } from "@/components/config-form/sections";
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
|
||||||
type ModelTab = "plus" | "custom";
|
type ModelTab = "plus" | "custom";
|
||||||
|
|
||||||
@ -76,6 +79,11 @@ export default function DetectorsAndModelSettingsView(
|
|||||||
isOverridden: false,
|
isOverridden: false,
|
||||||
hasValidationErrors: false,
|
hasValidationErrors: false,
|
||||||
});
|
});
|
||||||
|
const [modelStatus, setModelStatus] = useState<SectionStatus>({
|
||||||
|
hasChanges: false,
|
||||||
|
isOverridden: false,
|
||||||
|
hasValidationErrors: false,
|
||||||
|
});
|
||||||
|
|
||||||
const handleChildPendingChange = useCallback(
|
const handleChildPendingChange = useCallback(
|
||||||
(
|
(
|
||||||
@ -95,9 +103,19 @@ export default function DetectorsAndModelSettingsView(
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleDetectorStatusChange = useCallback(
|
||||||
|
(status: SectionStatus) => setDetectorStatus(status),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleModelStatusChange = useCallback(
|
||||||
|
(status: SectionStatus) => setModelStatus(status),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const detectorsPending = childPending["detectors"];
|
const detectorsPending = childPending["detectors"];
|
||||||
if (detectorsPending && state) {
|
if (detectorsPending) {
|
||||||
setState((prev) =>
|
setState((prev) =>
|
||||||
prev ? { ...prev, detectors: detectorsPending } : prev,
|
prev ? { ...prev, detectors: detectorsPending } : prev,
|
||||||
);
|
);
|
||||||
@ -105,6 +123,16 @@ export default function DetectorsAndModelSettingsView(
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [childPending["detectors"]]);
|
}, [childPending["detectors"]]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const modelPending = childPending["model"];
|
||||||
|
if (modelPending) {
|
||||||
|
setState((prev) =>
|
||||||
|
prev ? { ...prev, customModel: modelPending } : prev,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [childPending["model"]]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!config || snapshot !== null) return;
|
if (!config || snapshot !== null) return;
|
||||||
const initial = deriveInitialState(config);
|
const initial = deriveInitialState(config);
|
||||||
@ -150,7 +178,10 @@ export default function DetectorsAndModelSettingsView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const saveDisabled =
|
const saveDisabled =
|
||||||
!isDirty || isSaving || detectorStatus.hasValidationErrors;
|
!isDirty ||
|
||||||
|
isSaving ||
|
||||||
|
detectorStatus.hasValidationErrors ||
|
||||||
|
(state.modelTab === "custom" && modelStatus.hasValidationErrors);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex size-full flex-col md:pr-2">
|
<div className="flex size-full flex-col md:pr-2">
|
||||||
@ -194,13 +225,47 @@ export default function DetectorsAndModelSettingsView(
|
|||||||
embedded
|
embedded
|
||||||
pendingDataBySection={childPending}
|
pendingDataBySection={childPending}
|
||||||
onPendingDataChange={handleChildPendingChange}
|
onPendingDataChange={handleChildPendingChange}
|
||||||
onStatusChange={(status) => setDetectorStatus(status)}
|
onStatusChange={handleDetectorStatusChange}
|
||||||
/>
|
/>
|
||||||
</SettingsGroupCard>
|
</SettingsGroupCard>
|
||||||
<div className="rounded-lg border border-dashed border-border/70 p-6 text-sm text-muted-foreground">
|
<SettingsGroupCard title={t("detectorsAndModel.cardTitles.model")}>
|
||||||
{t("detectorsAndModel.cardTitles.model")} — placeholder, filled in
|
<Tabs
|
||||||
Tasks 6–8.
|
value={state.modelTab}
|
||||||
</div>
|
onValueChange={(value) =>
|
||||||
|
setState((prev) =>
|
||||||
|
prev ? { ...prev, modelTab: value as ModelTab } : prev,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<TabsList className="mb-4">
|
||||||
|
<TabsTrigger value="plus" disabled={!config.plus?.enabled}>
|
||||||
|
{t("detectorsAndModel.tabs.plus")}
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="custom">
|
||||||
|
{t("detectorsAndModel.tabs.custom")}
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="plus">
|
||||||
|
<div className="py-4 text-sm text-muted-foreground">
|
||||||
|
Frigate+ model selector — added in Task 7.
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="custom">
|
||||||
|
<ConfigSectionTemplate
|
||||||
|
sectionKey="model"
|
||||||
|
level="global"
|
||||||
|
showOverrideIndicator={false}
|
||||||
|
showTitle={false}
|
||||||
|
embedded
|
||||||
|
pendingDataBySection={childPending}
|
||||||
|
onPendingDataChange={handleChildPendingChange}
|
||||||
|
onStatusChange={handleModelStatusChange}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</SettingsGroupCard>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user