'use client'; import { useEffect } from 'react'; import { zodResolver } from '@hookform/resolvers/zod'; import { CircleHelp, TriangleAlert } from 'lucide-react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Button } from '@/components/ui/button'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from '@/components/ui/form'; import { Popover, PopoverContent, PopoverTrigger, } from '@/components/ui/popover'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Switch } from '@/components/ui/switch'; import { Textarea } from '@/components/ui/textarea'; import type { ProxyRouteItem } from '@/lib/services/openflare'; import { useTranslations } from 'next-intl'; import { linesFromTextarea, validateCacheRules, } from '../../components/helpers'; import { proxyRouteFormIds } from '../helpers'; import { useRouteSectionSave } from '../hooks/use-route-section-save'; import { SectionShell } from './section-shell'; type CacheValues = { cache_enabled: boolean; cache_policy: 'static' | 'all' | 'suffix' | 'path_prefix' | 'path_exact'; cache_rules_text: string; }; interface CacheSectionProps { route: ProxyRouteItem; onRouteUpdate: (route: ProxyRouteItem) => void; onSavingChange?: (saving: boolean) => void; } /** Map API/DB values for the form. Legacy empty/url → all (compat). */ function normalizeCachePolicyValue( policy: string | undefined | null, enabled = true, ) { if (!enabled) { return 'static'; } const value = (policy || '').trim(); if (!value || value === 'url' || value === 'all') return 'all'; if (value === 'static') return 'static'; if (value === 'suffix' || value === 'path_prefix' || value === 'path_exact') { return value; } return 'static'; } function needsRulesForPolicy(policy: string) { return ( policy === 'suffix' || policy === 'path_prefix' || policy === 'path_exact' ); } function CacheHelpButton() { const t = useTranslations('proxyRoutes'); return (
{t('cacheHelpTitle')}

{t('cacheHelpIntro')}

{t('cacheHelpRecommendLabel')} {t('cacheHelpRecommend')}

{t('cacheHelpGeneralLabel')} {t('cacheHelpGeneral')}

{t('cacheHelpAllGetLabel')} {t('cacheHelpAllGet')}

{t('cacheHelpCustomLabel')} {t('cacheHelpCustom')}

); } export function CacheSection({ route, onRouteUpdate, onSavingChange, }: CacheSectionProps) { const t = useTranslations('proxyRoutes'); const cacheSchema = z .object({ cache_enabled: z.boolean(), cache_policy: z.enum([ 'static', 'all', 'suffix', 'path_prefix', 'path_exact', ]), cache_rules_text: z.string(), }) .superRefine((value, context) => { if (!value.cache_enabled) { return; } const rules = linesFromTextarea(value.cache_rules_text); const error = validateCacheRules(value.cache_policy, rules, t); if (error) { context.addIssue({ code: z.ZodIssueCode.custom, path: ['cache_rules_text'], message: error, }); } }); const { saving, save } = useRouteSectionSave( route, onRouteUpdate, onSavingChange, ); const form = useForm({ resolver: zodResolver(cacheSchema), defaultValues: { cache_enabled: route.cache_enabled, cache_policy: normalizeCachePolicyValue( route.cache_policy, route.cache_enabled, ) as CacheValues['cache_policy'], cache_rules_text: route.cache_rule_list.join('\n'), }, }); useEffect(() => { form.reset({ cache_enabled: route.cache_enabled, cache_policy: normalizeCachePolicyValue( route.cache_policy, route.cache_enabled, ) as CacheValues['cache_policy'], cache_rules_text: route.cache_rule_list.join('\n'), }); }, [form, route]); const watchedEnabled = form.watch('cache_enabled'); const watchedPolicy = form.watch('cache_policy'); const needsRules = watchedPolicy === 'suffix' || watchedPolicy === 'path_prefix' || watchedPolicy === 'path_exact'; const rulesHint = watchedPolicy === 'suffix' ? t('cacheHintSuffix') : watchedPolicy === 'path_prefix' ? t('cacheHintPrefix') : watchedPolicy === 'path_exact' ? t('cacheHintExact') : watchedPolicy === 'static' ? t('cacheHintStatic') : t('cacheHintNone'); const rulesPlaceholder = watchedPolicy === 'suffix' ? 'jpg\ncss\njs' : watchedPolicy === 'path_prefix' ? '/assets\n/static' : watchedPolicy === 'path_exact' ? '/robots.txt\n/manifest.json' : t('cachePlaceholderNone'); return ( } formId={proxyRouteFormIds.cache} saving={saving} >
{ const rules = linesFromTextarea(values.cache_rules_text); await save( { cache_enabled: values.cache_enabled, cache_policy: values.cache_enabled ? values.cache_policy : '', cache_rules: values.cache_enabled && needsRulesForPolicy(values.cache_policy) ? rules : [], }, t('cacheSaved'), ); })} > (
{t('enableCache')} {t('enableCacheDesc')}
)} /> ( {t('cachePolicy')} )} /> {watchedEnabled && watchedPolicy === 'all' ? ( {t('advancedRiskTitle')} {t('advancedRiskDesc')} ) : null} ( {t('cacheRules')}