Vercel/src/admin/actions.ts
Sam Becker 59f5c74269
Chromatic sorting (#284)
* Test color palette extraction

* Fix import

* Add hex <> oklch conversions

* Add 'hue' storage to photos

* Consolidate color modules

* Add chromatic config, track missing color data

* Bump deps

* Fix lens text test

* Finalize color storage

* Refactor color imports

* Hide form color data when disabled

* Store all average oklch color components

* Finalize color-config language

* Optimize photo syncing for color data

* Only update color data when syncing if possible

* Build out all color sorts

* Debug image colors

* Improve color debugging

* Improve color logging

* Simplify color sorting

* Bump deps

* Fix color sync logic

* Switch to sort params: ascending, descending

* Fix commandk sort menu

* Update tr-tr sorting language

* Add color capture to all photo extractions

* Add color visualization to photo form

* Standardize photo update language

* Create global debug color update function

* Improve color data capture logging

* Update maximum function duration for admin photos

* Add note to remove maxDuration

* Use AI to generate sorting color

* Conditionally use AI to analyze colors

* Manage AI color analysis batched requests

* Fix color reporting in admin photo table

* Only update color where AI fields are missing

* Temporarily upgrade admin/photos timeout

* Fix pro-based max duration

* Standardize color sorting foundations

* Update color sorting language

* Refactor color calculations

* Restore max duration time

* Update color-based sort menu labels

* Finalize color documentation

* Clean up color test actions

* Round color sort values before submitting to db

* Consolidate color server actions
2025-08-03 19:31:02 -05:00

118 lines
3.0 KiB
TypeScript

'use server';
import { runAuthenticatedAdminServerAction } from '@/auth/server';
import { testRedisConnection } from '@/platforms/redis';
import { testOpenAiConnection } from '@/platforms/openai';
import { testDatabaseConnection } from '@/platforms/postgres';
import { testStorageConnection } from '@/platforms/storage';
import { APP_CONFIGURATION } from '@/app/config';
import { getStorageUploadUrlsNoStore } from '@/platforms/storage/cache';
import {
getPhotosMeta,
getUniqueTags,
getUniqueRecipes,
getPhotosInNeedOfUpdateCount,
} from '@/photo/db/query';
import {
getGitHubMetaForCurrentApp,
indicatorStatusForSignificantInsights,
} from './insights';
export type AdminData = Awaited<ReturnType<typeof getAdminDataAction>>;
export const getAdminDataAction = async () =>
runAuthenticatedAdminServerAction(async () => {
const [
photosCount,
photosCountHidden,
photosCountNeedSync,
codeMeta,
uploadsCount,
tagsCount,
recipesCount,
] = await Promise.all([
getPhotosMeta()
.then(({ count }) => count)
.catch(() => 0),
getPhotosMeta({ hidden: 'only' })
.then(({ count }) => count)
.catch(() => 0),
getPhotosInNeedOfUpdateCount(),
getGitHubMetaForCurrentApp(),
getStorageUploadUrlsNoStore()
.then(urls => urls.length)
.catch(e => {
console.error(`Error getting blob upload urls: ${e}`);
return 0;
}),
getUniqueTags()
.then(tags => tags.length)
.catch(() => 0),
getUniqueRecipes()
.then(recipes => recipes.length)
.catch(() => 0),
]);
const insightsIndicatorStatus = indicatorStatusForSignificantInsights({
codeMeta,
photosCountNeedSync,
});
const photosCountTotal = (
photosCount !== undefined &&
photosCountHidden !== undefined
)
? photosCount + photosCountHidden
: undefined;
return {
photosCount,
photosCountHidden,
photosCountNeedSync,
photosCountTotal,
uploadsCount,
tagsCount,
recipesCount,
insightsIndicatorStatus,
} as const;
});
const scanForError = (
shouldCheck: boolean,
promise: () => Promise<any>,
): Promise<string> =>
shouldCheck
? promise()
.then(() => '')
.catch(error => error.message)
: Promise.resolve('');
export const testConnectionsAction = async () =>
runAuthenticatedAdminServerAction(async () => {
const {
hasDatabase,
hasStorageProvider,
hasRedisStorage,
isAiTextGenerationEnabled,
} = APP_CONFIGURATION;
const [
databaseError,
storageError,
redisError,
aiError,
] = await Promise.all([
scanForError(hasDatabase, testDatabaseConnection),
scanForError(hasStorageProvider, testStorageConnection),
scanForError(hasRedisStorage, testRedisConnection),
scanForError(isAiTextGenerationEnabled, testOpenAiConnection),
]);
return {
databaseError,
storageError,
redisError,
aiError,
};
});