import { useState } from 'react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { fetchAudit, fetchInstanceGuilds, fetchInstanceSettings, fetchInstanceUsers, instanceAuditQueryKey, instanceGuildsQueryKey, instanceSettingsQueryKey, instanceUsersQueryKey, setInstanceAdmin, type InstanceSettings, } from '@/api/instance'; import { InstanceDashboard } from '@/components/instance/InstanceDashboard'; import { InstanceGuildsPanel } from '@/components/instance/InstanceGuildsPanel'; import { InstanceHealth } from '@/components/instance/InstanceHealth'; import { InstanceLimitsPanel } from '@/components/instance/InstanceLimitsPanel'; import { InstanceUsersPanel } from '@/components/instance/InstanceUsersPanel'; import { useSessionStore } from '@/stores/session'; import { useUiStore } from '@/stores/ui'; import { ErrorNotice, LoadingNotice } from '@/components/ui/ErrorNotice'; import { Card } from '@/components/ui/primitives'; import { formatDateTime } from '@/lib/identity'; import { useCurrentUser } from '@/lib/hooks'; import { useInstanceMetrics } from '@/lib/useInstanceMetrics'; const AUDIT_LIMIT = 50; /** Разделы админ-панели (AGENT.md 7.19). */ const tabs = ['overview', 'limits', 'users', 'guilds', 'audit'] as const; type InstanceTab = (typeof tabs)[number]; /** Админский раздел инстанса: настройки, серверы, пользователи, аудит (read-only). */ export default function InstanceSettingsPage() { const { t, i18n } = useTranslation(); const locale = i18n.resolvedLanguage ?? 'ru'; const currentUser = useCurrentUser(); const isAdmin = currentUser.data?.is_instance_admin === true; const queryClient = useQueryClient(); const selectSettingsGuild = useSessionStore((state) => state.selectSettingsGuild); const openSettings = useUiStore((state) => state.openSettings); const [tab, setTab] = useState('overview'); const settings = useQuery({ queryKey: instanceSettingsQueryKey, queryFn: ({ signal }) => fetchInstanceSettings(signal), enabled: isAdmin, retry: 0, }); const guilds = useQuery({ queryKey: instanceGuildsQueryKey, queryFn: ({ signal }) => fetchInstanceGuilds(signal), enabled: isAdmin, retry: 0, }); const users = useQuery({ queryKey: instanceUsersQueryKey, queryFn: ({ signal }) => fetchInstanceUsers(signal), enabled: isAdmin, retry: 0, }); const audit = useQuery({ queryKey: instanceAuditQueryKey(AUDIT_LIMIT), queryFn: ({ signal }) => fetchAudit(AUDIT_LIMIT, signal), enabled: isAdmin, retry: 0, }); // Живые метрики: опрос раз в секунду, пока раздел открыт (AGENT.md 7.19). const metrics = useInstanceMetrics(isAdmin); const admin = useMutation({ mutationFn: (input: { userId: string; makeAdmin: boolean }) => setInstanceAdmin(input.userId, input.makeAdmin), onSuccess: () => { void queryClient.invalidateQueries({ queryKey: instanceUsersQueryKey }); void queryClient.invalidateQueries({ queryKey: instanceAuditQueryKey(AUDIT_LIMIT) }); }, }); if (!isAdmin) { return (

{t('settings.instance.title')}

{t('settings.instance.notAdmin')}

); } const tabLabels: Record = { overview: t('settings.instance.tabs.overview'), limits: t('settings.instance.tabs.limits'), users: t('settings.instance.tabs.users', { count: users.data?.length ?? 0 }), guilds: t('settings.instance.tabs.guilds', { count: guilds.data?.length ?? 0 }), audit: t('settings.instance.tabs.audit'), }; return (

{t('settings.instance.title')}

{t('settings.instance.description')}

{/* Вкладки админ-панели: обзор и здоровье, лимиты, пользователи, серверы, аудит. */}
{tabs.map((item) => ( ))}
{tab === 'overview' ? ( <> ) : null} {tab === 'limits' ? (

{t('settings.instance.limits.title')}

{t('settings.instance.limits.description')}

{settings.isPending ? : null} {settings.isError ? ( void settings.refetch()} /> ) : null} {settings.data === undefined ? null : ( { void queryClient.setQueryData(instanceSettingsQueryKey, updated); }} /> )}
) : null} {tab === 'users' ? (

{t('settings.instance.usersTitle')}

{/* ID пользователей — единственное место, где он виден: раздел открыт только администратору инстанса. */}

{t('settings.instance.usersIdHint')}

void users.refetch()} onToggleAdmin={(userId, makeAdmin) => admin.mutate({ userId, makeAdmin })} adminPending={admin.isPending} adminError={admin.error} />
) : null} {tab === 'guilds' ? (

{t('settings.instance.guildsTitle')}

void guilds.refetch()} onOpenSettings={(guildId) => { // Настройки сервера открываются обычным разделом: у администратора // инстанса там все права (AGENTS.md 7.19). selectSettingsGuild(guildId); openSettings({ section: 'server', guildId }); }} />
) : null} {tab === 'audit' ? (

{t('settings.instance.audit', { count: audit.data?.length ?? 0 })}

{audit.isPending ? : null} {audit.isError ? ( void audit.refetch()} /> ) : null} {audit.data !== undefined && audit.data.length === 0 ? (

{t('settings.instance.auditEmpty')}

) : null} {audit.data === undefined || audit.data.length === 0 ? null : (
    {audit.data.map((entry) => (
  • {entry.action} {entry.target === undefined ? '' : ` → ${entry.target}`} {formatDateTime(entry.created_at, locale)}
  • ))}
)}
) : null}
); }