Add counts to admin tag management

This commit is contained in:
Sam Becker 2023-10-05 23:31:12 -05:00
parent 74bc870b3d
commit cddabc6180
4 changed files with 38 additions and 10 deletions

View File

@ -1,15 +1,16 @@
import FormWithConfirm from '@/components/FormWithConfirm';
import SiteGrid from '@/components/SiteGrid';
import { deletePhotoTagGloballyAction } from '@/photo/actions';
import { getUniqueTagsCached } from '@/cache';
import AdminGrid from '@/admin/AdminGrid';
import { Fragment } from 'react';
import DeleteButton from '@/admin/DeleteButton';
import { photoQuantityText } from '@/photo';
import { getUniqueTagsWithCountCached } from '@/cache';
export const runtime = 'edge';
export default async function AdminPhotosPage() {
const tags = await getUniqueTagsCached();
const tags = await getUniqueTagsWithCountCached();
return (
<SiteGrid
@ -17,18 +18,19 @@ export default async function AdminPhotosPage() {
<div className="space-y-6">
<div className="space-y-4">
<AdminGrid>
{tags.map(tag =>
{tags.map(({ tag, count }) =>
<Fragment key={tag}>
<div className="flex-grow w-full">
<div>
{tag}
</div>
<div />
<div />
<div className="text-dim">
{photoQuantityText(count, false)}
</div>
<FormWithConfirm
action={deletePhotoTagGloballyAction}
confirmText={
// eslint-disable-next-line max-len
`Are you sure you want to remove "${tag}?" from all photos?`}
`Are you sure you want to remove "${tag}?" from ${photoQuantityText(count, false)}?`}
>
<input type="hidden" name="tag" value={tag} />
<DeleteButton />

10
src/cache/index.ts vendored
View File

@ -11,6 +11,7 @@ import {
getUniqueTags,
getPhotosTagDateRange,
getPhotosCameraDateRange,
getUniqueTagsWithCount,
} from '@/services/postgres';
import { parseCachedPhotosDates, parseCachedPhotoDates } from '@/photo';
import { getBlobPhotoUrls, getBlobUploadUrls } from '@/services/blob';
@ -181,6 +182,15 @@ export const getUniqueTagsCached: typeof getUniqueTags = (...args) =>
}
)();
// eslint-disable-next-line max-len
export const getUniqueTagsWithCountCached: typeof getUniqueTagsWithCount = (...args) =>
unstable_cache(
() => getUniqueTagsWithCount(...args),
[KEY_PHOTOS, KEY_TAGS], {
tags: [KEY_PHOTOS, KEY_TAGS],
}
)();
export const getUniqueCamerasCached: typeof getUniqueCameras = (...args) =>
unstable_cache(
() => getUniqueCameras(...args),

View File

@ -157,8 +157,10 @@ export const titleForPhoto = (photo: Photo) =>
const photoLabelForCount = (count: number) =>
count === 1 ? 'Photo' : 'Photos';
export const photoQuantityText = (count: number) =>
`(${count} ${photoLabelForCount(count)})`;
export const photoQuantityText = (count: number, includeParentheses = true) =>
includeParentheses
? `(${count} ${photoLabelForCount(count)})`
: `${count} ${photoLabelForCount(count)}`;
export type PhotoDateRange = { start: string, end: string };

View File

@ -283,6 +283,17 @@ const sqlGetUniqueTags = async () => sql`
ORDER BY tag ASC
`.then(({ rows }) => rows.map(row => row.tag as string));
// Include hidden photos for admin usage
const sqlGetUniqueTagsWithCount = async () => sql`
SELECT DISTINCT unnest(tags) as tag, count(distinct id) as count FROM photos
GROUP BY tag
ORDER BY count ASC
`.then(({ rows }) => rows.map(row => ({
tag: row.tag as string,
count: parseInt(row.count, 10),
})));
const sqlGetUniqueCameras = async () => sql`
SELECT DISTINCT make||' '||model as camera, make, model FROM photos
WHERE hidden IS NOT TRUE
@ -390,6 +401,9 @@ export const getPhotosCameraDateRange = (camera: Camera) =>
export const getPhotosCountIncludingHidden = () =>
safelyQueryPhotos(sqlGetPhotosCountIncludingHidden);
export const getUniqueTags = () => safelyQueryPhotos(sqlGetUniqueTags);
export const getUniqueTags = () =>
safelyQueryPhotos(sqlGetUniqueTags);
export const getUniqueTagsWithCount = () =>
safelyQueryPhotos(sqlGetUniqueTagsWithCount);
export const getUniqueCameras = () => safelyQueryPhotos(sqlGetUniqueCameras);