Add severity filter (#11190)

* Allow viewing all types on single screen

* Implement for mobile as well

* fix import

* Show all is optional
This commit is contained in:
Nicolas Mowen 2024-05-01 08:11:16 -06:00 committed by GitHub
parent 499f70cfd3
commit b5b819c866
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 66 additions and 6 deletions

View File

@ -3,24 +3,27 @@ import { Label } from "../ui/label";
type FilterSwitchProps = { type FilterSwitchProps = {
label: string; label: string;
disabled?: boolean;
isChecked: boolean; isChecked: boolean;
onCheckedChange: (checked: boolean) => void; onCheckedChange: (checked: boolean) => void;
}; };
export default function FilterSwitch({ export default function FilterSwitch({
label, label,
disabled = false,
isChecked, isChecked,
onCheckedChange, onCheckedChange,
}: FilterSwitchProps) { }: FilterSwitchProps) {
return ( return (
<div className="flex justify-between items-center gap-1"> <div className="flex justify-between items-center gap-1">
<Label <Label
className="w-full mx-2 text-primary capitalize cursor-pointer" className={`w-full mx-2 text-primary capitalize cursor-pointer ${disabled ? "text-secondary-foreground" : ""}`}
htmlFor={label} htmlFor={label}
> >
{label} {label}
</Label> </Label>
<Switch <Switch
id={label} id={label}
disabled={disabled}
checked={isChecked} checked={isChecked}
onCheckedChange={onCheckedChange} onCheckedChange={onCheckedChange}
/> />

View File

@ -10,7 +10,7 @@ import {
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "../ui/dropdown-menu"; } from "../ui/dropdown-menu";
import { ReviewFilter, ReviewSummary } from "@/types/review"; import { ReviewFilter, ReviewSeverity, ReviewSummary } from "@/types/review";
import { getEndOfDayTimestamp } from "@/utils/dateUtil"; import { getEndOfDayTimestamp } from "@/utils/dateUtil";
import { useFormattedTimestamp } from "@/hooks/use-date-utils"; import { useFormattedTimestamp } from "@/hooks/use-date-utils";
import { import {
@ -49,19 +49,21 @@ const DEFAULT_REVIEW_FILTERS: ReviewFilters[] = [
type ReviewFilterGroupProps = { type ReviewFilterGroupProps = {
filters?: ReviewFilters[]; filters?: ReviewFilters[];
currentSeverity?: ReviewSeverity;
reviewSummary?: ReviewSummary; reviewSummary?: ReviewSummary;
filter?: ReviewFilter; filter?: ReviewFilter;
onUpdateFilter: (filter: ReviewFilter) => void;
motionOnly: boolean; motionOnly: boolean;
onUpdateFilter: (filter: ReviewFilter) => void;
setMotionOnly: React.Dispatch<React.SetStateAction<boolean>>; setMotionOnly: React.Dispatch<React.SetStateAction<boolean>>;
}; };
export default function ReviewFilterGroup({ export default function ReviewFilterGroup({
filters = DEFAULT_REVIEW_FILTERS, filters = DEFAULT_REVIEW_FILTERS,
currentSeverity,
reviewSummary, reviewSummary,
filter, filter,
onUpdateFilter,
motionOnly, motionOnly,
onUpdateFilter,
setMotionOnly, setMotionOnly,
}: ReviewFilterGroupProps) { }: ReviewFilterGroupProps) {
const { data: config } = useSWR<FrigateConfig>("config"); const { data: config } = useSWR<FrigateConfig>("config");
@ -179,6 +181,11 @@ export default function ReviewFilterGroup({
<GeneralFilterButton <GeneralFilterButton
allLabels={filterValues.labels} allLabels={filterValues.labels}
selectedLabels={filter?.labels} selectedLabels={filter?.labels}
currentSeverity={currentSeverity}
showAll={filter?.showAll == true}
setShowAll={(showAll) => {
onUpdateFilter({ ...filter, showAll });
}}
updateLabelFilter={(newLabels) => { updateLabelFilter={(newLabels) => {
onUpdateFilter({ ...filter, labels: newLabels }); onUpdateFilter({ ...filter, labels: newLabels });
}} }}
@ -188,6 +195,7 @@ export default function ReviewFilterGroup({
<MobileReviewSettingsDrawer <MobileReviewSettingsDrawer
features={mobileSettingsFeatures} features={mobileSettingsFeatures}
filter={filter} filter={filter}
currentSeverity={currentSeverity}
reviewSummary={reviewSummary} reviewSummary={reviewSummary}
onUpdateFilter={onUpdateFilter} onUpdateFilter={onUpdateFilter}
// not applicable as exports are not used // not applicable as exports are not used
@ -477,11 +485,17 @@ function CalendarFilterButton({
type GeneralFilterButtonProps = { type GeneralFilterButtonProps = {
allLabels: string[]; allLabels: string[];
selectedLabels: string[] | undefined; selectedLabels: string[] | undefined;
currentSeverity?: ReviewSeverity;
showAll: boolean;
setShowAll: (showAll: boolean) => void;
updateLabelFilter: (labels: string[] | undefined) => void; updateLabelFilter: (labels: string[] | undefined) => void;
}; };
function GeneralFilterButton({ function GeneralFilterButton({
allLabels, allLabels,
selectedLabels, selectedLabels,
currentSeverity,
showAll,
setShowAll,
updateLabelFilter, updateLabelFilter,
}: GeneralFilterButtonProps) { }: GeneralFilterButtonProps) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
@ -510,6 +524,9 @@ function GeneralFilterButton({
allLabels={allLabels} allLabels={allLabels}
selectedLabels={selectedLabels} selectedLabels={selectedLabels}
currentLabels={currentLabels} currentLabels={currentLabels}
currentSeverity={currentSeverity}
showAll={showAll}
setShowAll={setShowAll}
updateLabelFilter={updateLabelFilter} updateLabelFilter={updateLabelFilter}
setCurrentLabels={setCurrentLabels} setCurrentLabels={setCurrentLabels}
onClose={() => setOpen(false)} onClose={() => setOpen(false)}
@ -557,6 +574,9 @@ type GeneralFilterContentProps = {
allLabels: string[]; allLabels: string[];
selectedLabels: string[] | undefined; selectedLabels: string[] | undefined;
currentLabels: string[] | undefined; currentLabels: string[] | undefined;
currentSeverity?: ReviewSeverity;
showAll?: boolean;
setShowAll?: (showAll: boolean) => void;
updateLabelFilter: (labels: string[] | undefined) => void; updateLabelFilter: (labels: string[] | undefined) => void;
setCurrentLabels: (labels: string[] | undefined) => void; setCurrentLabels: (labels: string[] | undefined) => void;
onClose: () => void; onClose: () => void;
@ -565,6 +585,9 @@ export function GeneralFilterContent({
allLabels, allLabels,
selectedLabels, selectedLabels,
currentLabels, currentLabels,
currentSeverity,
showAll,
setShowAll,
updateLabelFilter, updateLabelFilter,
setCurrentLabels, setCurrentLabels,
onClose, onClose,
@ -572,6 +595,25 @@ export function GeneralFilterContent({
return ( return (
<> <>
<div className="h-auto max-h-[80dvh] overflow-y-auto overflow-x-hidden"> <div className="h-auto max-h-[80dvh] overflow-y-auto overflow-x-hidden">
{currentSeverity && setShowAll && (
<div className="my-2.5 flex flex-col gap-2.5">
<FilterSwitch
label="Alerts"
disabled={currentSeverity == "alert"}
isChecked={currentSeverity == "alert" ? true : showAll == true}
onCheckedChange={setShowAll}
/>
<FilterSwitch
label="Detections"
disabled={currentSeverity == "detection"}
isChecked={
currentSeverity == "detection" ? true : showAll == true
}
onCheckedChange={setShowAll}
/>
<DropdownMenuSeparator />
</div>
)}
<div className="flex justify-between items-center my-2.5"> <div className="flex justify-between items-center my-2.5">
<Label <Label
className="mx-2 text-primary cursor-pointer" className="mx-2 text-primary cursor-pointer"

View File

@ -7,7 +7,7 @@ import { ExportContent } from "./ExportDialog";
import { ExportMode } from "@/types/filter"; import { ExportMode } from "@/types/filter";
import ReviewActivityCalendar from "./ReviewActivityCalendar"; import ReviewActivityCalendar from "./ReviewActivityCalendar";
import { SelectSeparator } from "../ui/select"; import { SelectSeparator } from "../ui/select";
import { ReviewFilter, ReviewSummary } from "@/types/review"; import { ReviewFilter, ReviewSeverity, ReviewSummary } from "@/types/review";
import { getEndOfDayTimestamp } from "@/utils/dateUtil"; import { getEndOfDayTimestamp } from "@/utils/dateUtil";
import { GeneralFilterContent } from "../filter/ReviewFilterGroup"; import { GeneralFilterContent } from "../filter/ReviewFilterGroup";
import useSWR from "swr"; import useSWR from "swr";
@ -31,6 +31,7 @@ type MobileReviewSettingsDrawerProps = {
features?: DrawerFeatures[]; features?: DrawerFeatures[];
camera: string; camera: string;
filter?: ReviewFilter; filter?: ReviewFilter;
currentSeverity?: ReviewSeverity;
latestTime: number; latestTime: number;
currentTime: number; currentTime: number;
range?: TimeRange; range?: TimeRange;
@ -44,6 +45,7 @@ export default function MobileReviewSettingsDrawer({
features = DEFAULT_DRAWER_FEATURES, features = DEFAULT_DRAWER_FEATURES,
camera, camera,
filter, filter,
currentSeverity,
latestTime, latestTime,
currentTime, currentTime,
range, range,
@ -263,6 +265,11 @@ export default function MobileReviewSettingsDrawer({
allLabels={allLabels} allLabels={allLabels}
selectedLabels={filter?.labels} selectedLabels={filter?.labels}
currentLabels={currentLabels} currentLabels={currentLabels}
currentSeverity={currentSeverity}
showAll={filter?.showAll == true}
setShowAll={(showAll) => {
onUpdateFilter({ ...filter, showAll });
}}
setCurrentLabels={setCurrentLabels} setCurrentLabels={setCurrentLabels}
updateLabelFilter={(newLabels) => updateLabelFilter={(newLabels) =>
onUpdateFilter({ ...filter, labels: newLabels }) onUpdateFilter({ ...filter, labels: newLabels })

View File

@ -26,6 +26,7 @@ export type ReviewFilter = {
before?: number; before?: number;
after?: number; after?: number;
showReviewed?: 0 | 1; showReviewed?: 0 | 1;
showAll?: boolean;
}; };
type ReviewSummaryDay = { type ReviewSummaryDay = {

View File

@ -270,6 +270,7 @@ export default function EventView({
? ["cameras", "date", "motionOnly"] ? ["cameras", "date", "motionOnly"]
: ["cameras", "reviewed", "date", "general"] : ["cameras", "reviewed", "date", "general"]
} }
currentSeverity={severityToggle}
reviewSummary={reviewSummary} reviewSummary={reviewSummary}
filter={filter} filter={filter}
onUpdateFilter={updateFilter} onUpdateFilter={updateFilter}
@ -370,7 +371,13 @@ function DetectionReview({
return null; return null;
} }
const current = reviewItems[severity]; let current;
if (filter?.showAll) {
current = reviewItems.all;
} else {
current = reviewItems[severity];
}
if (!current || current.length == 0) { if (!current || current.length == 0) {
return []; return [];