Extract common upload add routine
This commit is contained in:
parent
b115b98ea5
commit
5704597a4f
@ -1,20 +0,0 @@
|
||||
import { BiImageAdd } from 'react-icons/bi';
|
||||
import PathLoaderButton from '@/components/primitives/PathLoaderButton';
|
||||
import { ComponentProps } from 'react';
|
||||
|
||||
export default function AddButton({
|
||||
children,
|
||||
...props
|
||||
}: ComponentProps<typeof PathLoaderButton>) {
|
||||
return (
|
||||
<PathLoaderButton
|
||||
{...props}
|
||||
icon={<BiImageAdd
|
||||
size={18}
|
||||
className="translate-x-[1px] translate-y-[1px]"
|
||||
/>}
|
||||
>
|
||||
{children || 'Add'}
|
||||
</PathLoaderButton>
|
||||
);
|
||||
}
|
||||
@ -8,13 +8,14 @@ import clsx from 'clsx/lite';
|
||||
import ResponsiveDate from '@/components/ResponsiveDate';
|
||||
import Spinner from '@/components/Spinner';
|
||||
import { FaRegCircleCheck } from 'react-icons/fa6';
|
||||
import AddButton from './AddButton';
|
||||
import { pathForAdminUploadUrl } from '@/app/paths';
|
||||
import DeleteBlobButton from './DeleteUploadButton';
|
||||
import { Dispatch, SetStateAction, useEffect, useRef } from 'react';
|
||||
import { isElementEntirelyInViewport } from '@/utility/dom';
|
||||
import FieldSetWithStatus from '@/components/FieldSetWithStatus';
|
||||
import EditButton from './EditButton';
|
||||
import LoaderButton from '@/components/primitives/LoaderButton';
|
||||
import { BiImageAdd } from 'react-icons/bi';
|
||||
|
||||
export default function AdminUploadsTableRow({
|
||||
url,
|
||||
@ -55,6 +56,8 @@ export default function AdminUploadsTableRow({
|
||||
}
|
||||
}, [status]);
|
||||
|
||||
const isRowLoading = isAdding || isDeleting || isComplete || Boolean(status);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
@ -97,7 +100,7 @@ export default function AdminUploadsTableRow({
|
||||
}}
|
||||
placeholder="Title (optional)"
|
||||
tabIndex={tabIndex}
|
||||
readOnly={isAdding || isDeleting || isComplete || Boolean(status)}
|
||||
readOnly={isRowLoading}
|
||||
hideLabel
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
@ -112,14 +115,20 @@ export default function AdminUploadsTableRow({
|
||||
/>}
|
||||
</>
|
||||
: <>
|
||||
<AddButton
|
||||
path={pathForAdminUploadUrl(url)}
|
||||
disabled={isDeleting}
|
||||
<LoaderButton
|
||||
icon={<BiImageAdd
|
||||
size={18}
|
||||
className="translate-x-[1px] translate-y-[1px]"
|
||||
/>}
|
||||
disabled={isRowLoading}
|
||||
tooltip="Add directly"
|
||||
hideText="never"
|
||||
/>
|
||||
>
|
||||
Add
|
||||
</LoaderButton>
|
||||
<EditButton
|
||||
path={pathForAdminUploadUrl(url)}
|
||||
disabled={isRowLoading}
|
||||
tooltip="Review photo details"
|
||||
hideText="always"
|
||||
/>
|
||||
@ -133,7 +142,7 @@ export default function AdminUploadsTableRow({
|
||||
setUrlAddStatuses?.(statuses => statuses
|
||||
.filter(({ url: urlToRemove }) => urlToRemove !== url));
|
||||
}}
|
||||
isLoading={isDeleting}
|
||||
disabled={isRowLoading}
|
||||
tooltip="Delete upload"
|
||||
/>
|
||||
</>}
|
||||
|
||||
@ -85,23 +85,108 @@ export const createPhotoAction = async (formData: FormData) =>
|
||||
}
|
||||
});
|
||||
|
||||
export const addUploadsAction = async ({
|
||||
uploadUrls,
|
||||
uploadTitles,
|
||||
// Helper function for:
|
||||
// - addUploadAction
|
||||
// - addUploadsAction
|
||||
const addUpload = async ({
|
||||
url,
|
||||
title,
|
||||
tags,
|
||||
favorite,
|
||||
hidden,
|
||||
takenAtLocal,
|
||||
takenAtNaiveLocal,
|
||||
shouldRevalidateAllKeysAndPaths = true,
|
||||
}: {
|
||||
uploadUrls: string[]
|
||||
uploadTitles: string[]
|
||||
onStreamUpdate,
|
||||
onFinish,
|
||||
}:{
|
||||
url: string
|
||||
title?: string
|
||||
tags?: string
|
||||
favorite?: string
|
||||
hidden?: string
|
||||
takenAtLocal: string
|
||||
takenAtNaiveLocal: string
|
||||
onStreamUpdate: (
|
||||
statusMessage: string,
|
||||
status?: UrlAddStatus['status'],
|
||||
) => void
|
||||
onFinish?: (url: string) => void
|
||||
}) => {
|
||||
const {
|
||||
formDataFromExif,
|
||||
imageResizedBase64,
|
||||
shouldStripGpsData,
|
||||
fileBytes,
|
||||
} = await extractImageDataFromBlobPath(url, {
|
||||
includeInitialPhotoFields: true,
|
||||
generateBlurData: BLUR_ENABLED,
|
||||
generateResizedImage: AI_TEXT_GENERATION_ENABLED,
|
||||
});
|
||||
|
||||
if (formDataFromExif) {
|
||||
if (AI_TEXT_GENERATION_ENABLED) {
|
||||
onStreamUpdate('Generating AI text');
|
||||
}
|
||||
|
||||
const {
|
||||
title: aiTitle,
|
||||
caption,
|
||||
tags: aiTags,
|
||||
semanticDescription,
|
||||
} = await generateAiImageQueries(
|
||||
imageResizedBase64,
|
||||
Boolean(title)
|
||||
? AI_TEXT_AUTO_GENERATED_FIELDS
|
||||
.filter(field => field !== 'title')
|
||||
: AI_TEXT_AUTO_GENERATED_FIELDS,
|
||||
title,
|
||||
);
|
||||
|
||||
const form: Partial<PhotoFormData> = {
|
||||
...formDataFromExif,
|
||||
title: title || aiTitle,
|
||||
caption,
|
||||
tags: tags || aiTags,
|
||||
hidden,
|
||||
favorite,
|
||||
semanticDescription,
|
||||
takenAt: formDataFromExif.takenAt || takenAtLocal,
|
||||
takenAtNaive: formDataFromExif.takenAtNaive || takenAtNaiveLocal,
|
||||
};
|
||||
|
||||
onStreamUpdate('Transferring to photo storage');
|
||||
|
||||
const updatedUrl = await convertUploadToPhoto({
|
||||
urlOrigin: url,
|
||||
fileBytes,
|
||||
shouldStripGpsData,
|
||||
});
|
||||
if (updatedUrl) {
|
||||
const subheadFinal = 'Adding to database';
|
||||
onStreamUpdate(subheadFinal);
|
||||
const photo =
|
||||
await convertFormDataToPhotoDbInsertAndLookupRecipeTitle(form);
|
||||
photo.url = updatedUrl;
|
||||
await insertPhoto(photo);
|
||||
onFinish?.(url);
|
||||
// Re-submit with updated url
|
||||
onStreamUpdate(subheadFinal, 'added');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const addUploadsAction = async ({
|
||||
uploadUrls,
|
||||
uploadTitles,
|
||||
shouldRevalidateAllKeysAndPaths = true,
|
||||
tags,
|
||||
favorite,
|
||||
hidden,
|
||||
takenAtLocal,
|
||||
takenAtNaiveLocal,
|
||||
}: Parameters<typeof addUpload>[0] & {
|
||||
uploadUrls: string[]
|
||||
uploadTitles: string[]
|
||||
shouldRevalidateAllKeysAndPaths?: boolean
|
||||
}) =>
|
||||
runAuthenticatedAdminServerAction(async () => {
|
||||
@ -128,71 +213,23 @@ export const addUploadsAction = async ({
|
||||
try {
|
||||
for (const [index, url] of uploadUrls.entries()) {
|
||||
currentUploadUrl = url;
|
||||
const title = uploadTitles[index];
|
||||
progress = 0;
|
||||
const title = uploadTitles[index];
|
||||
streamUpdate('Parsing EXIF data');
|
||||
|
||||
const {
|
||||
formDataFromExif,
|
||||
imageResizedBase64,
|
||||
shouldStripGpsData,
|
||||
fileBytes,
|
||||
} = await extractImageDataFromBlobPath(url, {
|
||||
includeInitialPhotoFields: true,
|
||||
generateBlurData: BLUR_ENABLED,
|
||||
generateResizedImage: AI_TEXT_GENERATION_ENABLED,
|
||||
});
|
||||
|
||||
if (formDataFromExif) {
|
||||
if (AI_TEXT_GENERATION_ENABLED) {
|
||||
streamUpdate('Generating AI text');
|
||||
}
|
||||
|
||||
const {
|
||||
title: aiTitle,
|
||||
caption,
|
||||
tags: aiTags,
|
||||
semanticDescription,
|
||||
} = await generateAiImageQueries(
|
||||
imageResizedBase64,
|
||||
Boolean(title)
|
||||
? AI_TEXT_AUTO_GENERATED_FIELDS
|
||||
.filter(field => field !== 'title')
|
||||
: AI_TEXT_AUTO_GENERATED_FIELDS,
|
||||
title,
|
||||
);
|
||||
|
||||
const form: Partial<PhotoFormData> = {
|
||||
...formDataFromExif,
|
||||
title: title || aiTitle,
|
||||
caption,
|
||||
tags: tags || aiTags,
|
||||
hidden,
|
||||
favorite,
|
||||
semanticDescription,
|
||||
takenAt: formDataFromExif.takenAt || takenAtLocal,
|
||||
takenAtNaive: formDataFromExif.takenAtNaive || takenAtNaiveLocal,
|
||||
};
|
||||
|
||||
streamUpdate('Transferring to photo storage');
|
||||
|
||||
const updatedUrl = await convertUploadToPhoto({
|
||||
urlOrigin: url,
|
||||
fileBytes,
|
||||
shouldStripGpsData,
|
||||
});
|
||||
if (updatedUrl) {
|
||||
const subheadFinal = 'Adding to database';
|
||||
streamUpdate(subheadFinal);
|
||||
const photo =
|
||||
await convertFormDataToPhotoDbInsertAndLookupRecipeTitle(form);
|
||||
photo.url = updatedUrl;
|
||||
await insertPhoto(photo);
|
||||
await addUpload({
|
||||
url,
|
||||
title,
|
||||
tags,
|
||||
favorite,
|
||||
hidden,
|
||||
takenAtLocal,
|
||||
takenAtNaiveLocal,
|
||||
onStreamUpdate: streamUpdate,
|
||||
onFinish: () => {
|
||||
addedUploadUrls.push(url);
|
||||
// Re-submit with updated url
|
||||
streamUpdate(subheadFinal, 'added');
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
} catch (error: any) {
|
||||
// eslint-disable-next-line max-len
|
||||
|
||||
Loading…
Reference in New Issue
Block a user