Add Anthropic API, test environment, remove locale settings
Feature 1: Anthropic API Integration - Add @anthropic-ai/sdk with adapter wrapping OpenAI-shaped interface - Support Claude models (opus, sonnet, haiku) with extended thinking - Auto-reset model on provider switch, JSON retry logic - Add Claude model pricing to ai-usage tracker - Update AI settings form with Anthropic provider option Feature 2: Remove Locale Settings UI - Strip Localization tab from admin settings - Remove i18n settings from router inferCategory and getFeatureFlags - Keep franc document language detection intact Feature 3: Test Environment with Role Impersonation - Add isTest field to User, Program, Project, Competition models - Test environment service: create/teardown with realistic dummy data - JWT-based impersonation for test users (@test.local emails) - Impersonation banner with quick-switch between test roles - Test environment panel in admin settings (SUPER_ADMIN only) - Email redirect: @test.local emails routed to admin with [TEST] prefix - Complete data isolation: 45+ isTest:false filters across platform - All global queries on User/Project/Program/Competition - AI services blocked from processing test data - Cron jobs skip test rounds/users - Analytics/exports exclude test data - Admin layout/pickers hide test programs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -226,7 +226,8 @@ export function AdminSidebar({ user }: AdminSidebarProps) {
|
||||
{navigation.map((item) => {
|
||||
const isActive =
|
||||
pathname === item.href ||
|
||||
(item.href !== '/admin' && pathname.startsWith(item.href))
|
||||
(item.href !== '/admin' && pathname.startsWith(item.href)) ||
|
||||
(item.href === '/admin/rounds' && pathname.startsWith('/admin/competitions'))
|
||||
return (
|
||||
<div key={item.name}>
|
||||
<Link
|
||||
@@ -258,12 +259,24 @@ export function AdminSidebar({ user }: AdminSidebarProps) {
|
||||
Administration
|
||||
</p>
|
||||
{dynamicAdminNav.map((item) => {
|
||||
const isDisabled = item.name === 'Apply Page' && !currentEdition?.id
|
||||
let isActive = pathname.startsWith(item.href)
|
||||
if (item.activeMatch) {
|
||||
isActive = pathname.includes(item.activeMatch)
|
||||
} else if (item.activeExclude && pathname.includes(item.activeExclude)) {
|
||||
isActive = false
|
||||
}
|
||||
if (isDisabled) {
|
||||
return (
|
||||
<span
|
||||
key={item.name}
|
||||
className="group flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium opacity-50 pointer-events-none text-muted-foreground"
|
||||
>
|
||||
<item.icon className="h-4 w-4 text-muted-foreground" />
|
||||
{item.name}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Link
|
||||
key={item.name}
|
||||
|
||||
Reference in New Issue
Block a user