use id instead of index for object details and scrolling

This commit is contained in:
Josh Hawkins 2024-12-01 14:26:53 -06:00
parent c95bc9fe44
commit ce455de426
2 changed files with 87 additions and 38 deletions

View File

@ -26,7 +26,7 @@ type ExploreViewProps = {
searchDetail: SearchResult | undefined;
setSearchDetail: (search: SearchResult | undefined) => void;
setSimilaritySearch: (search: SearchResult) => void;
onSelectSearch: (item: SearchResult, index: number, page?: SearchTab) => void;
onSelectSearch: (item: SearchResult, page?: SearchTab) => void;
};
export default function ExploreView({
@ -125,7 +125,7 @@ type ThumbnailRowType = {
setSearchDetail: (search: SearchResult | undefined) => void;
mutate: () => void;
setSimilaritySearch: (search: SearchResult) => void;
onSelectSearch: (item: SearchResult, index: number, page?: SearchTab) => void;
onSelectSearch: (item: SearchResult, page?: SearchTab) => void;
};
function ThumbnailRow({
@ -205,7 +205,7 @@ type ExploreThumbnailImageProps = {
setSearchDetail: (search: SearchResult | undefined) => void;
mutate: () => void;
setSimilaritySearch: (search: SearchResult) => void;
onSelectSearch: (item: SearchResult, index: number, page?: SearchTab) => void;
onSelectSearch: (item: SearchResult, page?: SearchTab) => void;
};
function ExploreThumbnailImage({
event,
@ -225,11 +225,11 @@ function ExploreThumbnailImage({
};
const handleShowObjectLifecycle = () => {
onSelectSearch(event, 0, "object lifecycle");
onSelectSearch(event, "object lifecycle");
};
const handleShowSnapshot = () => {
onSelectSearch(event, 0, "snapshot");
onSelectSearch(event, "snapshot");
};
return (

View File

@ -181,21 +181,45 @@ export default function SearchView({
// search interaction
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
const [selectedObjects, setSelectedObjects] = useState<string[]>([]);
const itemRefs = useRef<(HTMLDivElement | null)[]>([]);
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);
setSearchDetail(item);
setSelectedIndex(index);
},
[],
[selectedObjects],
);
useEffect(() => {
setSelectedIndex(0);
}, [searchTerm, searchFilter]);
if (uniqueResults && uniqueResults.length > 0) {
setSelectedObjects([uniqueResults[0].id]);
} else {
setSelectedObjects([]);
}
}, [searchTerm, searchFilter, uniqueResults]);
// confidence score
@ -244,21 +268,46 @@ export default function SearchView({
switch (key) {
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 =
prevIndex === null
currentIndex === -1
? uniqueResults.length - 1
: (prevIndex - 1 + uniqueResults.length) % uniqueResults.length;
setSearchDetail(uniqueResults[newIndex]);
return newIndex;
: (currentIndex - 1 + uniqueResults.length) %
uniqueResults.length;
const newSelectedResult = uniqueResults[newIndex];
setSearchDetail(newSelectedResult);
return [newSelectedResult.id];
});
break;
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 =
prevIndex === null ? 0 : (prevIndex + 1) % uniqueResults.length;
setSearchDetail(uniqueResults[newIndex]);
return newIndex;
currentIndex === -1
? 0
: (currentIndex + 1) % uniqueResults.length;
const newSelectedResult = uniqueResults[newIndex];
setSearchDetail(newSelectedResult);
return [newSelectedResult.id];
});
break;
case "PageDown":
@ -287,20 +336,22 @@ export default function SearchView({
// scroll into view
useEffect(() => {
if (
selectedIndex !== null &&
uniqueResults &&
itemRefs.current?.[selectedIndex]
) {
if (selectedObjects.length > 0 && uniqueResults && itemRefs.current) {
const selectedIndex = uniqueResults.findIndex(
(result) => result.id === selectedObjects[0],
);
if (selectedIndex !== -1 && itemRefs.current[selectedIndex]) {
scrollIntoView(itemRefs.current[selectedIndex], {
block: "center",
behavior: "smooth",
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
}, [selectedIndex]);
}, [selectedObjects]);
// observer for loading more
@ -412,7 +463,7 @@ export default function SearchView({
<div className={gridClassName}>
{uniqueResults &&
uniqueResults.map((value, index) => {
const selected = selectedIndex === index;
const selected = selectedObjects.includes(value.id);
return (
<div
@ -428,7 +479,7 @@ export default function SearchView({
>
<SearchThumbnail
searchResult={value}
onClick={() => onSelectSearch(value, index)}
onClick={() => onSelectSearch(value)}
/>
{(searchTerm ||
searchFilter?.search_type?.includes("similarity")) && (
@ -469,11 +520,9 @@ export default function SearchView({
}}
refreshResults={refresh}
showObjectLifecycle={() =>
onSelectSearch(value, index, "object lifecycle")
}
showSnapshot={() =>
onSelectSearch(value, index, "snapshot")
onSelectSearch(value, "object lifecycle")
}
showSnapshot={() => onSelectSearch(value, "snapshot")}
/>
</div>
</div>