'use client'; import { ComponentProps, ReactNode, } from 'react'; import ChecklistRow from '../components/ChecklistRow'; import { BiData, BiHide, BiLockAlt, BiPencil, } from 'react-icons/bi'; import { HiOutlineCog } from 'react-icons/hi'; import ChecklistGroup from '@/components/ChecklistGroup'; import { ConfigChecklistStatus } from '../app/config'; import StatusIcon from '@/components/StatusIcon'; import { labelForStorage } from '@/platforms/storage'; import { HiSparkles } from 'react-icons/hi'; import { testConnectionsAction } from '@/admin/actions'; import ErrorNote from '@/components/ErrorNote'; import WarningNote from '@/components/WarningNote'; import { RiSpeedMiniLine } from 'react-icons/ri'; import SecretGenerator from '../app/SecretGenerator'; import { PiPaintBrushHousehold } from 'react-icons/pi'; import { IoMdGrid } from 'react-icons/io'; import { CgDebug } from 'react-icons/cg'; import EnvVar from '@/components/EnvVar'; import AdminLink from './AdminLink'; import ScoreCardContainer from '@/components/ScoreCardContainer'; export default function AdminAppConfigurationClient({ // Storage hasDatabase, isPostgresSslEnabled, hasVercelPostgres, hasRedisStorage, hasStorageProvider, hasVercelBlobStorage, hasCloudflareR2Storage, hasAwsS3Storage, hasMultipleStorageProviders, currentStorage, // Auth hasAuthSecret, hasAdminUser, // Content hasDomain, hasTitle, hasDescription, hasAbout, // AI isAiTextGenerationEnabled, aiTextAutoGeneratedFields, hasAiTextAutoGeneratedFields, // Performance isStaticallyOptimized, arePhotosStaticallyOptimized, arePhotoOGImagesStaticallyOptimized, arePhotoCategoriesStaticallyOptimized, arePhotoCategoryOgImagesStaticallyOptimized, areOriginalUploadsPreserved, imageQuality, hasImageQuality, isBlurEnabled, // Visual hasDefaultTheme, defaultTheme, arePhotosMatted, // Display showExifInfo, showZoomControls, showTakenAtTimeHidden, showSocial, showFilmSimulations, showRecipes, showRepoLink, // Grid isGridHomepageEnabled, gridAspectRatio, hasGridAspectRatio, hasHighGridDensity, hasGridDensityPreference, // Settings isGeoPrivacyEnabled, arePublicDownloadsEnabled, isPublicApiEnabled, isPriorityOrderEnabled, isOgTextBottomAligned, // Internal areInternalToolsEnabled, areAdminDebugToolsEnabled, isAdminDbOptimizeEnabled, isAdminSqlDebugEnabled, // Misc baseUrl, // Connection status databaseError, storageError, redisError, aiError, // Component props simplifiedView, isAnalyzingConfiguration, }: ConfigChecklistStatus & Partial>> & { simplifiedView?: boolean isAnalyzingConfiguration?: boolean }) { const renderEnvVars = (variables: string[]) =>
{variables.map(envVar => )}
; const renderSubStatus = ( type: ComponentProps['type'], label: ReactNode, iconClassName = 'translate-y-[3.5px]', ) =>
{label}
; const renderSubStatusWithEnvVar = ( type: ComponentProps['type'], variable: string, ) => renderSubStatus( type, renderEnvVars([variable]), 'translate-y-[4.5px]', ); const renderError = ({ connection, message, }: { connection?: { provider: string, error: string } message?: string }) => {connection && <> {connection.provider} connection error: {`"${connection.error}"`} } {message} ; const renderWarning = ({ connection, message, }: { connection?: { provider: string, error: string } message?: string }) => {connection && <> {connection.provider} connection error: {`"${connection.error}"`} } {message} ; return ( } > {databaseError && renderError({ connection: { provider: 'Database', error: databaseError}, })} {hasVercelPostgres ? renderSubStatus('checked', 'Vercel Postgres: connected') : renderSubStatus('optional', <> Vercel Postgres: {' '} create store {' '} and connect to project )} {hasDatabase && !hasVercelPostgres && renderSubStatus('checked', <> Postgres-compatible: connected {' '} (SSL {isPostgresSslEnabled ? 'enabled' : 'disabled'}) )} {storageError && renderError({ connection: { provider: 'Storage', error: storageError}, })} {hasVercelBlobStorage ? renderSubStatus('checked', 'Vercel Blob: connected') : renderSubStatus('optional', <> {labelForStorage('vercel-blob')}: {' '} create store {' '} and connect to project , )} {hasCloudflareR2Storage ? renderSubStatus('checked', 'Cloudflare R2: connected') : renderSubStatus('optional', <> {labelForStorage('cloudflare-r2')}: {' '} create/configure bucket )} {hasAwsS3Storage ? renderSubStatus('checked', 'AWS S3: connected') : renderSubStatus('optional', <> {labelForStorage('aws-s3')}: {' '} create/configure bucket )} } > Store auth secret in environment variable: {!hasAuthSecret &&
} {renderEnvVars(['AUTH_SECRET'])}
Store admin email/password {' '} in environment variables: {renderEnvVars([ 'ADMIN_EMAIL', 'ADMIN_PASSWORD', ])}
} > {!hasDomain && renderWarning({message: 'Not explicitly setting a domain may cause ' + 'certain features to behave unexpectedly', })} Store in environment variable (seen in top-right nav): {renderEnvVars(['NEXT_PUBLIC_SITE_DOMAIN'])} Store in environment variable (seen in browser tab): {renderEnvVars(['NEXT_PUBLIC_SITE_TITLE'])} Store in environment variable (seen in nav, under title): {renderEnvVars(['NEXT_PUBLIC_SITE_DESCRIPTION'])} Store in environment variable (seen in grid sidebar): {renderEnvVars(['NEXT_PUBLIC_SITE_ABOUT'])} {!simplifiedView && <> } optional > {aiError && renderError({ connection: { provider: 'OpenAI', error: aiError}, })} Store your OpenAI secret key in order to enable AI-generated text descriptions and optionally leverage an invisible field called {'"Semantic Description"'} used to support CMD-K search and improve accessibility: {renderEnvVars(['OPENAI_SECRET_KEY'])} {redisError && renderError({ connection: { provider: 'Redis', error: redisError}, })} Create Upstash Redis store from storage tab on Vercel dashboard and connect to this project to enable rate limiting Comma-separated fields to auto-generate when uploading photos. Accepted values: title, caption, tags, description, all, or none {' '} (default: {'"title, tags, semantic"'}): {renderEnvVars(['AI_TEXT_AUTO_GENERATED_FIELDS'])} } optional > Set environment variable to {'"1"'} to make site more responsive by enabling static optimization (i.e., rendering pages and images at build time): {renderSubStatusWithEnvVar( arePhotosStaticallyOptimized ? 'checked' : 'optional', 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTOS', )} {renderSubStatusWithEnvVar( arePhotoOGImagesStaticallyOptimized ? 'checked' : 'optional', 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_OG_IMAGES', )} {renderSubStatusWithEnvVar( arePhotoCategoriesStaticallyOptimized ? 'checked' : 'optional', 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORIES', )} {renderSubStatusWithEnvVar( // eslint-disable-next-line max-len arePhotoCategoryOgImagesStaticallyOptimized ? 'checked' : 'optional', 'NEXT_PUBLIC_STATICALLY_OPTIMIZE_PHOTO_CATEGORY_OG_IMAGES', )} Set environment variable to {'"1"'} to prevent image uploads being compressed before storing: {renderEnvVars(['NEXT_PUBLIC_PRESERVE_ORIGINAL_UPLOADS'])} Set environment variable from {'"1-100"'} {' '} to control the quality of large photos ({'"100"'} represents highest quality/largest size): {renderEnvVars(['NEXT_PUBLIC_IMAGE_QUALITY'])} Set environment variable to {'"1"'} to prevent image blur data being stored and displayed: {renderEnvVars(['NEXT_PUBLIC_BLUR_DISABLED'])} } optional > {'Set environment variable to \'light\' or \'dark\''} {' '} to configure initial theme {' '} (defaults to {'\'system\''}): {renderEnvVars(['NEXT_PUBLIC_DEFAULT_THEME'])} Set environment variable to {'"1"'} to constrain the size {' '} of each photo, and display a surrounding border: {renderEnvVars(['NEXT_PUBLIC_MATTE_PHOTOS'])} } optional > Set environment variable to {'"1"'} to hide EXIF data: {renderEnvVars(['NEXT_PUBLIC_HIDE_EXIF_DATA'])} Set environment variable to {'"1"'} to hide fullscreen photo zoom controls: {renderEnvVars(['NEXT_PUBLIC_HIDE_ZOOM_CONTROLS'])} Set environment variable to {'"1"'} to hide taken at time from photo meta: {renderEnvVars(['NEXT_PUBLIC_HIDE_TAKEN_AT_TIME'])} Set environment variable to {'"1"'} to hide {' '} X (formerly Twitter) button from share modal: {renderEnvVars(['NEXT_PUBLIC_HIDE_SOCIAL'])} Set environment variable to {'"1"'} to prevent simulations showing up in /grid sidebar and CMD-K results: {renderEnvVars(['NEXT_PUBLIC_HIDE_FILM_SIMULATIONS'])} Set environment variable to {'"1"'} to prevent Fujifilm recipe button showing up in photo meta: {renderEnvVars(['NEXT_PUBLIC_HIDE_RECIPES'])} Set environment variable to {'"1"'} to hide footer link: {renderEnvVars(['NEXT_PUBLIC_HIDE_REPO_LINK'])} } optional > Set environment variable to {'"1"'} to show grid layout on homepage: {renderEnvVars(['NEXT_PUBLIC_GRID_HOMEPAGE'])} Set environment variable to any number to enforce aspect ratio {' '} (default is {'"1"'}, i.e., square)—set to {'"0"'} to disable: {renderEnvVars(['NEXT_PUBLIC_GRID_ASPECT_RATIO'])} Set environment variable to {'"1"'} to ensure large thumbnails on photo grid views (if not configured, density is based on aspect ratio): {renderEnvVars(['NEXT_PUBLIC_SHOW_LARGE_THUMBNAILS'])} } optional > Set environment variable to {'"1"'} to disable collection/display of location-based data: {renderEnvVars(['NEXT_PUBLIC_GEO_PRIVACY'])} Set environment variable to {'"1"'} to enable public photo downloads for all visitors: {renderEnvVars(['NEXT_PUBLIC_ALLOW_PUBLIC_DOWNLOADS'])} Set environment variable to {'"1"'} to enable a public API available at /api: {renderEnvVars(['NEXT_PUBLIC_PUBLIC_API'])} Set environment variable to {'"1"'} to prevent priority order photo field affecting photo order: {renderEnvVars(['NEXT_PUBLIC_IGNORE_PRIORITY_ORDER'])} Set environment variable to {'"BOTTOM"'} to keep OG image text bottom aligned (default is {'"top"'}): {renderEnvVars(['NEXT_PUBLIC_OG_TEXT_ALIGNMENT'])} {areInternalToolsEnabled && } optional > Set environment variable to {'"1"'} to temporarily enable features like photo matting, baseline grid, etc.: {renderEnvVars(['ADMIN_DEBUG_TOOLS'])} Set environment variable to {'"1"'} to prevent homepages from seeding infinite scroll on load: {renderEnvVars(['ADMIN_DB_OPTIMIZE'])} Set environment variable to {'"1"'} to enable console output for all sql queries: {renderEnvVars(['ADMIN_SQL_DEBUG'])} } }
Changes to environment variables require a redeploy or reboot of local dev server
{!simplifiedView &&
Domain    {baseUrl || 'Not Defined'}
}
); }