forked from Github/frigate
Search functionality and UI tweaks (#13978)
* Portal tooltips * Add ability to time_range filter chroma searches * centering and padding consistency * add event id back to chroma metadata * query sqlite first and pass those ids to chroma for embeddings search * ensure we pass timezone to the api call * remove object lifecycle from search details for non-object events * simplify hour calculation * fix query without filters * bump chroma version * chroma 0.5.7 * fix selecting camera group in cameras filter button
This commit is contained in:
@@ -15,6 +15,7 @@ import { capitalizeFirstLetter } from "@/utils/stringUtil";
|
||||
import { SearchResult } from "@/types/search";
|
||||
import useContextMenu from "@/hooks/use-contextmenu";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
||||
|
||||
type SearchThumbnailProps = {
|
||||
searchResult: SearchResult;
|
||||
@@ -95,16 +96,18 @@ export default function SearchThumbnail({
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
</div>
|
||||
<TooltipContent className="capitalize">
|
||||
{[...new Set([searchResult.label])]
|
||||
.filter(
|
||||
(item) => item !== undefined && !item.includes("-verified"),
|
||||
)
|
||||
.map((text) => capitalizeFirstLetter(text))
|
||||
.sort()
|
||||
.join(", ")
|
||||
.replaceAll("-verified", "")}
|
||||
</TooltipContent>
|
||||
<TooltipPortal>
|
||||
<TooltipContent className="capitalize">
|
||||
{[...new Set([searchResult.label])]
|
||||
.filter(
|
||||
(item) => item !== undefined && !item.includes("-verified"),
|
||||
)
|
||||
.map((text) => capitalizeFirstLetter(text))
|
||||
.sort()
|
||||
.join(", ")
|
||||
.replaceAll("-verified", "")}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="rounded-t-l pointer-events-none absolute inset-x-0 top-0 z-10 h-[30%] w-full bg-gradient-to-b from-black/60 to-transparent"></div>
|
||||
|
||||
@@ -112,7 +112,10 @@ export function CamerasFilterButton({
|
||||
<div
|
||||
key={name}
|
||||
className="w-full cursor-pointer rounded-lg px-2 py-0.5 text-sm capitalize text-primary hover:bg-muted"
|
||||
onClick={() => setCurrentCameras([...conf.cameras])}
|
||||
onClick={() => {
|
||||
setAllCamerasSelected(false);
|
||||
setCurrentCameras([...conf.cameras]);
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</div>
|
||||
|
||||
@@ -27,7 +27,7 @@ function Bottombar() {
|
||||
isPWA && isIOS
|
||||
? "portrait:items-start portrait:pt-1 landscape:items-center"
|
||||
: "items-center",
|
||||
isMobile && !isPWA && "h-12 landscape:md:h-16",
|
||||
isMobile && !isPWA && "h-12 md:h-16",
|
||||
)}
|
||||
>
|
||||
{navItems.map((item) => (
|
||||
|
||||
@@ -201,21 +201,24 @@ export default function MobileReviewSettingsDrawer({
|
||||
Calendar
|
||||
</div>
|
||||
</div>
|
||||
<ReviewActivityCalendar
|
||||
reviewSummary={reviewSummary}
|
||||
selectedDay={
|
||||
filter?.after == undefined
|
||||
? undefined
|
||||
: new Date(filter.after * 1000)
|
||||
}
|
||||
onSelect={(day) => {
|
||||
onUpdateFilter({
|
||||
...filter,
|
||||
after: day == undefined ? undefined : day.getTime() / 1000,
|
||||
before: day == undefined ? undefined : getEndOfDayTimestamp(day),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<div className="flex w-full flex-row justify-center">
|
||||
<ReviewActivityCalendar
|
||||
reviewSummary={reviewSummary}
|
||||
selectedDay={
|
||||
filter?.after == undefined
|
||||
? undefined
|
||||
: new Date(filter.after * 1000)
|
||||
}
|
||||
onSelect={(day) => {
|
||||
onUpdateFilter({
|
||||
...filter,
|
||||
after: day == undefined ? undefined : day.getTime() / 1000,
|
||||
before:
|
||||
day == undefined ? undefined : getEndOfDayTimestamp(day),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<SelectSeparator />
|
||||
<div className="flex items-center justify-center p-2">
|
||||
<Button
|
||||
|
||||
@@ -95,6 +95,11 @@ export default function SearchDetailDialog({
|
||||
views.splice(index, 1);
|
||||
}
|
||||
|
||||
if (search.data.type != "object") {
|
||||
const index = views.indexOf("object lifecycle");
|
||||
views.splice(index, 1);
|
||||
}
|
||||
|
||||
// TODO implement
|
||||
//if (!config.semantic_search.enabled) {
|
||||
// const index = views.indexOf("similar-calendar");
|
||||
|
||||
@@ -26,7 +26,7 @@ export default function PlatformAwareDialog({
|
||||
return (
|
||||
<Drawer open={open} onOpenChange={onOpenChange}>
|
||||
<DrawerTrigger asChild>{trigger}</DrawerTrigger>
|
||||
<DrawerContent className="max-h-[75dvh] overflow-hidden p-4">
|
||||
<DrawerContent className="max-h-[75dvh] overflow-hidden px-4">
|
||||
{content}
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
@@ -82,14 +82,9 @@ export function useFormattedHour(
|
||||
const [hour, minute] = time.includes(":") ? time.split(":") : [time, "00"];
|
||||
const hourNum = parseInt(hour);
|
||||
|
||||
if (hourNum < 12) {
|
||||
if (hourNum == 0) {
|
||||
return `12:${minute} AM`;
|
||||
}
|
||||
const adjustedHour = hourNum % 12 || 12;
|
||||
const period = hourNum < 12 ? "AM" : "PM";
|
||||
|
||||
return `${hourNum}:${minute} AM`;
|
||||
} else {
|
||||
return `${hourNum - 12}:${minute} PM`;
|
||||
}
|
||||
return `${adjustedHour}:${minute} ${period}`;
|
||||
}, [hour24, time]);
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ export default function Explore() {
|
||||
time_range: searchSearchParams["time_range"],
|
||||
search_type: searchSearchParams["search_type"],
|
||||
event_id: searchSearchParams["event_id"],
|
||||
timezone,
|
||||
include_thumbnails: 0,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -11,13 +11,7 @@ import {
|
||||
} from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import {
|
||||
DEFAULT_SEARCH_FILTERS,
|
||||
SearchFilter,
|
||||
SearchFilters,
|
||||
SearchResult,
|
||||
SearchSource,
|
||||
} from "@/types/search";
|
||||
import { SearchFilter, SearchResult, SearchSource } from "@/types/search";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { isMobileOnly } from "react-device-detect";
|
||||
import { LuImage, LuSearchX, LuText } from "react-icons/lu";
|
||||
@@ -31,6 +25,7 @@ import InputWithTags from "@/components/input/InputWithTags";
|
||||
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
||||
import { isEqual } from "lodash";
|
||||
import { formatDateToLocaleString } from "@/utils/dateUtil";
|
||||
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
||||
|
||||
type SearchViewProps = {
|
||||
search: string;
|
||||
@@ -144,20 +139,6 @@ export default function SearchView({
|
||||
|
||||
const [searchDetail, setSearchDetail] = useState<SearchResult>();
|
||||
|
||||
const selectedFilters = useMemo<SearchFilters[]>(() => {
|
||||
const filters = [...DEFAULT_SEARCH_FILTERS];
|
||||
|
||||
if (
|
||||
searchFilter &&
|
||||
(searchFilter?.query?.length || searchFilter?.event_id?.length)
|
||||
) {
|
||||
const index = filters.indexOf("time");
|
||||
filters.splice(index, 1);
|
||||
}
|
||||
|
||||
return filters;
|
||||
}, [searchFilter]);
|
||||
|
||||
// search interaction
|
||||
|
||||
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
|
||||
@@ -335,7 +316,6 @@ export default function SearchView({
|
||||
"w-full justify-between md:justify-start lg:justify-end",
|
||||
)}
|
||||
filter={searchFilter}
|
||||
filters={selectedFilters as SearchFilters[]}
|
||||
onUpdateFilter={onUpdateFilter}
|
||||
/>
|
||||
<ScrollBar orientation="horizontal" className="h-0" />
|
||||
@@ -401,14 +381,16 @@ export default function SearchView({
|
||||
%
|
||||
</Chip>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
Matched {value.search_source} at{" "}
|
||||
{zScoreToConfidence(
|
||||
value.search_distance,
|
||||
value.search_source,
|
||||
)}
|
||||
%
|
||||
</TooltipContent>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>
|
||||
Matched {value.search_source} at{" "}
|
||||
{zScoreToConfidence(
|
||||
value.search_distance,
|
||||
value.search_source,
|
||||
)}
|
||||
%
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user