{/* Logo */}
diff --git a/src/locales/en.json b/src/locales/en.json
index 1b3ec48..4e85c02 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -15,10 +15,12 @@
"yes": "Yes",
"no": "No",
"or": "or",
+ "add": "Add",
"and": "and",
"edit": "Edit",
"delete": "Delete",
- "currency": "$"
+ "currency": "$",
+ "refresh": "Refresh"
},
"nav": {
"dashboard": "Dashboard",
@@ -449,6 +451,7 @@
"wheel": "Wheel",
"tariffs": "Tariffs",
"servers": "Servers",
+ "banSystem": "Ban Monitoring",
"broadcasts": "Broadcasts",
"users": "Users",
"payments": "Payments",
@@ -464,6 +467,7 @@
"wheelDesc": "Configure fortune wheel and prizes",
"tariffsDesc": "Manage tariff plans",
"serversDesc": "Configure VPN servers",
+ "banSystemDesc": "Ban monitoring and violations",
"broadcastsDesc": "Mass messaging to users",
"usersDesc": "Manage bot users",
"paymentsDesc": "Payment verification",
@@ -863,6 +867,283 @@
"noTariffs": "No tariffs"
}
},
+ "banSystem": {
+ "title": "Ban Monitoring",
+ "subtitle": "BedolagaBan system management",
+ "notConfigured": "Ban system is not configured",
+ "configureHint": "Set BAN_SYSTEM_API_URL and BAN_SYSTEM_API_TOKEN in configuration",
+ "loadError": "Failed to load data",
+ "tabs": {
+ "dashboard": "Dashboard",
+ "users": "Users",
+ "punishments": "Bans",
+ "nodes": "Nodes",
+ "agents": "Agents",
+ "violations": "Violations",
+ "traffic": "Traffic",
+ "reports": "Reports",
+ "settings": "Settings",
+ "health": "Health"
+ },
+ "stats": {
+ "activeUsers": "Active Users",
+ "total": "Total",
+ "usersOverLimit": "Over Limit",
+ "activeBans": "Active Bans",
+ "nodesOnline": "Nodes Online",
+ "agentsOnline": "Agents Online",
+ "totalRequests": "Total Requests",
+ "panelStatus": "Panel Status",
+ "connected": "Connected",
+ "disconnected": "Disconnected",
+ "uptime": "Uptime"
+ },
+ "dashboard": {
+ "totalUsers": "Total Users",
+ "activeUsers": "Active Users",
+ "usersOverLimit": "Over Limit",
+ "totalRequests": "Total Requests",
+ "totalPunishments": "Total Punishments",
+ "activePunishments": "Active Bans",
+ "nodesOnline": "Nodes Online",
+ "agentsOnline": "Agents Online",
+ "panelConnected": "Panel Connected",
+ "panelDisconnected": "Panel Disconnected",
+ "uptime": "Uptime"
+ },
+ "users": {
+ "title": "Users",
+ "searchPlaceholder": "Search by email...",
+ "email": "Email",
+ "uniqueIps": "Unique IPs",
+ "ipCount": "IPs",
+ "requests": "Requests",
+ "limit": "Limit",
+ "status": "Status",
+ "bans": "Bans",
+ "lastSeen": "Last Seen",
+ "overLimit": "Over Limit",
+ "ok": "OK",
+ "normal": "Normal",
+ "noLimit": "No Limit",
+ "noUsers": "No users found",
+ "viewDetails": "View Details",
+ "networkType": "Network Type",
+ "filter": {
+ "all": "All",
+ "overLimit": "Over Limit",
+ "normal": "Normal"
+ }
+ },
+ "userDetail": {
+ "title": "User Details",
+ "email": "Email",
+ "uniqueIps": "Unique IPs",
+ "totalRequests": "Total Requests",
+ "limit": "Device Limit",
+ "status": "Status",
+ "networkType": "Network Type",
+ "ipHistory": "IP History",
+ "recentRequests": "Recent Requests",
+ "ip": "IP Address",
+ "firstSeen": "First Seen",
+ "lastSeen": "Last Seen",
+ "node": "Node",
+ "requestCount": "Requests",
+ "requests": "Requests",
+ "country": "Country",
+ "city": "City",
+ "timestamp": "Timestamp",
+ "sourceIp": "Source IP",
+ "destination": "Destination",
+ "port": "Port",
+ "protocol": "Protocol",
+ "action": "Action",
+ "noIps": "No IP data",
+ "noRequests": "No request data",
+ "ban": "Ban",
+ "close": "Close"
+ },
+ "punishments": {
+ "title": "Active Bans",
+ "user": "User",
+ "username": "User",
+ "reason": "Reason",
+ "punishedAt": "Banned At",
+ "bannedAt": "Banned At",
+ "enableAt": "Unban At",
+ "ipCount": "IPs",
+ "limit": "Limit",
+ "node": "Node",
+ "actions": "Actions",
+ "unban": "Unban",
+ "noPunishments": "No active bans",
+ "noBans": "No active bans",
+ "unbanConfirm": "Unban user {{username}}?",
+ "unbanSuccess": "User unbanned",
+ "unbanError": "Unban failed",
+ "history": "Ban History",
+ "searchHistory": "Search history...",
+ "noHistory": "No history found"
+ },
+ "banModal": {
+ "title": "Ban User",
+ "username": "Username",
+ "usernamePlaceholder": "Enter username",
+ "duration": "Duration (minutes)",
+ "durationPlaceholder": "Enter duration in minutes",
+ "reason": "Reason",
+ "reasonPlaceholder": "Enter ban reason (optional)",
+ "cancel": "Cancel",
+ "ban": "Ban",
+ "success": "User banned",
+ "error": "Ban failed"
+ },
+ "nodes": {
+ "title": "Nodes",
+ "name": "Name",
+ "address": "Address",
+ "status": "Status",
+ "lastSeen": "Last Seen",
+ "usersCount": "Users",
+ "users": "Users",
+ "online": "Online",
+ "offline": "Offline",
+ "noNodes": "No nodes found",
+ "total": "Total",
+ "onlineCount": "Online"
+ },
+ "agents": {
+ "title": "Agents",
+ "nodeName": "Node",
+ "node": "Node",
+ "status": "Status",
+ "health": "Health",
+ "sent": "Sent",
+ "dropped": "Dropped",
+ "totalSent": "Total Sent",
+ "totalDropped": "Total Dropped",
+ "batches": "Batches",
+ "reconnects": "Reconnects",
+ "failures": "Failures",
+ "queue": "Queue",
+ "dedup": "Deduplication",
+ "filter": "Filtering",
+ "lastReport": "Last Report",
+ "online": "Online",
+ "offline": "Offline",
+ "healthy": "Healthy",
+ "warning": "Warning",
+ "critical": "Critical",
+ "noAgents": "No agents found",
+ "summary": {
+ "title": "Summary",
+ "totalAgents": "Total Agents",
+ "onlineAgents": "Online",
+ "totalSent": "Total Sent",
+ "totalDropped": "Total Dropped",
+ "avgQueueSize": "Avg Queue Size",
+ "healthyCount": "Healthy",
+ "warningCount": "Warning",
+ "criticalCount": "Critical"
+ }
+ },
+ "violations": {
+ "title": "Traffic Violations",
+ "user": "User",
+ "username": "User",
+ "email": "Email",
+ "type": "Type",
+ "description": "Description",
+ "bytesUsed": "Used",
+ "bytesLimit": "Limit",
+ "detectedAt": "Detected At",
+ "status": "Status",
+ "resolved": "Resolved",
+ "active": "Active",
+ "noViolations": "No violations found",
+ "yes": "Yes",
+ "no": "No"
+ },
+ "traffic": {
+ "title": "Traffic Statistics",
+ "enabled": "Traffic Monitoring",
+ "topUsers": "Top by Traffic",
+ "username": "User",
+ "bytesTotal": "Total",
+ "bytesLimit": "Limit",
+ "status": "Status",
+ "overLimit": "Over Limit",
+ "ok": "OK",
+ "recentViolations": "Recent Violations"
+ },
+ "reports": {
+ "title": "Period Reports",
+ "period": "Period",
+ "currentUsers": "Active Users",
+ "currentIps": "Unique IPs",
+ "topViolators": "Top Violators",
+ "username": "User",
+ "count": "Violations"
+ },
+ "settings": {
+ "title": "System Settings",
+ "general": "General",
+ "limits": "Limits",
+ "notifications": "Notifications",
+ "whitelist": "Whitelist",
+ "saved": "Setting saved",
+ "error": "Error saving",
+ "categories": {
+ "general": "General Settings",
+ "punishment": "Punishments",
+ "progressive_bans": "Progressive Bans",
+ "traffic": "Traffic Monitoring",
+ "network": "Network Detection",
+ "notifications": "Notifications",
+ "rate_limit": "Rate Limits"
+ },
+ "punishment_enabled": "Enable auto-ban",
+ "punishment_minutes": "Ban duration (minutes)",
+ "ip_window_seconds": "IP counting window (seconds)",
+ "notify_on_punishment": "Notify on bans",
+ "notify_on_node_status": "Notify on node status",
+ "daily_report_enabled": "Daily report",
+ "daily_report_hour": "Report hour",
+ "rate_limit_max": "Max requests",
+ "rate_limit_window": "Rate limit window (sec)",
+ "heartbeat_timeout": "Heartbeat timeout (sec)",
+ "progressive_bans_enabled": "Progressive bans",
+ "progressive_ban_1": "1st ban (minutes)",
+ "progressive_ban_2": "2nd ban (minutes)",
+ "progressive_ban_3": "3rd ban (minutes)",
+ "progressive_ban_window_hours": "Reset window (hours)",
+ "traffic_monitor_enabled": "Traffic monitoring",
+ "traffic_limit_gb": "Traffic limit (GB)",
+ "traffic_window_minutes": "Check window (min)",
+ "traffic_check_interval": "Check interval (min)",
+ "traffic_ban_minutes": "Traffic ban (min)",
+ "network_detection_enabled": "Network type detection",
+ "network_detection_nodes": "Detection nodes",
+ "network_detection_monitor_all": "Monitor all nodes",
+ "network_detection_collect_all": "Collect from all nodes",
+ "network_notify_mobile": "Notify on mobile",
+ "network_block_mobile": "Block mobile",
+ "network_block_mobile_minutes": "Block mobile (min)",
+ "network_notify_wifi": "Notify on WiFi",
+ "network_block_wifi": "Block WiFi",
+ "network_block_wifi_minutes": "Block WiFi (min)"
+ },
+ "health": {
+ "title": "System Health",
+ "systemStatus": "System Status",
+ "healthy": "Healthy",
+ "degraded": "Degraded",
+ "unhealthy": "Unhealthy",
+ "components": "Components",
+ "uptime": "Uptime"
+ }
+ },
"profile": {
"title": "Profile",
"accountInfo": "Account Information",
diff --git a/src/locales/ru.json b/src/locales/ru.json
index 94422cc..e46a052 100644
--- a/src/locales/ru.json
+++ b/src/locales/ru.json
@@ -15,10 +15,12 @@
"yes": "Да",
"no": "Нет",
"or": "или",
+ "add": "Добавить",
"and": "и",
"edit": "Редактировать",
"delete": "Удалить",
- "currency": "₽"
+ "currency": "₽",
+ "refresh": "Обновить"
},
"nav": {
"dashboard": "Главная",
@@ -449,6 +451,7 @@
"wheel": "Колесо",
"tariffs": "Тарифы",
"servers": "Серверы",
+ "banSystem": "Мониторинг банов",
"broadcasts": "Рассылки",
"users": "Пользователи",
"payments": "Платежи",
@@ -464,6 +467,7 @@
"wheelDesc": "Настройка колеса удачи и призов",
"tariffsDesc": "Управление тарифными планами",
"serversDesc": "Настройка VPN серверов",
+ "banSystemDesc": "Мониторинг банов и нарушений",
"broadcastsDesc": "Массовая отправка сообщений",
"usersDesc": "Управление пользователями бота",
"paymentsDesc": "Проверка платежей",
@@ -863,6 +867,283 @@
"noTariffs": "Нет тарифов"
}
},
+ "banSystem": {
+ "title": "Мониторинг банов",
+ "subtitle": "Управление системой банов BedolagaBan",
+ "notConfigured": "Ban система не настроена",
+ "configureHint": "Укажите BAN_SYSTEM_API_URL и BAN_SYSTEM_API_TOKEN в конфигурации",
+ "loadError": "Не удалось загрузить данные",
+ "tabs": {
+ "dashboard": "Статистика",
+ "users": "Пользователи",
+ "punishments": "Баны",
+ "nodes": "Ноды",
+ "agents": "Агенты",
+ "violations": "Нарушения",
+ "traffic": "Трафик",
+ "reports": "Отчёты",
+ "settings": "Настройки",
+ "health": "Здоровье"
+ },
+ "stats": {
+ "activeUsers": "Активных пользователей",
+ "total": "Всего",
+ "usersOverLimit": "Превысили лимит",
+ "activeBans": "Активных банов",
+ "nodesOnline": "Нод онлайн",
+ "agentsOnline": "Агентов онлайн",
+ "totalRequests": "Всего запросов",
+ "panelStatus": "Статус панели",
+ "connected": "Подключена",
+ "disconnected": "Отключена",
+ "uptime": "Аптайм"
+ },
+ "dashboard": {
+ "totalUsers": "Всего пользователей",
+ "activeUsers": "Активных пользователей",
+ "usersOverLimit": "Превысили лимит",
+ "totalRequests": "Всего запросов",
+ "totalPunishments": "Всего наказаний",
+ "activePunishments": "Активных банов",
+ "nodesOnline": "Нод онлайн",
+ "agentsOnline": "Агентов онлайн",
+ "panelConnected": "Панель подключена",
+ "panelDisconnected": "Панель отключена",
+ "uptime": "Аптайм"
+ },
+ "users": {
+ "title": "Пользователи",
+ "searchPlaceholder": "Поиск по email...",
+ "email": "Email",
+ "uniqueIps": "Уникальных IP",
+ "ipCount": "IP",
+ "requests": "Запросов",
+ "limit": "Лимит",
+ "status": "Статус",
+ "bans": "Баны",
+ "lastSeen": "Последняя активность",
+ "overLimit": "Превышен лимит",
+ "ok": "OK",
+ "normal": "Норма",
+ "noLimit": "Без лимита",
+ "noUsers": "Пользователи не найдены",
+ "viewDetails": "Подробнее",
+ "networkType": "Тип сети",
+ "filter": {
+ "all": "Все",
+ "overLimit": "Превысили лимит",
+ "normal": "В норме"
+ }
+ },
+ "userDetail": {
+ "title": "Детали пользователя",
+ "email": "Email",
+ "uniqueIps": "Уникальных IP",
+ "totalRequests": "Всего запросов",
+ "limit": "Лимит устройств",
+ "status": "Статус",
+ "networkType": "Тип сети",
+ "ipHistory": "История IP",
+ "recentRequests": "Последние запросы",
+ "ip": "IP адрес",
+ "firstSeen": "Первое подключение",
+ "lastSeen": "Последнее подключение",
+ "node": "Нода",
+ "requestCount": "Запросов",
+ "requests": "Запросов",
+ "country": "Страна",
+ "city": "Город",
+ "timestamp": "Время",
+ "sourceIp": "IP источника",
+ "destination": "Назначение",
+ "port": "Порт",
+ "protocol": "Протокол",
+ "action": "Действие",
+ "noIps": "Нет данных об IP",
+ "noRequests": "Нет данных о запросах",
+ "ban": "Забанить",
+ "close": "Закрыть"
+ },
+ "punishments": {
+ "title": "Активные баны",
+ "user": "Пользователь",
+ "username": "Пользователь",
+ "reason": "Причина",
+ "punishedAt": "Забанен",
+ "bannedAt": "Забанен",
+ "enableAt": "Разбан в",
+ "ipCount": "IP",
+ "limit": "Лимит",
+ "node": "Нода",
+ "actions": "Действия",
+ "unban": "Разбанить",
+ "noPunishments": "Активных банов нет",
+ "noBans": "Активных банов нет",
+ "unbanConfirm": "Разбанить пользователя {{username}}?",
+ "unbanSuccess": "Пользователь разбанен",
+ "unbanError": "Ошибка разбана",
+ "history": "История банов",
+ "searchHistory": "Поиск истории...",
+ "noHistory": "История не найдена"
+ },
+ "banModal": {
+ "title": "Забанить пользователя",
+ "username": "Username",
+ "usernamePlaceholder": "Введите username",
+ "duration": "Длительность (минуты)",
+ "durationPlaceholder": "Введите длительность в минутах",
+ "reason": "Причина",
+ "reasonPlaceholder": "Введите причину бана (опционально)",
+ "cancel": "Отмена",
+ "ban": "Забанить",
+ "success": "Пользователь забанен",
+ "error": "Ошибка бана"
+ },
+ "nodes": {
+ "title": "Ноды",
+ "name": "Название",
+ "address": "Адрес",
+ "status": "Статус",
+ "lastSeen": "Последняя активность",
+ "usersCount": "Пользователей",
+ "users": "Пользователей",
+ "online": "Онлайн",
+ "offline": "Оффлайн",
+ "noNodes": "Ноды не найдены",
+ "total": "Всего",
+ "onlineCount": "Онлайн"
+ },
+ "agents": {
+ "title": "Агенты",
+ "nodeName": "Нода",
+ "node": "Нода",
+ "status": "Статус",
+ "health": "Здоровье",
+ "sent": "Отправлено",
+ "dropped": "Отброшено",
+ "totalSent": "Всего отправлено",
+ "totalDropped": "Всего отброшено",
+ "batches": "Пакетов",
+ "reconnects": "Переподключений",
+ "failures": "Ошибок",
+ "queue": "Очередь",
+ "dedup": "Дедупликация",
+ "filter": "Фильтрация",
+ "lastReport": "Последний отчёт",
+ "online": "Онлайн",
+ "offline": "Оффлайн",
+ "healthy": "Здоровых",
+ "warning": "Предупреждение",
+ "critical": "Критический",
+ "noAgents": "Агенты не найдены",
+ "summary": {
+ "title": "Сводка",
+ "totalAgents": "Всего агентов",
+ "onlineAgents": "Онлайн",
+ "totalSent": "Отправлено",
+ "totalDropped": "Отброшено",
+ "avgQueueSize": "Средний размер очереди",
+ "healthyCount": "Здоровых",
+ "warningCount": "С предупреждениями",
+ "criticalCount": "Критических"
+ }
+ },
+ "violations": {
+ "title": "Нарушения трафика",
+ "user": "Пользователь",
+ "username": "Пользователь",
+ "email": "Email",
+ "type": "Тип",
+ "description": "Описание",
+ "bytesUsed": "Использовано",
+ "bytesLimit": "Лимит",
+ "detectedAt": "Обнаружено",
+ "status": "Статус",
+ "resolved": "Решено",
+ "active": "Активно",
+ "noViolations": "Нарушений не обнаружено",
+ "yes": "Да",
+ "no": "Нет"
+ },
+ "traffic": {
+ "title": "Статистика трафика",
+ "enabled": "Мониторинг трафика",
+ "topUsers": "Топ по трафику",
+ "username": "Пользователь",
+ "bytesTotal": "Всего",
+ "bytesLimit": "Лимит",
+ "status": "Статус",
+ "overLimit": "Превышен",
+ "ok": "OK",
+ "recentViolations": "Последние нарушения"
+ },
+ "reports": {
+ "title": "Отчёты за период",
+ "period": "Период",
+ "currentUsers": "Активных пользователей",
+ "currentIps": "Уникальных IP",
+ "topViolators": "Топ нарушителей",
+ "username": "Пользователь",
+ "count": "Нарушений"
+ },
+ "settings": {
+ "title": "Настройки системы",
+ "general": "Общие",
+ "limits": "Лимиты",
+ "notifications": "Уведомления",
+ "whitelist": "Белый список",
+ "saved": "Настройка сохранена",
+ "error": "Ошибка сохранения",
+ "categories": {
+ "general": "Общие настройки",
+ "punishment": "Наказания",
+ "progressive_bans": "Прогрессивные баны",
+ "traffic": "Мониторинг трафика",
+ "network": "Детекция сети",
+ "notifications": "Уведомления",
+ "rate_limit": "Лимиты запросов"
+ },
+ "punishment_enabled": "Включить автобан",
+ "punishment_minutes": "Длительность бана (минуты)",
+ "ip_window_seconds": "Окно подсчёта IP (секунды)",
+ "notify_on_punishment": "Уведомлять о банах",
+ "notify_on_node_status": "Уведомлять о статусе нод",
+ "daily_report_enabled": "Ежедневный отчёт",
+ "daily_report_hour": "Час отправки отчёта",
+ "rate_limit_max": "Макс. запросов",
+ "rate_limit_window": "Окно лимита (сек)",
+ "heartbeat_timeout": "Таймаут heartbeat (сек)",
+ "progressive_bans_enabled": "Прогрессивные баны",
+ "progressive_ban_1": "1-й бан (минуты)",
+ "progressive_ban_2": "2-й бан (минуты)",
+ "progressive_ban_3": "3-й бан (минуты)",
+ "progressive_ban_window_hours": "Окно сброса (часы)",
+ "traffic_monitor_enabled": "Мониторинг трафика",
+ "traffic_limit_gb": "Лимит трафика (ГБ)",
+ "traffic_window_minutes": "Окно проверки (мин)",
+ "traffic_check_interval": "Интервал проверки (мин)",
+ "traffic_ban_minutes": "Бан за трафик (мин)",
+ "network_detection_enabled": "Детекция типа сети",
+ "network_detection_nodes": "Ноды для детекции",
+ "network_detection_monitor_all": "Мониторить все ноды",
+ "network_detection_collect_all": "Собирать со всех нод",
+ "network_notify_mobile": "Уведомлять о мобильных",
+ "network_block_mobile": "Блокировать мобильные",
+ "network_block_mobile_minutes": "Блок мобильных (мин)",
+ "network_notify_wifi": "Уведомлять о WiFi",
+ "network_block_wifi": "Блокировать WiFi",
+ "network_block_wifi_minutes": "Блок WiFi (мин)"
+ },
+ "health": {
+ "title": "Состояние системы",
+ "systemStatus": "Статус системы",
+ "healthy": "Здорова",
+ "degraded": "Деградация",
+ "unhealthy": "Проблема",
+ "components": "Компоненты",
+ "uptime": "Аптайм"
+ }
+ },
"adminUsers": {
"title": "Пользователи",
"subtitle": "Управление пользователями",
diff --git a/src/pages/AdminApps.tsx b/src/pages/AdminApps.tsx
index 2ff0b12..0a25598 100644
--- a/src/pages/AdminApps.tsx
+++ b/src/pages/AdminApps.tsx
@@ -1,6 +1,7 @@
import { useState, useRef } from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { useTranslation } from 'react-i18next'
+import { Link } from 'react-router-dom'
import {
adminAppsApi,
AppDefinition,
@@ -14,6 +15,12 @@ import {
} from '../api/adminApps'
// Icons
+const BackIcon = () => (
+
+)
+
const AppsIcon = () => (