Surface granular photo sync status text

This commit is contained in:
Sam Becker 2025-04-19 15:23:11 -05:00
parent f22d5f85a8
commit 5f2a979a11
6 changed files with 46 additions and 15 deletions

View File

@ -8,12 +8,12 @@ import PathLoaderButton from '@/components/primitives/PathLoaderButton';
import { PATH_ADMIN_PHOTOS_SYNC } from '@/app/paths';
import { Photo } from '@/photo';
import { StorageListResponse } from '@/platforms/storage';
import { LiaBroomSolid } from 'react-icons/lia';
import AdminUploadsTable from './AdminUploadsTable';
import { Timezone } from '@/utility/timezone';
import { useAppState } from '@/state/AppState';
import PhotoUploadWithStatus from '@/photo/PhotoUploadWithStatus';
import { pluralize } from '@/utility/string';
import IconBroom from '@/components/icons/IconBroom';
export default function AdminPhotosClient({
photos,
@ -55,7 +55,7 @@ export default function AdminPhotosClient({
{photosCountOutdated > 0 &&
<PathLoaderButton
path={PATH_ADMIN_PHOTOS_SYNC}
icon={<LiaBroomSolid
icon={<IconBroom
size={18}
className="translate-y-[-1px]"
/>}

View File

@ -34,8 +34,8 @@ export default function AdminPhotosSyncClient({
<AdminChildPage
backLabel="Photos"
backPath={PATH_ADMIN_PHOTOS}
breadcrumb={<ResponsiveText shortText="Need Sync">
Need Sync ({photos.length})
breadcrumb={<ResponsiveText shortText="Needs Sync">
Needs Sync ({photos.length})
</ResponsiveText>}
accessory={<LoaderButton
primary
@ -85,7 +85,7 @@ export default function AdminPhotosSyncClient({
</div>
Sync photos to import newer EXIF fields, improve blur data,
{' '}
and leverage AI-generated text where possible
and generate AI text when configured
</div>
</Note>
<div className="space-y-4">
@ -95,7 +95,7 @@ export default function AdminPhotosSyncClient({
hasAiTextGeneration={hasAiTextGeneration}
canEdit={false}
canDelete={false}
showUpdatedAt
dateType="updatedAt"
/>
</div>
</div>

View File

@ -15,6 +15,8 @@ import PhotoSyncButton from './PhotoSyncButton';
import DeletePhotoButton from './DeletePhotoButton';
import { Timezone } from '@/utility/timezone';
import IconHidden from '@/components/icons/IconHidden';
import Tooltip from '@/components/Tooltip';
import { photoHasSyncStatusText, photoSyncStatusText } from '@/photo/sync';
export default function AdminPhotosTable({
photos,
@ -22,7 +24,7 @@ export default function AdminPhotosTable({
revalidatePhoto,
photoIdsSyncing = [],
hasAiTextGeneration,
showUpdatedAt,
dateType = 'createdAt',
canEdit = true,
canDelete = true,
timezone,
@ -32,7 +34,7 @@ export default function AdminPhotosTable({
revalidatePhoto?: RevalidatePhoto
photoIdsSyncing?: string[]
hasAiTextGeneration: boolean
showUpdatedAt?: boolean
dateType?: 'createdAt' | 'updatedAt'
canEdit?: boolean
canDelete?: boolean
timezone?: Timezone
@ -90,11 +92,20 @@ export default function AdminPhotosTable({
'lg:w-[50%] uppercase',
'text-dim',
)}>
<PhotoDate {...{
photo,
dateType: showUpdatedAt ? 'updatedAt' : 'createdAt',
timezone,
}} />
{<>
<PhotoDate {...{
photo,
dateType,
timezone,
}} />
{photoHasSyncStatusText(photo) && <Tooltip
content={photoSyncStatusText(photo)}
classNameTrigger={clsx(
'translate-y-1 ml-1.5',
'text-blue-600 dark:text-blue-400',
)}
/>}
</>}
</div>
</div>
<div className={clsx(

View File

@ -10,7 +10,7 @@ export default function Tooltip({
}) {
return (
<TooltipPrimitive {...rest}>
{children ?? <IoInformationCircleOutline size={18} />}
{children ?? <IoInformationCircleOutline size={19} />}
</TooltipPrimitive>
);
}

View File

@ -0,0 +1,6 @@
import { IconBaseProps } from 'react-icons';
import { LiaBroomSolid } from 'react-icons/lia';
export default function IconBroom(props: IconBaseProps) {
return <LiaBroomSolid {...props} />;
}

View File

@ -1,5 +1,5 @@
import { MAKE_FUJIFILM } from '@/platforms/fujifilm';
import { PhotoDb } from '.';
import { Photo, PhotoDb } from '.';
import { AI_TEXT_AUTO_GENERATED_FIELDS } from '@/app/config';
export interface PhotoSyncStatus {
@ -34,3 +34,17 @@ export const generatePhotoSyncStatus = (photo: PhotoDb): PhotoSyncStatus => ({
isOutdated: isPhotoOutdated(photo),
isMissingAiText: doesPhotoNeedAiText(photo),
});
export const photoHasSyncStatusText = (photo: Photo) =>
photo.syncStatus.isOutdated || photo.syncStatus.isMissingAiText;
export const photoSyncStatusText = (photo: Photo) => {
const { isOutdated, isMissingAiText } = photo.syncStatus;
const text: string[] = [];
if (isOutdated) {
text.push('Outdated');
} else if (isMissingAiText) {
text.push('Missing AI Text');
}
return text.join(' and ');
};