Implement ability to sort frigate plus submissions

This commit is contained in:
Nicolas Mowen 2024-04-13 09:23:33 -06:00
parent 4870f976d4
commit 5700ff2019
2 changed files with 198 additions and 11 deletions

View File

@ -77,6 +77,8 @@ def events():
min_length = request.args.get("min_length", type=float) min_length = request.args.get("min_length", type=float)
max_length = request.args.get("max_length", type=float) max_length = request.args.get("max_length", type=float)
sort = request.args.get("sort", type=str)
clauses = [] clauses = []
selected_columns = [ selected_columns = [
@ -219,10 +221,22 @@ def events():
if len(clauses) == 0: if len(clauses) == 0:
clauses.append((True)) clauses.append((True))
if sort:
if sort == "score_asc":
order_by = Event.data["score"].asc()
elif sort == "score_desc":
order_by = Event.data["score"].desc()
elif sort == "date_asc":
Event.start_time.asc()
elif sort == "date_desc":
Event.start_time.desc()
else:
order_by = Event.start_time.desc()
events = ( events = (
Event.select(*selected_columns) Event.select(*selected_columns)
.where(reduce(operator.and_, clauses)) .where(reduce(operator.and_, clauses))
.order_by(Event.start_time.desc()) .order_by(order_by)
.limit(limit) .limit(limit)
.dicts() .dicts()
.iterator() .iterator()

View File

@ -20,13 +20,20 @@ import {
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { DualThumbSlider } from "@/components/ui/slider"; import { DualThumbSlider } from "@/components/ui/slider";
import { Event } from "@/types/event"; import { Event } from "@/types/event";
import { FrigateConfig } from "@/types/frigateConfig"; import { FrigateConfig } from "@/types/frigateConfig";
import axios from "axios"; import axios from "axios";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { isMobile } from "react-device-detect"; import { isMobile } from "react-device-detect";
import { FaList } from "react-icons/fa"; import {
FaList,
FaSort,
FaSortAmountDown,
FaSortAmountUp,
} from "react-icons/fa";
import { PiSlidersHorizontalFill } from "react-icons/pi"; import { PiSlidersHorizontalFill } from "react-icons/pi";
import useSWR from "swr"; import useSWR from "swr";
@ -43,6 +50,10 @@ export default function SubmitPlus() {
const [selectedLabels, setSelectedLabels] = useState<string[]>(); const [selectedLabels, setSelectedLabels] = useState<string[]>();
const [scoreRange, setScoreRange] = useState<number[]>(); const [scoreRange, setScoreRange] = useState<number[]>();
// sort
const [sort, setSort] = useState<string>();
// data // data
const { data: events, mutate: refresh } = useSWR<Event[]>([ const { data: events, mutate: refresh } = useSWR<Event[]>([
@ -55,6 +66,7 @@ export default function SubmitPlus() {
labels: selectedLabels ? selectedLabels.join(",") : null, labels: selectedLabels ? selectedLabels.join(",") : null,
min_score: scoreRange ? scoreRange[0] : null, min_score: scoreRange ? scoreRange[0] : null,
max_score: scoreRange ? scoreRange[1] : null, max_score: scoreRange ? scoreRange[1] : null,
sort: sort ? sort : null,
}, },
]); ]);
const [upload, setUpload] = useState<Event>(); const [upload, setUpload] = useState<Event>();
@ -112,14 +124,17 @@ export default function SubmitPlus() {
return ( return (
<div className="size-full flex flex-col"> <div className="size-full flex flex-col">
<PlusFilterGroup <div className="w-full h-16 px-2 flex items-center justify-between overflow-x-auto">
selectedCameras={selectedCameras} <PlusFilterGroup
selectedLabels={selectedLabels} selectedCameras={selectedCameras}
selectedScoreRange={scoreRange} selectedLabels={selectedLabels}
setSelectedCameras={setSelectedCameras} selectedScoreRange={scoreRange}
setSelectedLabels={setSelectedLabels} setSelectedCameras={setSelectedCameras}
setSelectedScoreRange={setScoreRange} setSelectedLabels={setSelectedLabels}
/> setSelectedScoreRange={setScoreRange}
/>
<PlusSortSelector selectedSort={sort} setSelectedSort={setSort} />
</div>
<div className="size-full flex flex-1 flex-wrap content-start gap-2 md:gap-4 overflow-y-auto no-scrollbar"> <div className="size-full flex flex-1 flex-wrap content-start gap-2 md:gap-4 overflow-y-auto no-scrollbar">
<div className="w-full p-2 grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-2"> <div className="w-full p-2 grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-2">
<Dialog <Dialog
@ -246,7 +261,7 @@ function PlusFilterGroup({
const Content = isMobile ? DrawerContent : DropdownMenuContent; const Content = isMobile ? DrawerContent : DropdownMenuContent;
return ( return (
<div className="w-full h-16 mx-2 flex justify-start gap-2 items-center"> <div className="h-full flex justify-start gap-2 items-center">
<CamerasFilterButton <CamerasFilterButton
allCameras={allCameras} allCameras={allCameras}
groups={[]} groups={[]}
@ -371,3 +386,161 @@ function PlusFilterGroup({
</div> </div>
); );
} }
type PlusSortSelectorProps = {
selectedSort?: string;
setSelectedSort: (sort: string | undefined) => void;
};
function PlusSortSelector({
selectedSort,
setSelectedSort,
}: PlusSortSelectorProps) {
// menu state
const [open, setOpen] = useState(false);
// sort
const [currentSort, setCurrentSort] = useState<string>();
const [currentDir, setCurrentDir] = useState<string>("desc");
// components
const Sort = selectedSort
? selectedSort.split("_")[1] == "desc"
? FaSortAmountDown
: FaSortAmountUp
: FaSort;
const Menu = isMobile ? Drawer : DropdownMenu;
const Trigger = isMobile ? DrawerTrigger : DropdownMenuTrigger;
const Content = isMobile ? DrawerContent : DropdownMenuContent;
return (
<div className="h-full flex justify-start gap-2 items-center">
<Menu
open={open}
onOpenChange={(open) => {
setOpen(open);
if (!open) {
const parts = selectedSort?.split("_");
if (parts?.length == 2) {
setCurrentSort(parts[0]);
setCurrentDir(parts[1]);
}
}
}}
>
<Trigger asChild>
<Button
className="flex items-center gap-2 capitalize"
size="sm"
variant={selectedSort == undefined ? "default" : "select"}
>
<Sort
className={`${selectedSort == undefined ? "text-secondary-foreground" : "text-selected-foreground"}`}
/>
<div className="hidden md:block text-primary">
{selectedSort == undefined ? "Sort" : selectedSort.split("_")[0]}
</div>
</Button>
</Trigger>
<Content
className={`p-2 flex flex-col justify-center gap-2 ${isMobile ? "max-h-[75dvh]" : ""}`}
>
<RadioGroup
className={`flex flex-col gap-4 ${isMobile ? "mt-4" : ""}`}
onValueChange={(value) => setCurrentSort(value)}
>
<div className="w-full flex items-center gap-2">
<RadioGroupItem
className={
currentSort == "date"
? "from-selected/50 to-selected/90 text-selected bg-selected"
: "from-secondary/50 to-secondary/90 text-secondary bg-secondary"
}
id="date"
value="date"
/>
<Label
className="w-full cursor-pointer capitalize"
htmlFor="date"
>
Date
</Label>
{currentSort == "date" ? (
currentDir == "desc" ? (
<FaSortAmountDown
className="size-5 cursor-pointer"
onClick={() => setCurrentDir("asc")}
/>
) : (
<FaSortAmountUp
className="size-5 cursor-pointer"
onClick={() => setCurrentDir("desc")}
/>
)
) : (
<div className="size-5" />
)}
</div>
<div className="w-full flex items-center gap-2">
<RadioGroupItem
className={
currentSort == "score"
? "from-selected/50 to-selected/90 text-selected bg-selected"
: "from-secondary/50 to-secondary/90 text-secondary bg-secondary"
}
id="score"
value="score"
/>
<Label
className="w-full cursor-pointer capitalize"
htmlFor="score"
>
Score
</Label>
{currentSort == "score" ? (
currentDir == "desc" ? (
<FaSortAmountDown
className="size-5 cursor-pointer"
onClick={() => setCurrentDir("asc")}
/>
) : (
<FaSortAmountUp
className="size-5 cursor-pointer"
onClick={() => setCurrentDir("desc")}
/>
)
) : (
<div className="size-5" />
)}
</div>
</RadioGroup>
<DropdownMenuSeparator />
<div className="p-2 flex justify-evenly items-center">
<Button
variant="select"
onClick={() => {
setSelectedSort(`${currentSort}_${currentDir}`);
setOpen(false);
}}
>
Apply
</Button>
<Button
onClick={() => {
setCurrentSort(undefined);
setCurrentDir("desc");
setSelectedSort(undefined);
}}
>
Reset
</Button>
</div>
</Content>
</Menu>
</div>
);
}