Refactor outdated photos header
This commit is contained in:
parent
a835e9ccdc
commit
141b7e3ed8
@ -5,18 +5,15 @@ import {
|
||||
getUniqueTagsCached,
|
||||
} from '@/photo/cache';
|
||||
import {
|
||||
PATH_ADMIN_OUTDATED,
|
||||
PATH_ADMIN_PHOTOS,
|
||||
PATH_ADMIN_TAGS,
|
||||
PATH_ADMIN_UPLOADS,
|
||||
} from '@/site/paths';
|
||||
import AdminNavClient from './AdminNavClient';
|
||||
import { OUTDATED_THRESHOLD } from '@/photo';
|
||||
|
||||
export default async function AdminNav() {
|
||||
const [
|
||||
countPhotos,
|
||||
countPhotosOutdated,
|
||||
countUploads,
|
||||
countTags,
|
||||
mostRecentPhotoUpdateTime,
|
||||
@ -24,12 +21,6 @@ export default async function AdminNav() {
|
||||
getPhotosMetaCached({ hidden: 'include' })
|
||||
.then(({ count }) => count)
|
||||
.catch(() => 0),
|
||||
getPhotosMetaCached({
|
||||
hidden: 'include',
|
||||
takenBefore: OUTDATED_THRESHOLD,
|
||||
})
|
||||
.then(({ count }) => count)
|
||||
.catch(() => 0),
|
||||
getStorageUploadUrlsNoStore()
|
||||
.then(urls => urls.length)
|
||||
.catch(e => {
|
||||
@ -47,13 +38,6 @@ export default async function AdminNav() {
|
||||
count: countPhotos,
|
||||
}];
|
||||
|
||||
// Outdated Photos
|
||||
if (countPhotosOutdated > 0) { items.push({
|
||||
label: 'Outdated',
|
||||
href: PATH_ADMIN_OUTDATED,
|
||||
count: countPhotosOutdated,
|
||||
}); }
|
||||
|
||||
// Uploads
|
||||
if (countUploads > 0) { items.push({
|
||||
label: 'Uploads',
|
||||
|
||||
@ -6,7 +6,7 @@ export default async function AdminLayout({
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<div className="mt-4 space-y-5">
|
||||
<div className="mt-4 space-y-4">
|
||||
<AdminNav />
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import SiteGrid from '@/components/SiteGrid';
|
||||
import { AI_TEXT_GENERATION_ENABLED } from '@/site/config';
|
||||
import { getPhotos } from '@/photo/db/query';
|
||||
import AdminPhotosTable from '@/admin/AdminPhotosTable';
|
||||
@ -6,6 +5,8 @@ import { OUTDATED_THRESHOLD } from '@/photo';
|
||||
import LoaderButton from '@/components/primitives/LoaderButton';
|
||||
import IconGrSync from '@/site/IconGrSync';
|
||||
import Banner from '@/components/Banner';
|
||||
import AdminChildPage from '@/components/AdminChildPage';
|
||||
import { PATH_ADMIN_PHOTOS } from '@/site/paths';
|
||||
|
||||
const UPDATE_BATCH_SIZE = 5;
|
||||
|
||||
@ -18,36 +19,44 @@ export default async function AdminPhotosPage() {
|
||||
}).catch(() => []);
|
||||
|
||||
return (
|
||||
<SiteGrid
|
||||
contentMain={
|
||||
<div className="space-y-4">
|
||||
<Banner>
|
||||
<div className="space-y-1.5">
|
||||
These photos {'('}uploaded before
|
||||
{' '}
|
||||
{new Date(OUTDATED_THRESHOLD).toLocaleDateString()}{')'}
|
||||
{' '}
|
||||
may have: missing EXIF fields, inaccurate blur data,
|
||||
{' '}
|
||||
undesired privacy settings,
|
||||
{' '}
|
||||
and missing AI-generated text.
|
||||
</div>
|
||||
</Banner>
|
||||
<LoaderButton
|
||||
icon={<IconGrSync className="translate-y-[1px]" />}
|
||||
hideTextOnMobile={false}
|
||||
className="primary"
|
||||
>
|
||||
Sync oldest {UPDATE_BATCH_SIZE} photos
|
||||
</LoaderButton>
|
||||
<div className="space-y-4">
|
||||
<AdminPhotosTable
|
||||
photos={photos}
|
||||
hasAiTextGeneration={AI_TEXT_GENERATION_ENABLED}
|
||||
/>
|
||||
<AdminChildPage
|
||||
backLabel="Photos"
|
||||
backPath={PATH_ADMIN_PHOTOS}
|
||||
breadcrumb={`Outdated (${photos.length})`}
|
||||
accessory={<LoaderButton
|
||||
icon={<IconGrSync className="translate-y-[1px]" />}
|
||||
hideTextOnMobile={false}
|
||||
className="primary"
|
||||
>
|
||||
<span className="hidden sm:inline-block">
|
||||
Sync oldest {UPDATE_BATCH_SIZE} photos
|
||||
</span>
|
||||
<span className="sm:hidden">
|
||||
Sync oldest
|
||||
</span>
|
||||
</LoaderButton>}
|
||||
>
|
||||
<div className="space-y-6">
|
||||
<Banner>
|
||||
<div className="space-y-1.5">
|
||||
These photos {'('}uploaded before
|
||||
{' '}
|
||||
{new Date(OUTDATED_THRESHOLD).toLocaleDateString()}{')'}
|
||||
{' '}
|
||||
may have: missing EXIF fields, inaccurate blur data,
|
||||
{' '}
|
||||
undesired privacy settings,
|
||||
{' '}
|
||||
and missing AI-generated text.
|
||||
</div>
|
||||
</div>}
|
||||
/>
|
||||
</Banner>
|
||||
<div className="space-y-4">
|
||||
<AdminPhotosTable
|
||||
photos={photos}
|
||||
hasAiTextGeneration={AI_TEXT_GENERATION_ENABLED}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</AdminChildPage>
|
||||
);
|
||||
}
|
||||
|
||||
@ -10,6 +10,10 @@ import AdminPhotosTable from '@/admin/AdminPhotosTable';
|
||||
import AdminPhotosTableInfinite from
|
||||
'@/admin/AdminPhotosTableInfinite';
|
||||
import { getPhotosMetaCached } from '@/photo/cache';
|
||||
import { IoInformationCircleOutline } from 'react-icons/io5';
|
||||
import PathLoaderButton from '@/components/primitives/PathLoaderButton';
|
||||
import { PATH_ADMIN_OUTDATED } from '@/site/paths';
|
||||
import { OUTDATED_THRESHOLD } from '@/photo';
|
||||
|
||||
const DEBUG_PHOTO_BLOBS = false;
|
||||
|
||||
@ -20,6 +24,7 @@ export default async function AdminPhotosPage() {
|
||||
const [
|
||||
photos,
|
||||
photosCount,
|
||||
photosCountOutdated,
|
||||
blobPhotoUrls,
|
||||
] = await Promise.all([
|
||||
getPhotos({
|
||||
@ -30,6 +35,12 @@ export default async function AdminPhotosPage() {
|
||||
getPhotosMetaCached({ hidden: 'include'})
|
||||
.then(({ count }) => count)
|
||||
.catch(() => 0),
|
||||
getPhotosMetaCached({
|
||||
hidden: 'include',
|
||||
takenBefore: OUTDATED_THRESHOLD,
|
||||
})
|
||||
.then(({ count }) => count)
|
||||
.catch(() => 0),
|
||||
DEBUG_PHOTO_BLOBS
|
||||
? getStoragePhotoUrlsNoStore()
|
||||
: [],
|
||||
@ -39,14 +50,28 @@ export default async function AdminPhotosPage() {
|
||||
<SiteGrid
|
||||
contentMain={
|
||||
<div className="space-y-4">
|
||||
<PhotoUpload
|
||||
shouldResize={!PRO_MODE_ENABLED}
|
||||
onLastUpload={async () => {
|
||||
'use server';
|
||||
// Update upload count in admin nav
|
||||
revalidatePath('/admin', 'layout');
|
||||
}}
|
||||
/>
|
||||
<div className="flex">
|
||||
<div className="grow">
|
||||
<PhotoUpload
|
||||
shouldResize={!PRO_MODE_ENABLED}
|
||||
onLastUpload={async () => {
|
||||
'use server';
|
||||
// Update upload count in admin nav
|
||||
revalidatePath('/admin', 'layout');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{photosCountOutdated > 0 && <PathLoaderButton
|
||||
path={PATH_ADMIN_OUTDATED}
|
||||
icon={<IoInformationCircleOutline
|
||||
size={18}
|
||||
/>}
|
||||
title={`${photosCountOutdated} Outdated Photos`}
|
||||
hideTextOnMobile={false}
|
||||
>
|
||||
{photosCountOutdated}
|
||||
</PathLoaderButton>}
|
||||
</div>
|
||||
{blobPhotoUrls.length > 0 &&
|
||||
<div className={clsx(
|
||||
'border-b pb-6',
|
||||
|
||||
@ -63,8 +63,8 @@ export default function ImageInput({
|
||||
isLoading={loading}
|
||||
className="primary"
|
||||
icon={<FiUploadCloud
|
||||
size={17}
|
||||
className="translate-y-[0.5px]"
|
||||
size={18}
|
||||
className="translate-x-[-0.5px] translate-y-[0.5px]"
|
||||
/>}
|
||||
aria-disabled={loading}
|
||||
onClick={() => inputRef.current?.click()}
|
||||
|
||||
@ -8,6 +8,7 @@ import LoaderButton from '@/components/primitives/LoaderButton';
|
||||
export default function PathLoaderButton({
|
||||
path,
|
||||
icon,
|
||||
title,
|
||||
prefetch,
|
||||
loaderDelay = 100,
|
||||
shouldScroll = true,
|
||||
@ -21,6 +22,7 @@ export default function PathLoaderButton({
|
||||
}: {
|
||||
path: string
|
||||
icon?: ReactNode
|
||||
title?: string
|
||||
prefetch?: boolean
|
||||
loaderDelay?: number
|
||||
shouldScroll?: boolean
|
||||
@ -58,6 +60,7 @@ export default function PathLoaderButton({
|
||||
return (
|
||||
<LoaderButton
|
||||
icon={icon}
|
||||
title={title}
|
||||
className={className}
|
||||
onClick={() => {
|
||||
startTransition(() => {
|
||||
|
||||
@ -99,6 +99,7 @@
|
||||
text-invert
|
||||
bg-gray-900 dark:bg-gray-100
|
||||
disabled:text-dim
|
||||
font-medium
|
||||
disabled:bg-gray-100 dark:disabled:bg-gray-900
|
||||
disabled:border-gray-200 disabled:dark:border-gray-700
|
||||
border-gray-900 dark:border-gray-100
|
||||
|
||||
Loading…
Reference in New Issue
Block a user