Explore pane infinite loading (#13738)

* swr for infinite loading

* search detail language change

* drawer padding

* spacing

* center calendar

* padding

* catch error

* use limit const
This commit is contained in:
Josh Hawkins
2024-09-14 08:42:56 -05:00
committed by GitHub
parent 088a0fb4a5
commit 2a66923524
9 changed files with 162 additions and 36 deletions

View File

@@ -3,12 +3,15 @@ import { useCameraPreviews } from "@/hooks/use-camera-previews";
import { useOverlayState, useSearchEffect } from "@/hooks/use-overlay-state";
import { FrigateConfig } from "@/types/frigateConfig";
import { RecordingStartingPoint } from "@/types/record";
import { SearchFilter, SearchResult } from "@/types/search";
import { SearchFilter, SearchQuery, SearchResult } from "@/types/search";
import { TimeRange } from "@/types/timeline";
import { RecordingView } from "@/views/recording/RecordingView";
import SearchView from "@/views/search/SearchView";
import { useCallback, useEffect, useMemo, useState } from "react";
import useSWR from "swr";
import useSWRInfinite from "swr/infinite";
const API_LIMIT = 25;
export default function Explore() {
const { data: config } = useSWR<FrigateConfig>("config", {
@@ -61,7 +64,7 @@ export default function Explore() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [search]);
const searchQuery = useMemo(() => {
const searchQuery: SearchQuery = useMemo(() => {
if (similaritySearch) {
return [
"events/search",
@@ -107,7 +110,8 @@ export default function Explore() {
before: searchSearchParams["before"],
after: searchSearchParams["after"],
search_type: searchSearchParams["search_type"],
limit: Object.keys(searchSearchParams).length == 0 ? 20 : null,
limit:
Object.keys(searchSearchParams).length == 0 ? API_LIMIT : undefined,
in_progress: 0,
include_thumbnails: 0,
},
@@ -117,8 +121,66 @@ export default function Explore() {
return null;
}, [searchTerm, searchSearchParams, similaritySearch]);
const { data: searchResults, isLoading } =
useSWR<SearchResult[]>(searchQuery);
// paging
const getKey = (
pageIndex: number,
previousPageData: SearchResult[] | null,
): SearchQuery => {
if (previousPageData && !previousPageData.length) return null; // reached the end
if (!searchQuery) return null;
const [url, params] = searchQuery;
// If it's not the first page, use the last item's start_time as the 'before' parameter
if (pageIndex > 0 && previousPageData) {
const lastDate = previousPageData[previousPageData.length - 1].start_time;
return [
url,
{ ...params, before: lastDate.toString(), limit: API_LIMIT },
];
}
// For the first page, use the original params
return [url, { ...params, limit: API_LIMIT }];
};
const { data, size, setSize, isValidating } = useSWRInfinite<SearchResult[]>(
getKey,
{
revalidateFirstPage: false,
revalidateAll: false,
},
);
const searchResults = useMemo(
() => (data ? ([] as SearchResult[]).concat(...data) : []),
[data],
);
const isLoadingInitialData = !data && !isValidating;
const isLoadingMore =
isLoadingInitialData ||
(size > 0 && data && typeof data[size - 1] === "undefined");
const isEmpty = data?.[0]?.length === 0;
const isReachingEnd =
isEmpty || (data && data[data.length - 1]?.length < API_LIMIT);
const loadMore = useCallback(() => {
if (!isReachingEnd && !isLoadingMore) {
if (searchQuery) {
const [url] = searchQuery;
// for chroma, only load 100 results for description and similarity
if (url === "events/search" && searchResults.length >= 100) {
return;
}
}
setSize(size + 1);
}
}, [isReachingEnd, isLoadingMore, setSize, size, searchResults, searchQuery]);
// previews
const previewTimeRange = useMemo<TimeRange>(() => {
if (!searchResults) {
@@ -212,11 +274,13 @@ export default function Explore() {
searchTerm={searchTerm}
searchFilter={searchFilter}
searchResults={searchResults}
isLoading={isLoading}
isLoading={(isLoadingInitialData || isLoadingMore) ?? true}
setSearch={setSearch}
setSimilaritySearch={(search) => setSearch(`similarity:${search.id}`)}
onUpdateFilter={setSearchFilter}
onOpenSearch={onOpenSearch}
loadMore={loadMore}
hasMore={!isReachingEnd}
/>
);
}