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; 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 (

View File

@ -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>