Add photo sync to admin menu
This commit is contained in:
parent
f4c1ebd642
commit
0309f66b10
@ -5,6 +5,7 @@ import {
|
||||
PATH_ADMIN_CONFIGURATION,
|
||||
PATH_ADMIN_INSIGHTS,
|
||||
PATH_ADMIN_PHOTOS,
|
||||
PATH_ADMIN_PHOTOS_SYNC,
|
||||
PATH_ADMIN_RECIPES,
|
||||
PATH_ADMIN_TAGS,
|
||||
PATH_ADMIN_UPLOADS,
|
||||
@ -26,6 +27,7 @@ import IconSignOut from '@/components/icons/IconSignOut';
|
||||
import IconLock from '@/components/icons/IconLock';
|
||||
import { IoMdCheckboxOutline } from 'react-icons/io';
|
||||
import Spinner from '@/components/Spinner';
|
||||
import IconBroom from '@/components/icons/IconBroom';
|
||||
|
||||
export default function AdminAppMenu({
|
||||
active,
|
||||
@ -38,6 +40,7 @@ export default function AdminAppMenu({
|
||||
}) {
|
||||
const {
|
||||
photosCountTotal = 0,
|
||||
photosCountNeedSync = 0,
|
||||
uploadsCount = 0,
|
||||
tagsCount = 0,
|
||||
recipesCount = 0,
|
||||
@ -71,7 +74,7 @@ export default function AdminAppMenu({
|
||||
annotation: `${uploadsCount}`,
|
||||
icon: <IconFolder
|
||||
size={16}
|
||||
className="translate-y-[0.5px]"
|
||||
className="translate-x-[1px] translate-y-[0.5px]"
|
||||
/>,
|
||||
href: PATH_ADMIN_UPLOADS,
|
||||
});
|
||||
@ -121,7 +124,10 @@ export default function AdminAppMenu({
|
||||
size={18}
|
||||
className="translate-x-[-1px] translate-y-[0.5px]"
|
||||
/>
|
||||
: <IoMdCheckboxOutline size={17} className="translate-x-[-0.5px]" />,
|
||||
: <IoMdCheckboxOutline
|
||||
size={16}
|
||||
className="translate-x-[-0.5px]"
|
||||
/>,
|
||||
href: PATH_GRID_INFERRED,
|
||||
action: () => {
|
||||
if (isSelecting) {
|
||||
@ -136,6 +142,17 @@ export default function AdminAppMenu({
|
||||
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({
|
||||
label: showAppInsightsLink
|
||||
|
||||
@ -61,7 +61,7 @@ export default function AdminPhotosClient({
|
||||
/>}
|
||||
tooltip={(
|
||||
pluralize(photosCountNeedsSync, 'photo') +
|
||||
' needs sync'
|
||||
' missing data or AI-generated text'
|
||||
)}
|
||||
className={clsx(
|
||||
'text-blue-600 dark:text-blue-400',
|
||||
|
||||
@ -7,12 +7,16 @@ import { testDatabaseConnection } from '@/platforms/postgres';
|
||||
import { testStorageConnection } from '@/platforms/storage';
|
||||
import { APP_CONFIGURATION } from '@/app/config';
|
||||
import { getStorageUploadUrlsNoStore } from '@/platforms/storage/cache';
|
||||
import { getInsightsIndicatorStatus } from '@/admin/insights/server';
|
||||
import {
|
||||
getPhotosMeta,
|
||||
getUniqueTags,
|
||||
getUniqueRecipes,
|
||||
getPhotosInNeedOfSyncCount,
|
||||
} from '@/photo/db/query';
|
||||
import {
|
||||
getGitHubMetaForCurrentApp,
|
||||
indicatorStatusForSignificantInsights,
|
||||
} from './insights';
|
||||
|
||||
export type AdminData = Awaited<ReturnType<typeof getAdminDataAction>>;
|
||||
|
||||
@ -21,10 +25,11 @@ export const getAdminDataAction = async () =>
|
||||
const [
|
||||
photosCount,
|
||||
photosCountHidden,
|
||||
photosCountNeedSync,
|
||||
codeMeta,
|
||||
uploadsCount,
|
||||
tagsCount,
|
||||
recipesCount,
|
||||
insightsIndicatorStatus,
|
||||
] = await Promise.all([
|
||||
getPhotosMeta()
|
||||
.then(({ count }) => count)
|
||||
@ -32,6 +37,8 @@ export const getAdminDataAction = async () =>
|
||||
getPhotosMeta({ hidden: 'only' })
|
||||
.then(({ count }) => count)
|
||||
.catch(() => 0),
|
||||
getPhotosInNeedOfSyncCount(),
|
||||
getGitHubMetaForCurrentApp(),
|
||||
getStorageUploadUrlsNoStore()
|
||||
.then(urls => urls.length)
|
||||
.catch(e => {
|
||||
@ -44,9 +51,13 @@ export const getAdminDataAction = async () =>
|
||||
getUniqueRecipes()
|
||||
.then(recipes => recipes.length)
|
||||
.catch(() => 0),
|
||||
getInsightsIndicatorStatus(),
|
||||
]);
|
||||
|
||||
const insightsIndicatorStatus = indicatorStatusForSignificantInsights({
|
||||
codeMeta,
|
||||
photosCountNeedSync,
|
||||
});
|
||||
|
||||
const photosCountTotal = (
|
||||
photosCount !== undefined &&
|
||||
photosCountHidden !== undefined
|
||||
@ -57,12 +68,13 @@ export const getAdminDataAction = async () =>
|
||||
return {
|
||||
photosCount,
|
||||
photosCountHidden,
|
||||
photosCountNeedSync,
|
||||
photosCountTotal,
|
||||
uploadsCount,
|
||||
tagsCount,
|
||||
recipesCount,
|
||||
insightsIndicatorStatus,
|
||||
};
|
||||
} as const;
|
||||
});
|
||||
|
||||
const scanForError = (
|
||||
|
||||
@ -46,6 +46,7 @@ import IconFocalLength from '@/components/icons/IconFocalLength';
|
||||
import IconTag from '@/components/icons/IconTag';
|
||||
import IconPhoto from '@/components/icons/IconPhoto';
|
||||
import { HiOutlineDocumentText } from 'react-icons/hi';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
const DEBUG_COMMIT_SHA = '4cd29ed';
|
||||
const DEBUG_COMMIT_MESSAGE = 'Long commit message for debugging purposes';
|
||||
@ -131,6 +132,13 @@ export default function AdminAppInsightsClient({
|
||||
{codeMeta?.branch ?? TEMPLATE_REPO_BRANCH}
|
||||
</a>;
|
||||
|
||||
const renderTooltipContent = (content: ReactNode) =>
|
||||
<Tooltip
|
||||
content={content}
|
||||
classNameTrigger="translate-y-[-1.5px] ml-2 h-3"
|
||||
supportMobile
|
||||
/>;
|
||||
|
||||
return (
|
||||
<ScoreCardContainer>
|
||||
{(codeMeta || debug) && <>
|
||||
@ -143,11 +151,9 @@ export default function AdminAppInsightsClient({
|
||||
/>}
|
||||
content={<>
|
||||
<span>Could not analyze source code</span>
|
||||
<Tooltip
|
||||
content="Could not connect to GitHub API. Try refreshing."
|
||||
classNameTrigger="translate-y-[-1.5px] ml-2 h-3"
|
||||
supportMobile
|
||||
/>
|
||||
{renderTooltipContent(
|
||||
'Could not connect to GitHub API. Try refreshing.',
|
||||
)}
|
||||
</>}
|
||||
/>}
|
||||
{((!codeMeta?.didError && noFork) || debug) &&
|
||||
@ -435,6 +441,9 @@ export default function AdminAppInsightsClient({
|
||||
)}
|
||||
{' '}
|
||||
to sync
|
||||
{renderTooltipContent(<>
|
||||
Missing data or AI‑generated text
|
||||
</>)}
|
||||
</>}
|
||||
expandPath={PATH_ADMIN_PHOTOS_SYNC}
|
||||
/>}
|
||||
|
||||
@ -99,9 +99,17 @@ export const getSignificantInsights = ({
|
||||
};
|
||||
};
|
||||
|
||||
export const indicatorStatusForSignificantInsights = (
|
||||
insights: Awaited<ReturnType<typeof getSignificantInsights>>,
|
||||
) => {
|
||||
export const indicatorStatusForSignificantInsights = ({
|
||||
codeMeta,
|
||||
photosCountNeedSync,
|
||||
}: Parameters<typeof getSignificantInsights>[0] & {
|
||||
photosCountNeedSync: number
|
||||
}) => {
|
||||
const insights = getSignificantInsights({
|
||||
codeMeta,
|
||||
photosCountNeedSync,
|
||||
});
|
||||
|
||||
const {
|
||||
forkBehind,
|
||||
noAiRateLimiting,
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
import { getPhotosInNeedOfSyncCount } from '@/photo/db/query';
|
||||
import {
|
||||
getSignificantInsights,
|
||||
indicatorStatusForSignificantInsights,
|
||||
} from '.';
|
||||
import { getGitHubMetaForCurrentApp } from '.';
|
||||
|
||||
export const getInsightsIndicatorStatus = async () => {
|
||||
const [
|
||||
codeMeta,
|
||||
photosCountNeedSync,
|
||||
] = await Promise.all([
|
||||
getGitHubMetaForCurrentApp(),
|
||||
getPhotosInNeedOfSyncCount(),
|
||||
]);
|
||||
|
||||
const significantInsights = getSignificantInsights({
|
||||
codeMeta,
|
||||
photosCountNeedSync,
|
||||
});
|
||||
|
||||
return indicatorStatusForSignificantInsights(significantInsights);
|
||||
};
|
||||
@ -151,7 +151,7 @@ export default function AppStateProvider({
|
||||
if (userEmail) {
|
||||
storeAuthEmailCookie(userEmail);
|
||||
}
|
||||
}, [userEmail, adminData]);
|
||||
}, [userEmail]);
|
||||
|
||||
const registerAdminUpdate = useCallback(() =>
|
||||
setAdminUpdateTimes(updates => [...updates, new Date()])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user