Make photo querying more resilient

This commit is contained in:
Sam Becker 2024-09-07 11:45:24 -05:00
parent 236101d34e
commit e584a0364b
4 changed files with 49 additions and 33 deletions

View File

@ -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]);

View File

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

View File

@ -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[];
});

View File

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