import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { logsApi, endpointsApi, apiKeysApi } from '@/services/api'; import { Trash2, Eye, Filter, X } from 'lucide-react'; import toast from 'react-hot-toast'; import { format } from 'date-fns'; import Dialog from '@/components/Dialog'; export default function Logs() { const queryClient = useQueryClient(); const [selectedLog, setSelectedLog] = useState(null); const [filters, setFilters] = useState({ endpoint_id: '', api_key_id: '', }); const [dialog, setDialog] = useState<{ isOpen: boolean; title: string; message: string; type: 'alert' | 'confirm'; onConfirm?: () => void; }>({ isOpen: false, title: '', message: '', type: 'alert', }); const { data: logs, isLoading } = useQuery({ queryKey: ['logs', filters], queryFn: () => logsApi.getAll(filters).then(res => res.data), }); const { data: endpoints } = useQuery({ queryKey: ['endpoints'], queryFn: () => endpointsApi.getAll().then(res => res.data), }); const { data: apiKeys } = useQuery({ queryKey: ['apiKeys'], queryFn: () => apiKeysApi.getAll().then(res => res.data), }); const deleteMutation = useMutation({ mutationFn: (id: string) => logsApi.delete(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['logs'] }); toast.success('Лог удален'); }, onError: () => toast.error('Ошибка удаления лога'), }); const clearMutation = useMutation({ mutationFn: (data: any) => logsApi.clear(data), onSuccess: (response) => { queryClient.invalidateQueries({ queryKey: ['logs'] }); toast.success(`Удалено ${response.data.deleted} лог(ов)`); }, onError: () => toast.error('Ошибка очистки логов'), }); const handleClearAll = () => { setDialog({ isOpen: true, title: 'Подтверждение', message: 'Вы уверены, что хотите очистить все логи?', type: 'confirm', onConfirm: () => { clearMutation.mutate({}); }, }); }; const handleClearFiltered = () => { setDialog({ isOpen: true, title: 'Подтверждение', message: 'Вы уверены, что хотите очистить логи с текущими фильтрами?', type: 'confirm', onConfirm: () => { clearMutation.mutate(filters); }, }); }; return (

Логи запросов

История запросов к API эндпоинтам

{Object.values(filters).some(v => v) && ( )}

Фильтры

{Object.values(filters).some(v => v) && ( )}
{isLoading ? (
) : (
{logs?.map((log: any) => (
= 200 && log.response_status < 300 ? 'bg-green-100 text-green-700' : log.response_status >= 400 ? 'bg-red-100 text-red-700' : 'bg-yellow-100 text-yellow-700' }`}> {log.response_status} {log.method} {log.path} {log.endpoint_name && ( → {log.endpoint_name} )}
⏱ {log.execution_time}мс 📅 {format(new Date(log.created_at), 'dd.MM.yyyy HH:mm:ss')} {log.api_key_name && ( 🔑 {log.api_key_name} )} {log.ip_address && log.ip_address !== 'unknown' && ( 📍 {log.ip_address} )}
{log.error_message && (
❌ {log.error_message}
)}
))} {logs?.length === 0 && (

Логи не найдены

)}
)} {selectedLog && ( setSelectedLog(null)} /> )} setDialog({ ...dialog, isOpen: false })} title={dialog.title} message={dialog.message} type={dialog.type} onConfirm={dialog.onConfirm} />
); } function LogDetailModal({ log, onClose }: { log: any; onClose: () => void }) { return (

Детали лога

{log.method}

{log.path}

{log.response_status}

{log.execution_time}мс

{log.endpoint_name || 'N/A'}

{log.api_key_name || 'Без ключа'}

{log.ip_address}

{format(new Date(log.created_at), 'dd.MM.yyyy HH:mm:ss')}

{log.request_params && Object.keys(log.request_params).length > 0 && (
                {JSON.stringify(log.request_params, null, 2)}
              
)} {log.request_body && Object.keys(log.request_body).length > 0 && (
                {JSON.stringify(log.request_body, null, 2)}
              
)}
              {JSON.stringify(log.response_data, null, 2)}
            
{log.error_message && (
{log.error_message}
)} {log.user_agent && log.user_agent !== 'unknown' && (

{log.user_agent}

)}
); }