mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-11 05:35:25 +03:00
Implement ability to sort frigate plus submissions
This commit is contained in:
parent
4870f976d4
commit
5700ff2019
@ -77,6 +77,8 @@ def events():
|
||||
min_length = request.args.get("min_length", type=float)
|
||||
max_length = request.args.get("max_length", type=float)
|
||||
|
||||
sort = request.args.get("sort", type=str)
|
||||
|
||||
clauses = []
|
||||
|
||||
selected_columns = [
|
||||
@ -219,10 +221,22 @@ def events():
|
||||
if len(clauses) == 0:
|
||||
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 = (
|
||||
Event.select(*selected_columns)
|
||||
.where(reduce(operator.and_, clauses))
|
||||
.order_by(Event.start_time.desc())
|
||||
.order_by(order_by)
|
||||
.limit(limit)
|
||||
.dicts()
|
||||
.iterator()
|
||||
|
||||
@ -20,13 +20,20 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
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 { Event } from "@/types/event";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import axios from "axios";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
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 useSWR from "swr";
|
||||
|
||||
@ -43,6 +50,10 @@ export default function SubmitPlus() {
|
||||
const [selectedLabels, setSelectedLabels] = useState<string[]>();
|
||||
const [scoreRange, setScoreRange] = useState<number[]>();
|
||||
|
||||
// sort
|
||||
|
||||
const [sort, setSort] = useState<string>();
|
||||
|
||||
// data
|
||||
|
||||
const { data: events, mutate: refresh } = useSWR<Event[]>([
|
||||
@ -55,6 +66,7 @@ export default function SubmitPlus() {
|
||||
labels: selectedLabels ? selectedLabels.join(",") : null,
|
||||
min_score: scoreRange ? scoreRange[0] : null,
|
||||
max_score: scoreRange ? scoreRange[1] : null,
|
||||
sort: sort ? sort : null,
|
||||
},
|
||||
]);
|
||||
const [upload, setUpload] = useState<Event>();
|
||||
@ -112,14 +124,17 @@ export default function SubmitPlus() {
|
||||
|
||||
return (
|
||||
<div className="size-full flex flex-col">
|
||||
<PlusFilterGroup
|
||||
selectedCameras={selectedCameras}
|
||||
selectedLabels={selectedLabels}
|
||||
selectedScoreRange={scoreRange}
|
||||
setSelectedCameras={setSelectedCameras}
|
||||
setSelectedLabels={setSelectedLabels}
|
||||
setSelectedScoreRange={setScoreRange}
|
||||
/>
|
||||
<div className="w-full h-16 px-2 flex items-center justify-between overflow-x-auto">
|
||||
<PlusFilterGroup
|
||||
selectedCameras={selectedCameras}
|
||||
selectedLabels={selectedLabels}
|
||||
selectedScoreRange={scoreRange}
|
||||
setSelectedCameras={setSelectedCameras}
|
||||
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="w-full p-2 grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-2">
|
||||
<Dialog
|
||||
@ -246,7 +261,7 @@ function PlusFilterGroup({
|
||||
const Content = isMobile ? DrawerContent : DropdownMenuContent;
|
||||
|
||||
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
|
||||
allCameras={allCameras}
|
||||
groups={[]}
|
||||
@ -371,3 +386,161 @@ function PlusFilterGroup({
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user