mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-15 23:55:25 +03:00
Add zones and saving logic
This commit is contained in:
parent
37bece3419
commit
b7ffc1ec4c
@ -448,105 +448,6 @@ function ZoneFilterButton({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type ZoneFilterContentProps = {
|
|
||||||
allZones?: string[];
|
|
||||||
selectedZones?: string[];
|
|
||||||
currentZones?: string[];
|
|
||||||
updateZoneFilter?: (zones: string[] | undefined) => void;
|
|
||||||
setCurrentZones?: (zones: string[] | undefined) => void;
|
|
||||||
onClose: () => void;
|
|
||||||
};
|
|
||||||
export function ZoneFilterContent({
|
|
||||||
allZones,
|
|
||||||
selectedZones,
|
|
||||||
currentZones,
|
|
||||||
updateZoneFilter,
|
|
||||||
setCurrentZones,
|
|
||||||
onClose,
|
|
||||||
}: ZoneFilterContentProps) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="scrollbar-container h-auto max-h-[80dvh] overflow-y-auto overflow-x-hidden">
|
|
||||||
{allZones && setCurrentZones && (
|
|
||||||
<>
|
|
||||||
{isDesktop && <DropdownMenuSeparator />}
|
|
||||||
<div className="mb-5 mt-2.5 flex items-center justify-between">
|
|
||||||
<Label
|
|
||||||
className="mx-2 cursor-pointer text-primary"
|
|
||||||
htmlFor="allZones"
|
|
||||||
>
|
|
||||||
All Zones
|
|
||||||
</Label>
|
|
||||||
<Switch
|
|
||||||
className="ml-1"
|
|
||||||
id="allZones"
|
|
||||||
checked={currentZones == undefined}
|
|
||||||
onCheckedChange={(isChecked) => {
|
|
||||||
if (isChecked) {
|
|
||||||
setCurrentZones(undefined);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="my-2.5 flex flex-col gap-2.5">
|
|
||||||
{allZones.map((item) => (
|
|
||||||
<FilterSwitch
|
|
||||||
key={item}
|
|
||||||
label={item.replaceAll("_", " ")}
|
|
||||||
isChecked={currentZones?.includes(item) ?? false}
|
|
||||||
onCheckedChange={(isChecked) => {
|
|
||||||
if (isChecked) {
|
|
||||||
const updatedZones = currentZones
|
|
||||||
? [...currentZones]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
updatedZones.push(item);
|
|
||||||
setCurrentZones(updatedZones);
|
|
||||||
} else {
|
|
||||||
const updatedZones = currentZones
|
|
||||||
? [...currentZones]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
// can not deselect the last item
|
|
||||||
if (updatedZones.length > 1) {
|
|
||||||
updatedZones.splice(updatedZones.indexOf(item), 1);
|
|
||||||
setCurrentZones(updatedZones);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{isDesktop && <DropdownMenuSeparator />}
|
|
||||||
<div className="flex items-center justify-evenly p-2">
|
|
||||||
<Button
|
|
||||||
variant="select"
|
|
||||||
onClick={() => {
|
|
||||||
if (updateZoneFilter && selectedZones != currentZones) {
|
|
||||||
updateZoneFilter(currentZones);
|
|
||||||
}
|
|
||||||
|
|
||||||
onClose();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Apply
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
setCurrentZones?.(undefined);
|
|
||||||
updateZoneFilter?.(undefined);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Reset
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
type SubFilterButtonProps = {
|
type SubFilterButtonProps = {
|
||||||
allSubLabels: string[];
|
allSubLabels: string[];
|
||||||
selectedSubLabels: string[] | undefined;
|
selectedSubLabels: string[] | undefined;
|
||||||
|
|||||||
@ -19,6 +19,10 @@ import {
|
|||||||
import { isDesktop } from "react-device-detect";
|
import { isDesktop } from "react-device-detect";
|
||||||
import { useFormattedHour } from "@/hooks/use-date-utils";
|
import { useFormattedHour } from "@/hooks/use-date-utils";
|
||||||
import Heading from "@/components/ui/heading";
|
import Heading from "@/components/ui/heading";
|
||||||
|
import FilterSwitch from "@/components/filter/FilterSwitch";
|
||||||
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { DropdownMenuSeparator } from "@/components/ui/dropdown-menu";
|
||||||
|
|
||||||
type SearchFilterDialogProps = {
|
type SearchFilterDialogProps = {
|
||||||
config?: FrigateConfig;
|
config?: FrigateConfig;
|
||||||
@ -63,6 +67,35 @@ export default function SearchFilterDialog({
|
|||||||
setCurrentFilter({ time_range: newRange, ...currentFilter })
|
setCurrentFilter({ time_range: newRange, ...currentFilter })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<ZoneFilterContent
|
||||||
|
allZones={filterValues.zones}
|
||||||
|
zones={currentFilter.zones}
|
||||||
|
updateZones={(newZones) =>
|
||||||
|
setCurrentFilter({ zones: newZones, ...currentFilter })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{isDesktop && <DropdownMenuSeparator />}
|
||||||
|
<div className="flex items-center justify-evenly p-2">
|
||||||
|
<Button
|
||||||
|
variant="select"
|
||||||
|
onClick={() => {
|
||||||
|
if (currentFilter != filter) {
|
||||||
|
onUpdateFilter(currentFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
setOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Apply
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setCurrentFilter(filter ?? {});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -70,7 +103,7 @@ export default function SearchFilterDialog({
|
|||||||
<PlatformAwareSheet
|
<PlatformAwareSheet
|
||||||
trigger={trigger}
|
trigger={trigger}
|
||||||
content={content}
|
content={content}
|
||||||
contentClassName="w-auto"
|
contentClassName="w-auto lg:w-[300px]"
|
||||||
open={open}
|
open={open}
|
||||||
onOpenChange={setOpen}
|
onOpenChange={setOpen}
|
||||||
/>
|
/>
|
||||||
@ -210,6 +243,72 @@ function TimeRangeFilterContent({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ZoneFilterContentProps = {
|
||||||
|
allZones?: string[];
|
||||||
|
zones?: string[];
|
||||||
|
updateZones: (zones: string[] | undefined) => void;
|
||||||
|
};
|
||||||
|
export function ZoneFilterContent({
|
||||||
|
allZones,
|
||||||
|
zones,
|
||||||
|
updateZones,
|
||||||
|
}: ZoneFilterContentProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="scrollbar-container h-auto max-h-[80dvh] overflow-y-auto overflow-x-hidden">
|
||||||
|
{allZones && (
|
||||||
|
<>
|
||||||
|
{isDesktop && <DropdownMenuSeparator />}
|
||||||
|
<div className="mb-5 mt-2.5 flex items-center justify-between">
|
||||||
|
<Label
|
||||||
|
className="mx-2 cursor-pointer text-primary"
|
||||||
|
htmlFor="allZones"
|
||||||
|
>
|
||||||
|
All Zones
|
||||||
|
</Label>
|
||||||
|
<Switch
|
||||||
|
className="ml-1"
|
||||||
|
id="allZones"
|
||||||
|
checked={zones == undefined}
|
||||||
|
onCheckedChange={(isChecked) => {
|
||||||
|
if (isChecked) {
|
||||||
|
updateZones(undefined);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="my-2.5 flex flex-col gap-2.5">
|
||||||
|
{allZones.map((item) => (
|
||||||
|
<FilterSwitch
|
||||||
|
key={item}
|
||||||
|
label={item.replaceAll("_", " ")}
|
||||||
|
isChecked={zones?.includes(item) ?? false}
|
||||||
|
onCheckedChange={(isChecked) => {
|
||||||
|
if (isChecked) {
|
||||||
|
const updatedZones = zones ? [...zones] : [];
|
||||||
|
|
||||||
|
updatedZones.push(item);
|
||||||
|
updateZones(updatedZones);
|
||||||
|
} else {
|
||||||
|
const updatedZones = zones ? [...zones] : [];
|
||||||
|
|
||||||
|
// can not deselect the last item
|
||||||
|
if (updatedZones.length > 1) {
|
||||||
|
updatedZones.splice(updatedZones.indexOf(item), 1);
|
||||||
|
updateZones(updatedZones);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {filters.includes("date") && (
|
* {filters.includes("date") && (
|
||||||
<CalendarRangeFilterButton
|
<CalendarRangeFilterButton
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user