mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-17 16:44:29 +03:00
use id instead of index for object details and scrolling
This commit is contained in:
parent
c95bc9fe44
commit
ce455de426
@ -26,7 +26,7 @@ type ExploreViewProps = {
|
|||||||
searchDetail: SearchResult | undefined;
|
searchDetail: SearchResult | undefined;
|
||||||
setSearchDetail: (search: SearchResult | undefined) => void;
|
setSearchDetail: (search: SearchResult | undefined) => void;
|
||||||
setSimilaritySearch: (search: SearchResult) => void;
|
setSimilaritySearch: (search: SearchResult) => void;
|
||||||
onSelectSearch: (item: SearchResult, index: number, page?: SearchTab) => void;
|
onSelectSearch: (item: SearchResult, page?: SearchTab) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ExploreView({
|
export default function ExploreView({
|
||||||
@ -125,7 +125,7 @@ type ThumbnailRowType = {
|
|||||||
setSearchDetail: (search: SearchResult | undefined) => void;
|
setSearchDetail: (search: SearchResult | undefined) => void;
|
||||||
mutate: () => void;
|
mutate: () => void;
|
||||||
setSimilaritySearch: (search: SearchResult) => void;
|
setSimilaritySearch: (search: SearchResult) => void;
|
||||||
onSelectSearch: (item: SearchResult, index: number, page?: SearchTab) => void;
|
onSelectSearch: (item: SearchResult, page?: SearchTab) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function ThumbnailRow({
|
function ThumbnailRow({
|
||||||
@ -205,7 +205,7 @@ type ExploreThumbnailImageProps = {
|
|||||||
setSearchDetail: (search: SearchResult | undefined) => void;
|
setSearchDetail: (search: SearchResult | undefined) => void;
|
||||||
mutate: () => void;
|
mutate: () => void;
|
||||||
setSimilaritySearch: (search: SearchResult) => void;
|
setSimilaritySearch: (search: SearchResult) => void;
|
||||||
onSelectSearch: (item: SearchResult, index: number, page?: SearchTab) => void;
|
onSelectSearch: (item: SearchResult, page?: SearchTab) => void;
|
||||||
};
|
};
|
||||||
function ExploreThumbnailImage({
|
function ExploreThumbnailImage({
|
||||||
event,
|
event,
|
||||||
@ -225,11 +225,11 @@ function ExploreThumbnailImage({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleShowObjectLifecycle = () => {
|
const handleShowObjectLifecycle = () => {
|
||||||
onSelectSearch(event, 0, "object lifecycle");
|
onSelectSearch(event, "object lifecycle");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleShowSnapshot = () => {
|
const handleShowSnapshot = () => {
|
||||||
onSelectSearch(event, 0, "snapshot");
|
onSelectSearch(event, "snapshot");
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -181,21 +181,45 @@ export default function SearchView({
|
|||||||
|
|
||||||
// search interaction
|
// search interaction
|
||||||
|
|
||||||
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
|
const [selectedObjects, setSelectedObjects] = useState<string[]>([]);
|
||||||
const itemRefs = useRef<(HTMLDivElement | null)[]>([]);
|
const itemRefs = useRef<(HTMLDivElement | null)[]>([]);
|
||||||
|
|
||||||
const onSelectSearch = useCallback(
|
const onSelectSearch = useCallback(
|
||||||
(item: SearchResult, index: number, page: SearchTab = "details") => {
|
(item: SearchResult, page: SearchTab = "details") => {
|
||||||
|
if (selectedObjects.length > 1) {
|
||||||
|
const index = selectedObjects.indexOf(item.id);
|
||||||
|
|
||||||
|
if (index != -1) {
|
||||||
|
if (selectedObjects.length == 1) {
|
||||||
|
setSelectedObjects([]);
|
||||||
|
} else {
|
||||||
|
const copy = [
|
||||||
|
...selectedObjects.slice(0, index),
|
||||||
|
...selectedObjects.slice(index + 1),
|
||||||
|
];
|
||||||
|
setSelectedObjects(copy);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const copy = [...selectedObjects];
|
||||||
|
copy.push(item.id);
|
||||||
|
setSelectedObjects(copy);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setSelectedObjects([item.id]);
|
||||||
|
}
|
||||||
setPage(page);
|
setPage(page);
|
||||||
setSearchDetail(item);
|
setSearchDetail(item);
|
||||||
setSelectedIndex(index);
|
|
||||||
},
|
},
|
||||||
[],
|
[selectedObjects],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedIndex(0);
|
if (uniqueResults && uniqueResults.length > 0) {
|
||||||
}, [searchTerm, searchFilter]);
|
setSelectedObjects([uniqueResults[0].id]);
|
||||||
|
} else {
|
||||||
|
setSelectedObjects([]);
|
||||||
|
}
|
||||||
|
}, [searchTerm, searchFilter, uniqueResults]);
|
||||||
|
|
||||||
// confidence score
|
// confidence score
|
||||||
|
|
||||||
@ -244,21 +268,46 @@ export default function SearchView({
|
|||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "ArrowLeft":
|
case "ArrowLeft":
|
||||||
setSelectedIndex((prevIndex) => {
|
setSelectedObjects((prevSelected) => {
|
||||||
|
if (uniqueResults.length === 0) return prevSelected;
|
||||||
|
|
||||||
|
const currentIndex =
|
||||||
|
prevSelected.length > 0
|
||||||
|
? uniqueResults.findIndex(
|
||||||
|
(result) => result.id === prevSelected[0],
|
||||||
|
)
|
||||||
|
: -1;
|
||||||
|
|
||||||
const newIndex =
|
const newIndex =
|
||||||
prevIndex === null
|
currentIndex === -1
|
||||||
? uniqueResults.length - 1
|
? uniqueResults.length - 1
|
||||||
: (prevIndex - 1 + uniqueResults.length) % uniqueResults.length;
|
: (currentIndex - 1 + uniqueResults.length) %
|
||||||
setSearchDetail(uniqueResults[newIndex]);
|
uniqueResults.length;
|
||||||
return newIndex;
|
|
||||||
|
const newSelectedResult = uniqueResults[newIndex];
|
||||||
|
setSearchDetail(newSelectedResult);
|
||||||
|
return [newSelectedResult.id];
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "ArrowRight":
|
case "ArrowRight":
|
||||||
setSelectedIndex((prevIndex) => {
|
setSelectedObjects((prevSelected) => {
|
||||||
|
if (uniqueResults.length === 0) return prevSelected;
|
||||||
|
|
||||||
|
const currentIndex =
|
||||||
|
prevSelected.length > 0
|
||||||
|
? uniqueResults.findIndex(
|
||||||
|
(result) => result.id === prevSelected[0],
|
||||||
|
)
|
||||||
|
: -1;
|
||||||
|
|
||||||
const newIndex =
|
const newIndex =
|
||||||
prevIndex === null ? 0 : (prevIndex + 1) % uniqueResults.length;
|
currentIndex === -1
|
||||||
setSearchDetail(uniqueResults[newIndex]);
|
? 0
|
||||||
return newIndex;
|
: (currentIndex + 1) % uniqueResults.length;
|
||||||
|
|
||||||
|
const newSelectedResult = uniqueResults[newIndex];
|
||||||
|
setSearchDetail(newSelectedResult);
|
||||||
|
return [newSelectedResult.id];
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "PageDown":
|
case "PageDown":
|
||||||
@ -287,20 +336,22 @@ export default function SearchView({
|
|||||||
// scroll into view
|
// scroll into view
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (selectedObjects.length > 0 && uniqueResults && itemRefs.current) {
|
||||||
selectedIndex !== null &&
|
const selectedIndex = uniqueResults.findIndex(
|
||||||
uniqueResults &&
|
(result) => result.id === selectedObjects[0],
|
||||||
itemRefs.current?.[selectedIndex]
|
);
|
||||||
) {
|
|
||||||
|
if (selectedIndex !== -1 && itemRefs.current[selectedIndex]) {
|
||||||
scrollIntoView(itemRefs.current[selectedIndex], {
|
scrollIntoView(itemRefs.current[selectedIndex], {
|
||||||
block: "center",
|
block: "center",
|
||||||
behavior: "smooth",
|
behavior: "smooth",
|
||||||
scrollMode: "if-needed",
|
scrollMode: "if-needed",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// we only want to scroll when the index changes
|
}
|
||||||
|
// we only want to scroll when the selected objects change
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [selectedIndex]);
|
}, [selectedObjects]);
|
||||||
|
|
||||||
// observer for loading more
|
// observer for loading more
|
||||||
|
|
||||||
@ -412,7 +463,7 @@ export default function SearchView({
|
|||||||
<div className={gridClassName}>
|
<div className={gridClassName}>
|
||||||
{uniqueResults &&
|
{uniqueResults &&
|
||||||
uniqueResults.map((value, index) => {
|
uniqueResults.map((value, index) => {
|
||||||
const selected = selectedIndex === index;
|
const selected = selectedObjects.includes(value.id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -428,7 +479,7 @@ export default function SearchView({
|
|||||||
>
|
>
|
||||||
<SearchThumbnail
|
<SearchThumbnail
|
||||||
searchResult={value}
|
searchResult={value}
|
||||||
onClick={() => onSelectSearch(value, index)}
|
onClick={() => onSelectSearch(value)}
|
||||||
/>
|
/>
|
||||||
{(searchTerm ||
|
{(searchTerm ||
|
||||||
searchFilter?.search_type?.includes("similarity")) && (
|
searchFilter?.search_type?.includes("similarity")) && (
|
||||||
@ -469,11 +520,9 @@ export default function SearchView({
|
|||||||
}}
|
}}
|
||||||
refreshResults={refresh}
|
refreshResults={refresh}
|
||||||
showObjectLifecycle={() =>
|
showObjectLifecycle={() =>
|
||||||
onSelectSearch(value, index, "object lifecycle")
|
onSelectSearch(value, "object lifecycle")
|
||||||
}
|
|
||||||
showSnapshot={() =>
|
|
||||||
onSelectSearch(value, index, "snapshot")
|
|
||||||
}
|
}
|
||||||
|
showSnapshot={() => onSelectSearch(value, "snapshot")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user