Rename photo 'sync' to 'updates'

This commit is contained in:
Sam Becker 2025-04-20 22:41:35 -05:00
parent 0309f66b10
commit 61f358b73b
7 changed files with 38 additions and 34 deletions

View File

@ -267,7 +267,7 @@ Vercel Postgres can be switched to another Postgres-compatible, pooling provider
> There have been reports ([Issue 184](https://github.com/sambecker/exif-photo-blog/issues/184#issuecomment-2629474045) + [185](https://github.com/sambecker/exif-photo-blog/issues/185#issuecomment-2629478570)) that having large photos (over 30MB), or a CDN, e.g., Cloudflare in front of Vercel, may destabilize static optimization. > There have been reports ([Issue 184](https://github.com/sambecker/exif-photo-blog/issues/184#issuecomment-2629474045) + [185](https://github.com/sambecker/exif-photo-blog/issues/185#issuecomment-2629478570)) that having large photos (over 30MB), or a CDN, e.g., Cloudflare in front of Vercel, may destabilize static optimization.
#### Why don't my older photos look right? #### Why don't my older photos look right?
> As the template has evolved, EXIF fields (such as lenses) have been added, blur data is generated through a different method, and AI/privacy features have been added. In order to bring older photos up to date, either click the 'sync' button next to a photo or use the photo sync page (`/admin/photos/sync`) to make batch updates. > As the template has evolved, EXIF fields (such as lenses) have been added, blur data is generated through a different method, and AI/privacy features have been added. In order to bring older photos up to date, either click the 'sync' button next to a photo or go to photo updates (`/admin/photos/updates`) to sync all photos that need updates.
#### Why don't my OG images load when I share a link? #### Why don't my OG images load when I share a link?
> Many services such as iMessage, Slack, and X, require near-instant responses when unfurling link-based content. In order to guarantee sufficient responsiveness, consider rendering pages and image assets ahead of time by enabling static optimization by setting `NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTOS = 1` and `NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_OG_IMAGES = 1`. Keep in mind that this will increase platform usage. > Many services such as iMessage, Slack, and X, require near-instant responses when unfurling link-based content. In order to guarantee sufficient responsiveness, consider rendering pages and image assets ahead of time by enabling static optimization by setting `NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTOS = 1` and `NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_OG_IMAGES = 1`. Keep in mind that this will increase platform usage.
@ -315,7 +315,7 @@ Vercel Postgres can be switched to another Postgres-compatible, pooling provider
> You may need to pre-purchase credits before accessing the OpenAI API. See [Issue #110](https://github.com/sambecker/exif-photo-blog/issues/110) for discussion. > You may need to pre-purchase credits before accessing the OpenAI API. See [Issue #110](https://github.com/sambecker/exif-photo-blog/issues/110) for discussion.
#### How do I generate AI text for preexisting photos? #### How do I generate AI text for preexisting photos?
> Once AI text generation is configured, photos missing text will show up on the photo sync page (`/admin/photos/sync`). > Once AI text generation is configured, photos missing text will show up in photo updates (`/admin/photos/updates`).
#### Will there be support for image storage providers beyond Vercel, AWS, and Cloudflare? #### Will there be support for image storage providers beyond Vercel, AWS, and Cloudflare?
> At this time, there are no plans to introduce support for new storage providers. While configuring a new, AWS-compatible provider (e.g., Cloudflare R2) should not be too difficult, there's nuance to consider surrounding details like IAM, CORS, and domain configuration, which can differ slightly from platform to platform. If youd like to contribute an implementation for a new storage provider, please open a PR. > At this time, there are no plans to introduce support for new storage providers. While configuring a new, AWS-compatible provider (e.g., Cloudflare R2) should not be too difficult, there's nuance to consider surrounding details like IAM, CORS, and domain configuration, which can differ slightly from platform to platform. If youd like to contribute an implementation for a new storage provider, please open a PR.

View File

@ -4,7 +4,7 @@ import { getPhotosInNeedOfSync } from '@/photo/db/query';
export const maxDuration = 60; export const maxDuration = 60;
export default async function AdminSyncPage() { export default async function AdminUpdatesPage() {
const photos = await getPhotosInNeedOfSync() const photos = await getPhotosInNeedOfSync()
.catch(() => []); .catch(() => []);

View File

@ -5,7 +5,7 @@ import {
PATH_ADMIN_CONFIGURATION, PATH_ADMIN_CONFIGURATION,
PATH_ADMIN_INSIGHTS, PATH_ADMIN_INSIGHTS,
PATH_ADMIN_PHOTOS, PATH_ADMIN_PHOTOS,
PATH_ADMIN_PHOTOS_SYNC, PATH_ADMIN_PHOTOS_UPDATES,
PATH_ADMIN_RECIPES, PATH_ADMIN_RECIPES,
PATH_ADMIN_TAGS, PATH_ADMIN_TAGS,
PATH_ADMIN_UPLOADS, PATH_ADMIN_UPLOADS,
@ -79,6 +79,17 @@ export default function AdminAppMenu({
href: PATH_ADMIN_UPLOADS, href: PATH_ADMIN_UPLOADS,
}); });
} }
if (photosCountNeedSync) {
items.push({
label: 'Updates',
annotation: `${photosCountNeedSync}`,
icon: <IconBroom
size={17}
className="translate-y-[0.5px]"
/>,
href: PATH_ADMIN_PHOTOS_UPDATES,
});
}
if (photosCountTotal) { if (photosCountTotal) {
items.push({ items.push({
label: 'Manage Photos', label: 'Manage Photos',
@ -142,17 +153,6 @@ export default function AdminAppMenu({
shouldPreventDefault: false, shouldPreventDefault: false,
}); });
} }
if (photosCountNeedSync) {
items.push({
label: 'To Sync',
annotation: `${photosCountNeedSync}`,
icon: <IconBroom
size={17}
className="translate-y-[0.5px]"
/>,
href: PATH_ADMIN_PHOTOS_SYNC,
});
}
items.push({ items.push({
label: showAppInsightsLink label: showAppInsightsLink

View File

@ -5,7 +5,7 @@ import AppGrid from '@/components/AppGrid';
import AdminPhotosTable from '@/admin/AdminPhotosTable'; import AdminPhotosTable from '@/admin/AdminPhotosTable';
import AdminPhotosTableInfinite from '@/admin/AdminPhotosTableInfinite'; import AdminPhotosTableInfinite from '@/admin/AdminPhotosTableInfinite';
import PathLoaderButton from '@/components/primitives/PathLoaderButton'; import PathLoaderButton from '@/components/primitives/PathLoaderButton';
import { PATH_ADMIN_PHOTOS_SYNC } from '@/app/paths'; import { PATH_ADMIN_PHOTOS_UPDATES } from '@/app/paths';
import { Photo } from '@/photo'; import { Photo } from '@/photo';
import { StorageListResponse } from '@/platforms/storage'; import { StorageListResponse } from '@/platforms/storage';
import AdminUploadsTable from './AdminUploadsTable'; import AdminUploadsTable from './AdminUploadsTable';
@ -14,6 +14,7 @@ import { useAppState } from '@/state/AppState';
import PhotoUploadWithStatus from '@/photo/PhotoUploadWithStatus'; import PhotoUploadWithStatus from '@/photo/PhotoUploadWithStatus';
import { pluralize } from '@/utility/string'; import { pluralize } from '@/utility/string';
import IconBroom from '@/components/icons/IconBroom'; import IconBroom from '@/components/icons/IconBroom';
import ResponsiveText from '@/components/primitives/ResponsiveText';
export default function AdminPhotosClient({ export default function AdminPhotosClient({
photos, photos,
@ -54,10 +55,10 @@ export default function AdminPhotosClient({
</div> </div>
{photosCountNeedsSync > 0 && {photosCountNeedsSync > 0 &&
<PathLoaderButton <PathLoaderButton
path={PATH_ADMIN_PHOTOS_SYNC} path={PATH_ADMIN_PHOTOS_UPDATES}
icon={<IconBroom icon={<IconBroom
size={18} size={18}
className="translate-y-[-1px]" className="translate-x-[-1px]"
/>} />}
tooltip={( tooltip={(
pluralize(photosCountNeedsSync, 'photo') + pluralize(photosCountNeedsSync, 'photo') +
@ -74,7 +75,9 @@ export default function AdminPhotosClient({
spinnerClassName="text-blue-200 dark:text-blue-600/40" spinnerClassName="text-blue-200 dark:text-blue-600/40"
hideTextOnMobile={false} hideTextOnMobile={false}
> >
{photosCountNeedsSync} <ResponsiveText shortText={photosCountNeedsSync}>
{pluralize(photosCountNeedsSync, 'Update')}
</ResponsiveText>
</PathLoaderButton>} </PathLoaderButton>}
</div> </div>
{blobPhotoUrls.length > 0 && {blobPhotoUrls.length > 0 &&

View File

@ -44,8 +44,8 @@ export default function AdminPhotosSyncClient({
<AdminChildPage <AdminChildPage
backLabel="Photos" backLabel="Photos"
backPath={PATH_ADMIN_PHOTOS} backPath={PATH_ADMIN_PHOTOS}
breadcrumb={<ResponsiveText shortText="Needs Sync"> breadcrumb={<ResponsiveText shortText="Updates">
Needs Sync ({photos.length}) Updates ({photos.length})
</ResponsiveText>} </ResponsiveText>}
accessory={<ProgressButton accessory={<ProgressButton
primary primary
@ -116,7 +116,7 @@ export default function AdminPhotosSyncClient({
> >
<div className="space-y-1.5"> <div className="space-y-1.5">
<div className="font-bold"> <div className="font-bold">
Photos found: {statusText} Photo updates: {statusText}
</div> </div>
Sync to capture new EXIF fields, improve blur data, Sync to capture new EXIF fields, improve blur data,
{' '} {' '}

View File

@ -28,7 +28,7 @@ import {
import EnvVar from '@/components/EnvVar'; import EnvVar from '@/components/EnvVar';
import { IoSyncCircle } from 'react-icons/io5'; import { IoSyncCircle } from 'react-icons/io5';
import clsx from 'clsx/lite'; import clsx from 'clsx/lite';
import { PATH_ADMIN_PHOTOS_SYNC } from '@/app/paths'; import { PATH_ADMIN_PHOTOS_UPDATES } from '@/app/paths';
import { LiaBroomSolid } from 'react-icons/lia'; import { LiaBroomSolid } from 'react-icons/lia';
import { IoMdGrid } from 'react-icons/io'; import { IoMdGrid } from 'react-icons/io';
import { RiSpeedMiniLine } from 'react-icons/ri'; import { RiSpeedMiniLine } from 'react-icons/ri';
@ -440,12 +440,12 @@ export default function AdminAppInsightsClient({
'blue', 'blue',
)} )}
{' '} {' '}
to sync with updates
{renderTooltipContent(<> {renderTooltipContent(<>
Missing data or AI&#8209;generated text Missing data or AI&#8209;generated text
</>)} </>)}
</>} </>}
expandPath={PATH_ADMIN_PHOTOS_SYNC} expandPath={PATH_ADMIN_PHOTOS_UPDATES}
/>} />}
<ScoreCardRow <ScoreCardRow
icon={<IconPhoto icon={<IconPhoto

View File

@ -38,15 +38,15 @@ const PATH_FOCAL_LENGTH_DYNAMIC = `${PREFIX_FOCAL_LENGTH}/[focal]`;
const PATH_RECIPE_DYNAMIC = `${PREFIX_RECIPE}/[recipe]`; const PATH_RECIPE_DYNAMIC = `${PREFIX_RECIPE}/[recipe]`;
// Admin paths // Admin paths
export const PATH_ADMIN_PHOTOS = `${PATH_ADMIN}/photos`; export const PATH_ADMIN_PHOTOS = `${PATH_ADMIN}/photos`;
export const PATH_ADMIN_PHOTOS_SYNC = `${PATH_ADMIN_PHOTOS}/sync`; export const PATH_ADMIN_PHOTOS_UPDATES = `${PATH_ADMIN_PHOTOS}/updates`;
export const PATH_ADMIN_UPLOADS = `${PATH_ADMIN}/uploads`; export const PATH_ADMIN_UPLOADS = `${PATH_ADMIN}/uploads`;
export const PATH_ADMIN_TAGS = `${PATH_ADMIN}/tags`; export const PATH_ADMIN_TAGS = `${PATH_ADMIN}/tags`;
export const PATH_ADMIN_RECIPES = `${PATH_ADMIN}/recipes`; export const PATH_ADMIN_RECIPES = `${PATH_ADMIN}/recipes`;
export const PATH_ADMIN_CONFIGURATION = `${PATH_ADMIN}/configuration`; export const PATH_ADMIN_CONFIGURATION = `${PATH_ADMIN}/configuration`;
export const PATH_ADMIN_INSIGHTS = `${PATH_ADMIN}/insights`; export const PATH_ADMIN_INSIGHTS = `${PATH_ADMIN}/insights`;
export const PATH_ADMIN_BASELINE = `${PATH_ADMIN}/baseline`; export const PATH_ADMIN_BASELINE = `${PATH_ADMIN}/baseline`;
export const PATH_ADMIN_COMPONENTS = `${PATH_ADMIN}/components`; export const PATH_ADMIN_COMPONENTS = `${PATH_ADMIN}/components`;
// Debug paths // Debug paths
export const PATH_OG_ALL = `${PATH_OG}/all`; export const PATH_OG_ALL = `${PATH_OG}/all`;
@ -66,6 +66,7 @@ export const MISSING_FIELD = '-';
export const PATHS_ADMIN = [ export const PATHS_ADMIN = [
PATH_ADMIN, PATH_ADMIN,
PATH_ADMIN_PHOTOS, PATH_ADMIN_PHOTOS,
PATH_ADMIN_PHOTOS_UPDATES,
PATH_ADMIN_UPLOADS, PATH_ADMIN_UPLOADS,
PATH_ADMIN_TAGS, PATH_ADMIN_TAGS,
PATH_ADMIN_RECIPES, PATH_ADMIN_RECIPES,