Make photo querying more resilient
This commit is contained in:
parent
236101d34e
commit
e584a0364b
@ -31,7 +31,7 @@ import { useTheme } from 'next-themes';
|
||||
import { BiDesktop, BiMoon, BiSun } from 'react-icons/bi';
|
||||
import { IoInvertModeSharp } from 'react-icons/io5';
|
||||
import { useAppState } from '@/state/AppState';
|
||||
import { queryPhotosByTitleAction } from '@/photo/actions';
|
||||
import { searchPhotosAction } from '@/photo/actions';
|
||||
import { RiToolsFill } from 'react-icons/ri';
|
||||
import { BiLockAlt, BiSolidUser } from 'react-icons/bi';
|
||||
import { HiDocumentText } from 'react-icons/hi';
|
||||
@ -151,27 +151,33 @@ export default function CommandKClient({
|
||||
useEffect(() => {
|
||||
if (queryDebounced.length >= MINIMUM_QUERY_LENGTH && !isPending) {
|
||||
setIsLoading(true);
|
||||
queryPhotosByTitleAction(queryDebounced).then(photos => {
|
||||
if (isOpenRef.current) {
|
||||
setQueriedSections(photos.length > 0
|
||||
? [{
|
||||
heading: 'Photos',
|
||||
accessory: <TbPhoto size={14} />,
|
||||
items: photos.map(photo => ({
|
||||
label: titleForPhoto(photo),
|
||||
keywords: getKeywordsForPhoto(photo),
|
||||
annotation: <PhotoDate {...{ photo }} />,
|
||||
accessory: <PhotoSmall photo={photo} />,
|
||||
path: pathForPhoto({ photo }),
|
||||
})),
|
||||
}]
|
||||
: []);
|
||||
} else {
|
||||
// Ignore stale requests that come in after dialog is closed
|
||||
searchPhotosAction(queryDebounced)
|
||||
.then(photos => {
|
||||
if (isOpenRef.current) {
|
||||
setQueriedSections(photos.length > 0
|
||||
? [{
|
||||
heading: 'Photos',
|
||||
accessory: <TbPhoto size={14} />,
|
||||
items: photos.map(photo => ({
|
||||
label: titleForPhoto(photo),
|
||||
keywords: getKeywordsForPhoto(photo),
|
||||
annotation: <PhotoDate {...{ photo }} />,
|
||||
accessory: <PhotoSmall photo={photo} />,
|
||||
path: pathForPhoto({ photo }),
|
||||
})),
|
||||
}]
|
||||
: []);
|
||||
} else {
|
||||
// Ignore stale requests that come in after dialog is closed
|
||||
setQueriedSections([]);
|
||||
}
|
||||
setIsLoading(false);
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
setQueriedSections([]);
|
||||
}
|
||||
setIsLoading(false);
|
||||
});
|
||||
setIsLoading(false);
|
||||
});
|
||||
}
|
||||
}, [queryDebounced, isPending]);
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
PhotoDateRange,
|
||||
PhotoSetAttributes,
|
||||
dateRangeForPhotos,
|
||||
titleForPhoto,
|
||||
} from '.';
|
||||
import ShareButton from '@/components/ShareButton';
|
||||
import AnimateItems from '@/components/AnimateItems';
|
||||
@ -13,7 +14,6 @@ import { ReactNode } from 'react';
|
||||
import DivDebugBaselineGrid from '@/components/DivDebugBaselineGrid';
|
||||
import PhotoPrevNext from './PhotoPrevNext';
|
||||
import PhotoLink from './PhotoLink';
|
||||
import { formatDate } from '@/utility/date';
|
||||
import ResponsiveText from '@/components/primitives/ResponsiveText';
|
||||
import { useAppState } from '@/state/AppState';
|
||||
|
||||
@ -83,10 +83,7 @@ export default function PhotoHeader({
|
||||
photo={selectedPhoto}
|
||||
className="uppercase font-bold text-ellipsis truncate"
|
||||
>
|
||||
{
|
||||
selectedPhoto.title ||
|
||||
formatDate(selectedPhoto.takenAt, 'tiny')
|
||||
}
|
||||
{titleForPhoto(selectedPhoto, true)}
|
||||
</PhotoLink>);
|
||||
|
||||
return (
|
||||
|
||||
@ -35,7 +35,7 @@ import {
|
||||
} from '@/site/paths';
|
||||
import { blurImageFromUrl, extractImageDataFromBlobPath } from './server';
|
||||
import { TAG_FAVS, isTagFavs } from '@/tag';
|
||||
import { convertPhotoToPhotoDbInsert } from '.';
|
||||
import { convertPhotoToPhotoDbInsert, Photo } from '.';
|
||||
import { runAuthenticatedAdminServerAction } from '@/auth';
|
||||
import { AI_IMAGE_QUERIES, AiImageQuery } from './ai';
|
||||
import { streamOpenAiImageQuery } from '@/services/openai';
|
||||
@ -412,6 +412,9 @@ export const getPhotosCachedAction = async (options: GetPhotosOptions) =>
|
||||
|
||||
// Public actions
|
||||
|
||||
export const queryPhotosByTitleAction = async (query: string) =>
|
||||
(await getPhotos({ query, limit: 10 }))
|
||||
.filter(({ title }) => Boolean(title));
|
||||
export const searchPhotosAction = async (query: string) =>
|
||||
getPhotos({ query, limit: 10 })
|
||||
.catch(e => {
|
||||
console.error('Could not query photos', e);
|
||||
return [] as Photo[];
|
||||
});
|
||||
|
||||
@ -5,7 +5,7 @@ import { getNextImageUrlForRequest } from '@/services/next-image';
|
||||
import { FilmSimulation } from '@/simulation';
|
||||
import { HIGH_DENSITY_GRID, SHOW_EXIF_DATA } from '@/site/config';
|
||||
import { ABSOLUTE_PATH_FOR_HOME_IMAGE } from '@/site/paths';
|
||||
import { formatDateFromPostgresString } from '@/utility/date';
|
||||
import { formatDate, formatDateFromPostgresString } from '@/utility/date';
|
||||
import {
|
||||
formatAperture,
|
||||
formatIso,
|
||||
@ -198,8 +198,18 @@ const PHOTO_ID_FORWARDING_TABLE: Record<string, string> = JSON.parse(
|
||||
export const translatePhotoId = (id: string) =>
|
||||
PHOTO_ID_FORWARDING_TABLE[id] || id;
|
||||
|
||||
export const titleForPhoto = (photo: Photo) =>
|
||||
photo.title || 'Untitled';
|
||||
export const titleForPhoto = (
|
||||
photo: Photo,
|
||||
preferDateOverUntitled?: boolean,
|
||||
) => {
|
||||
if (photo.title) {
|
||||
return photo.title;
|
||||
} else if (preferDateOverUntitled && (photo.takenAt || photo.createdAt)) {
|
||||
return formatDate(photo.takenAt || photo.createdAt, 'tiny');
|
||||
} else {
|
||||
return 'Untitled';
|
||||
}
|
||||
};
|
||||
|
||||
export const altTextForPhoto = (photo: Photo) =>
|
||||
photo.semanticDescription || titleForPhoto(photo);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user