fix: home
This commit is contained in:
@@ -8,7 +8,7 @@ interface ProtectedRouteProps {
|
|||||||
|
|
||||||
export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({
|
export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({
|
||||||
children,
|
children,
|
||||||
fallbackPath = "/",
|
fallbackPath = "/auth",
|
||||||
}) => {
|
}) => {
|
||||||
const isAuthenticated = authService.isAuthenticated();
|
const isAuthenticated = authService.isAuthenticated();
|
||||||
|
|
||||||
|
|||||||
@@ -17,16 +17,13 @@ export const Routing = () => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ReactRoutes>
|
<ReactRoutes>
|
||||||
<Route path="/" element={<AuthPage />} />
|
<Route path="/" element={<HomePage />} />
|
||||||
|
<Route path="/auth" element={<AuthPage />} />
|
||||||
<Route
|
<Route
|
||||||
path="/create-organization"
|
path="/create-organization"
|
||||||
element={<CreateOrganizationPage />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="/home"
|
|
||||||
element={
|
element={
|
||||||
<ProtectedRoute>
|
<ProtectedRoute>
|
||||||
<HomePage />
|
<CreateOrganizationPage />
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import type {
|
|||||||
LoginCredentials,
|
LoginCredentials,
|
||||||
RegisterData,
|
RegisterData,
|
||||||
OrganizationCreateData,
|
OrganizationCreateData,
|
||||||
OrganizationMember,
|
|
||||||
} from "../types/auth.types";
|
} from "../types/auth.types";
|
||||||
|
|
||||||
export const useAuth = () => {
|
export const useAuth = () => {
|
||||||
@@ -24,7 +23,7 @@ export const useAuth = () => {
|
|||||||
const orgs = await request(() => authService.getOrganizations());
|
const orgs = await request(() => authService.getOrganizations());
|
||||||
if (orgs && orgs.length > 0) {
|
if (orgs && orgs.length > 0) {
|
||||||
authService.saveOrganization(orgs[0]);
|
authService.saveOrganization(orgs[0]);
|
||||||
navigate("/home");
|
navigate("/");
|
||||||
} else {
|
} else {
|
||||||
navigate("/create-organization");
|
navigate("/create-organization");
|
||||||
}
|
}
|
||||||
@@ -58,7 +57,7 @@ export const useAuth = () => {
|
|||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
authService.saveOrganization(result);
|
authService.saveOrganization(result);
|
||||||
navigate("/home");
|
navigate("/");
|
||||||
} else if (error) {
|
} else if (error) {
|
||||||
setAuthError(error);
|
setAuthError(error);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-2
@@ -1,17 +1,30 @@
|
|||||||
import { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
import { ThemeToggle } from "@/modules/theme-changer/ui/Theme.toggle";
|
import { ThemeToggle } from "@/modules/theme-changer/ui/Theme.toggle";
|
||||||
import { LoginForm } from "@/modules/auth/components/LoginForm";
|
import { LoginForm } from "@/modules/auth/components/LoginForm";
|
||||||
import { RegisterForm } from "@/modules/auth/components/RegisterForm";
|
import { RegisterForm } from "@/modules/auth/components/RegisterForm";
|
||||||
|
|
||||||
export const AuthPage = () => {
|
export const AuthPage = () => {
|
||||||
const [isLogin, setIsLogin] = useState(true);
|
const [isLogin, setIsLogin] = useState(true);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="min-h-screen flex items-center justify-center p-4 transition-theme"
|
className="min-h-screen flex items-center justify-center p-4 transition-theme"
|
||||||
style={{ backgroundColor: "var(--bg-primary)" }}
|
style={{ backgroundColor: "var(--bg-primary)" }}
|
||||||
>
|
>
|
||||||
<div className="absolute top-4 right-4">
|
<div className="absolute top-4 right-4 flex gap-4">
|
||||||
|
<button
|
||||||
|
onClick={() => navigate("/")}
|
||||||
|
className="px-4 py-2 rounded-lg font-medium transition-all hover:scale-105"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "var(--bg-secondary)",
|
||||||
|
color: "var(--text-primary)",
|
||||||
|
border: `1px solid var(--border)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
На главную
|
||||||
|
</button>
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+505
-320
@@ -6,7 +6,6 @@ import {
|
|||||||
Shield,
|
Shield,
|
||||||
Users,
|
Users,
|
||||||
Bot,
|
Bot,
|
||||||
Settings,
|
|
||||||
Activity,
|
Activity,
|
||||||
LogOut,
|
LogOut,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
@@ -20,11 +19,14 @@ import {
|
|||||||
AlertCircle,
|
AlertCircle,
|
||||||
CheckCircle,
|
CheckCircle,
|
||||||
Clock,
|
Clock,
|
||||||
|
LogIn,
|
||||||
|
UserPlus,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
export const HomePage = () => {
|
export const HomePage = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { logout } = useAuth();
|
const { logout } = useAuth();
|
||||||
|
const isAuthenticated = authService.isAuthenticated();
|
||||||
const organization = authService.getCurrentOrganization();
|
const organization = authService.getCurrentOrganization();
|
||||||
const authStorage = localStorage.getItem("auth-storage");
|
const authStorage = localStorage.getItem("auth-storage");
|
||||||
const user = authStorage ? JSON.parse(authStorage).state?.user : null;
|
const user = authStorage ? JSON.parse(authStorage).state?.user : null;
|
||||||
@@ -72,37 +74,66 @@ export const HomePage = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const quickActions = [
|
const features = [
|
||||||
{
|
{
|
||||||
name: "IPS Агенты",
|
title: "Централизованное управление",
|
||||||
|
description: "Управляйте всеми IPS агентами из единого интерфейса",
|
||||||
icon: Server,
|
icon: Server,
|
||||||
path: "/agents",
|
|
||||||
description: "Управление агентами",
|
|
||||||
color: "#6366f1",
|
color: "#6366f1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Правила",
|
title: "AI Аналитика",
|
||||||
icon: Shield,
|
description: "Искусственный интеллект помогает находить сложные атаки",
|
||||||
path: "/rules",
|
|
||||||
description: "Правила фильтрации",
|
|
||||||
color: "#22c55e",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "AI Аналитика",
|
|
||||||
icon: Bot,
|
icon: Bot,
|
||||||
path: "/ai-analytics",
|
|
||||||
description: "Анализ логов",
|
|
||||||
color: "#8b5cf6",
|
color: "#8b5cf6",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Команда",
|
title: "Мгновенная блокировка",
|
||||||
icon: Users,
|
description: "Автоматическая блокировка IP при обнаружении угроз",
|
||||||
path: "/organization",
|
icon: Zap,
|
||||||
description: "Управление доступом",
|
|
||||||
color: "#f59e0b",
|
color: "#f59e0b",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Безопасность данных",
|
||||||
|
description: "LLM не получает доступ к чувствительным логам",
|
||||||
|
icon: Lock,
|
||||||
|
color: "#22c55e",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const quickActions = isAuthenticated
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
name: "IPS Агенты",
|
||||||
|
icon: Server,
|
||||||
|
path: "/agents",
|
||||||
|
description: "Управление агентами",
|
||||||
|
color: "#6366f1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Правила",
|
||||||
|
icon: Shield,
|
||||||
|
path: "/rules",
|
||||||
|
description: "Правила фильтрации",
|
||||||
|
color: "#22c55e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AI Аналитика",
|
||||||
|
icon: Bot,
|
||||||
|
path: "/ai-analytics",
|
||||||
|
description: "Анализ логов",
|
||||||
|
color: "#8b5cf6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Команда",
|
||||||
|
icon: Users,
|
||||||
|
path: "/organization",
|
||||||
|
description: "Управление доступом",
|
||||||
|
color: "#f59e0b",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
const getSeverityStyles = (severity: string) => {
|
const getSeverityStyles = (severity: string) => {
|
||||||
switch (severity) {
|
switch (severity) {
|
||||||
case "high":
|
case "high":
|
||||||
@@ -169,54 +200,88 @@ export const HomePage = () => {
|
|||||||
|
|
||||||
{/* Right section */}
|
{/* Right section */}
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<button
|
{isAuthenticated ? (
|
||||||
className="relative p-2 rounded-lg transition-all hover:scale-105"
|
<>
|
||||||
style={{ backgroundColor: "var(--bg-secondary)" }}
|
<button
|
||||||
>
|
className="relative p-2 rounded-lg transition-all hover:scale-105"
|
||||||
<Bell
|
style={{ backgroundColor: "var(--bg-secondary)" }}
|
||||||
className="w-5 h-5"
|
|
||||||
style={{ color: "var(--text-secondary)" }}
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
className="absolute top-1 right-1 w-2 h-2 rounded-full"
|
|
||||||
style={{ backgroundColor: "#ef4444" }}
|
|
||||||
></span>
|
|
||||||
</button>
|
|
||||||
<ThemeToggle />
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div
|
|
||||||
className="w-10 h-10 rounded-full flex items-center justify-center font-semibold text-white"
|
|
||||||
style={{ backgroundColor: "var(--accent)" }}
|
|
||||||
>
|
|
||||||
{user?.first_name?.[0]}
|
|
||||||
{user?.last_name?.[0]}
|
|
||||||
</div>
|
|
||||||
<div className="hidden md:block">
|
|
||||||
<p
|
|
||||||
className="text-sm font-medium"
|
|
||||||
style={{ color: "var(--text-primary)" }}
|
|
||||||
>
|
>
|
||||||
{user?.first_name} {user?.last_name}
|
<Bell
|
||||||
</p>
|
className="w-5 h-5"
|
||||||
<p className="text-xs" style={{ color: "var(--text-muted)" }}>
|
style={{ color: "var(--text-secondary)" }}
|
||||||
Администратор
|
/>
|
||||||
</p>
|
<span
|
||||||
</div>
|
className="absolute top-1 right-1 w-2 h-2 rounded-full"
|
||||||
</div>
|
style={{ backgroundColor: "#ef4444" }}
|
||||||
<button
|
></span>
|
||||||
onClick={logout}
|
</button>
|
||||||
className="p-2 rounded-lg transition-all hover:scale-105"
|
<ThemeToggle />
|
||||||
style={{ backgroundColor: "#ef4444" }}
|
<div className="flex items-center gap-3">
|
||||||
>
|
<div
|
||||||
<LogOut className="w-5 h-5 text-white" />
|
className="w-10 h-10 rounded-full flex items-center justify-center font-semibold text-white"
|
||||||
</button>
|
style={{ backgroundColor: "var(--accent)" }}
|
||||||
|
>
|
||||||
|
{user?.first_name?.[0]}
|
||||||
|
{user?.last_name?.[0]}
|
||||||
|
</div>
|
||||||
|
<div className="hidden md:block">
|
||||||
|
<p
|
||||||
|
className="text-sm font-medium"
|
||||||
|
style={{ color: "var(--text-primary)" }}
|
||||||
|
>
|
||||||
|
{user?.first_name} {user?.last_name}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
className="text-xs"
|
||||||
|
style={{ color: "var(--text-muted)" }}
|
||||||
|
>
|
||||||
|
Администратор
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={logout}
|
||||||
|
className="p-2 rounded-lg transition-all hover:scale-105"
|
||||||
|
style={{ backgroundColor: "#ef4444" }}
|
||||||
|
>
|
||||||
|
<LogOut className="w-5 h-5 text-white" />
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<ThemeToggle />
|
||||||
|
<button
|
||||||
|
onClick={() => navigate("/auth")}
|
||||||
|
className="px-4 py-2 rounded-lg font-medium transition-all flex items-center gap-2 hover:scale-105"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "var(--bg-secondary)",
|
||||||
|
color: "var(--text-primary)",
|
||||||
|
border: `1px solid var(--border)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LogIn className="w-4 h-4" />
|
||||||
|
Войти
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => navigate("/auth")}
|
||||||
|
className="px-4 py-2 rounded-lg font-medium transition-all flex items-center gap-2 hover:scale-105"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "var(--accent)",
|
||||||
|
color: "white",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<UserPlus className="w-4 h-4" />
|
||||||
|
Регистрация
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main className="container mx-auto px-6 py-8">
|
<main className="container mx-auto px-6 py-8">
|
||||||
{/* Welcome Section */}
|
{/* Hero Section */}
|
||||||
<div
|
<div
|
||||||
className="rounded-2xl p-8 mb-8 text-white relative overflow-hidden"
|
className="rounded-2xl p-8 mb-8 text-white relative overflow-hidden"
|
||||||
style={{
|
style={{
|
||||||
@@ -227,17 +292,36 @@ export const HomePage = () => {
|
|||||||
<div className="flex justify-between items-start">
|
<div className="flex justify-between items-start">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-3xl font-bold mb-2">
|
<h2 className="text-3xl font-bold mb-2">
|
||||||
Добро пожаловать, {user?.first_name || "Администратор"}!
|
{isAuthenticated
|
||||||
|
? `Добро пожаловать, ${user?.first_name || "Администратор"}!`
|
||||||
|
: "Добро пожаловать в IPS Manager"}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-white/80 text-lg">
|
<p className="text-white/80 text-lg">
|
||||||
Система IPS мониторинга и защиты
|
{isAuthenticated
|
||||||
|
? "Система IPS мониторинга и защиты"
|
||||||
|
: "Современная платформа для централизованного управления IPS агентами"}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-2 mt-4">
|
{!isAuthenticated && (
|
||||||
<Zap className="w-5 h-5" />
|
<div className="flex gap-4 mt-6">
|
||||||
<span className="text-white/90">
|
<button
|
||||||
Все системы работают стабильно
|
onClick={() => navigate("/auth")}
|
||||||
</span>
|
className="px-6 py-2 rounded-lg font-medium bg-white text-indigo-600 transition-all hover:scale-105 hover:shadow-lg"
|
||||||
</div>
|
>
|
||||||
|
Начать работу
|
||||||
|
</button>
|
||||||
|
<button className="px-6 py-2 rounded-lg font-medium border border-white/30 transition-all hover:bg-white/10">
|
||||||
|
Узнать больше
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isAuthenticated && (
|
||||||
|
<div className="flex items-center gap-2 mt-4">
|
||||||
|
<Zap className="w-5 h-5" />
|
||||||
|
<span className="text-white/90">
|
||||||
|
Все системы работают стабильно
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="hidden lg:block opacity-20">
|
<div className="hidden lg:block opacity-20">
|
||||||
<Cloud className="w-32 h-32" />
|
<Cloud className="w-32 h-32" />
|
||||||
@@ -246,292 +330,393 @@ export const HomePage = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Stats Grid */}
|
{/* Stats Grid - только для авторизованных */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
{isAuthenticated && (
|
||||||
{stats.map((stat, index) => {
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||||
const Icon = stat.icon;
|
{stats.map((stat, index) => {
|
||||||
return (
|
const Icon = stat.icon;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="rounded-2xl p-6 transition-all hover:scale-105 hover:shadow-xl"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "var(--card-bg)",
|
||||||
|
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex justify-between items-start mb-4">
|
||||||
|
<div
|
||||||
|
className="w-12 h-12 rounded-xl flex items-center justify-center bg-opacity-20"
|
||||||
|
style={{
|
||||||
|
backgroundColor: `${index === 0 ? "#6366f1" : index === 1 ? "#ef4444" : index === 2 ? "#22c55e" : "#f59e0b"}20`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
className="w-6 h-6"
|
||||||
|
style={{
|
||||||
|
color:
|
||||||
|
index === 0
|
||||||
|
? "#6366f1"
|
||||||
|
: index === 1
|
||||||
|
? "#ef4444"
|
||||||
|
: index === 2
|
||||||
|
? "#22c55e"
|
||||||
|
: "#f59e0b",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
className="text-sm font-medium"
|
||||||
|
style={{ color: "#22c55e" }}
|
||||||
|
>
|
||||||
|
{stat.change}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<h3
|
||||||
|
className="text-2xl font-bold mb-1"
|
||||||
|
style={{ color: "var(--text-primary)" }}
|
||||||
|
>
|
||||||
|
{stat.value}
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
className="text-sm"
|
||||||
|
style={{ color: "var(--text-secondary)" }}
|
||||||
|
>
|
||||||
|
{stat.label}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Features Section - для всех */}
|
||||||
|
<div className="mb-8">
|
||||||
|
<div className="text-center mb-8">
|
||||||
|
<h2
|
||||||
|
className="text-2xl font-bold mb-2"
|
||||||
|
style={{ color: "var(--text-primary)" }}
|
||||||
|
>
|
||||||
|
Ключевые возможности
|
||||||
|
</h2>
|
||||||
|
<p className="text-sm" style={{ color: "var(--text-secondary)" }}>
|
||||||
|
Всё необходимое для защиты вашей инфраструктуры
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||||
|
{features.map((feature, index) => {
|
||||||
|
const Icon = feature.icon;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="rounded-2xl p-6 transition-all hover:scale-105 hover:shadow-xl text-center"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "var(--card-bg)",
|
||||||
|
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="w-14 h-14 rounded-xl flex items-center justify-center mx-auto mb-4"
|
||||||
|
style={{ backgroundColor: `${feature.color}20` }}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
className="w-7 h-7"
|
||||||
|
style={{ color: feature.color }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h3
|
||||||
|
className="font-bold mb-2"
|
||||||
|
style={{ color: "var(--text-primary)" }}
|
||||||
|
>
|
||||||
|
{feature.title}
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
className="text-sm"
|
||||||
|
style={{ color: "var(--text-secondary)" }}
|
||||||
|
>
|
||||||
|
{feature.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{isAuthenticated ? (
|
||||||
|
<>
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||||
|
{/* Quick Actions */}
|
||||||
|
<div className="lg:col-span-2">
|
||||||
|
<div
|
||||||
|
className="rounded-2xl p-6"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "var(--card-bg)",
|
||||||
|
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
className="text-xl font-bold mb-6"
|
||||||
|
style={{ color: "var(--text-primary)" }}
|
||||||
|
>
|
||||||
|
Быстрый доступ
|
||||||
|
</h3>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
|
{quickActions.map((action, index) => {
|
||||||
|
const Icon = action.icon;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={index}
|
||||||
|
onClick={() => navigate(action.path)}
|
||||||
|
className="group p-4 rounded-xl text-left transition-all hover:scale-[1.02]"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "var(--bg-secondary)",
|
||||||
|
border: `1px solid var(--border)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex items-start justify-between">
|
||||||
|
<div
|
||||||
|
className="w-10 h-10 rounded-lg flex items-center justify-center mb-3 transition-all group-hover:scale-110"
|
||||||
|
style={{ backgroundColor: `${action.color}20` }}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
className="w-5 h-5"
|
||||||
|
style={{ color: action.color }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ChevronRight
|
||||||
|
className="w-5 h-5 opacity-0 group-hover:opacity-100 transition-all"
|
||||||
|
style={{ color: "var(--text-muted)" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h4
|
||||||
|
className="font-semibold mb-1"
|
||||||
|
style={{ color: "var(--text-primary)" }}
|
||||||
|
>
|
||||||
|
{action.name}
|
||||||
|
</h4>
|
||||||
|
<p
|
||||||
|
className="text-sm"
|
||||||
|
style={{ color: "var(--text-secondary)" }}
|
||||||
|
>
|
||||||
|
{action.description}
|
||||||
|
</p>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Recent Activity */}
|
||||||
<div
|
<div
|
||||||
key={index}
|
className="rounded-2xl p-6"
|
||||||
className="rounded-2xl p-6 transition-all hover:scale-105 hover:shadow-xl"
|
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "var(--card-bg)",
|
backgroundColor: "var(--card-bg)",
|
||||||
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
|
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex justify-between items-start mb-4">
|
<div className="flex justify-between items-center mb-6">
|
||||||
<div
|
<h3
|
||||||
className="w-12 h-12 rounded-xl flex items-center justify-center bg-opacity-20"
|
className="text-xl font-bold"
|
||||||
style={{
|
style={{ color: "var(--text-primary)" }}
|
||||||
backgroundColor: `${index === 0 ? "#6366f1" : index === 1 ? "#ef4444" : index === 2 ? "#22c55e" : "#f59e0b"}20`,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Icon
|
Последние события
|
||||||
className="w-6 h-6"
|
</h3>
|
||||||
style={{
|
<Activity
|
||||||
color:
|
className="w-5 h-5"
|
||||||
index === 0
|
style={{ color: "var(--text-muted)" }}
|
||||||
? "#6366f1"
|
/>
|
||||||
: index === 1
|
|
||||||
? "#ef4444"
|
|
||||||
: index === 2
|
|
||||||
? "#22c55e"
|
|
||||||
: "#f59e0b",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<span
|
|
||||||
className="text-sm font-medium"
|
|
||||||
style={{ color: "#22c55e" }}
|
|
||||||
>
|
|
||||||
{stat.change}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<h3
|
<div className="space-y-4">
|
||||||
className="text-2xl font-bold mb-1"
|
{recentActivities.map((activity) => {
|
||||||
style={{ color: "var(--text-primary)" }}
|
const severityStyles = getSeverityStyles(activity.severity);
|
||||||
|
const Icon = severityStyles.icon;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={activity.id}
|
||||||
|
className="p-3 rounded-lg transition-all hover:scale-[1.01]"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "var(--bg-secondary)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex gap-3">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<Icon
|
||||||
|
className="w-4 h-4 mt-0.5"
|
||||||
|
style={{ color: severityStyles.text }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<p
|
||||||
|
className="text-sm mb-1"
|
||||||
|
style={{ color: "var(--text-primary)" }}
|
||||||
|
>
|
||||||
|
{activity.message}
|
||||||
|
</p>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Clock
|
||||||
|
className="w-3 h-3"
|
||||||
|
style={{ color: "var(--text-muted)" }}
|
||||||
|
/>
|
||||||
|
<p
|
||||||
|
className="text-xs"
|
||||||
|
style={{ color: "var(--text-muted)" }}
|
||||||
|
>
|
||||||
|
{activity.time}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
className="w-full mt-4 py-2 rounded-lg text-sm font-medium transition-all hover:scale-[1.02]"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "var(--bg-secondary)",
|
||||||
|
color: "var(--text-secondary)",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{stat.value}
|
Показать всю историю
|
||||||
</h3>
|
</button>
|
||||||
<p
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "var(--text-secondary)" }}
|
|
||||||
>
|
|
||||||
{stat.label}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
{/* AI Insights */}
|
||||||
{/* Quick Actions */}
|
|
||||||
<div className="lg:col-span-2">
|
|
||||||
<div
|
<div
|
||||||
className="rounded-2xl p-6"
|
className="rounded-2xl p-6 mt-8 transition-all hover:shadow-xl"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "var(--card-bg)",
|
backgroundColor: "var(--card-bg)",
|
||||||
|
border: `1px solid var(--border)`,
|
||||||
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
|
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<h3
|
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-4 mb-6">
|
||||||
className="text-xl font-bold mb-6"
|
<div className="flex items-center gap-3">
|
||||||
style={{ color: "var(--text-primary)" }}
|
<div
|
||||||
>
|
className="w-10 h-10 rounded-xl flex items-center justify-center"
|
||||||
Быстрый доступ
|
style={{ backgroundColor: "#8b5cf620" }}
|
||||||
</h3>
|
>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<Bot className="w-5 h-5" style={{ color: "#8b5cf6" }} />
|
||||||
{quickActions.map((action, index) => {
|
</div>
|
||||||
const Icon = action.icon;
|
<div>
|
||||||
return (
|
<h3
|
||||||
<button
|
className="text-xl font-bold"
|
||||||
key={index}
|
style={{ color: "var(--text-primary)" }}
|
||||||
onClick={() => navigate(action.path)}
|
|
||||||
className="group p-4 rounded-xl text-left transition-all hover:scale-[1.02]"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "var(--bg-secondary)",
|
|
||||||
border: `1px solid var(--border)`,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between">
|
AI Аналитика
|
||||||
<div
|
</h3>
|
||||||
className="w-10 h-10 rounded-lg flex items-center justify-center mb-3 transition-all group-hover:scale-110"
|
<p
|
||||||
style={{ backgroundColor: `${action.color}20` }}
|
className="text-sm"
|
||||||
>
|
style={{ color: "var(--text-secondary)" }}
|
||||||
<Icon
|
>
|
||||||
className="w-5 h-5"
|
Новые предложения на основе анализа логов
|
||||||
style={{ color: action.color }}
|
</p>
|
||||||
/>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ChevronRight
|
<button
|
||||||
className="w-5 h-5 opacity-0 group-hover:opacity-100 transition-all"
|
className="px-4 py-2 rounded-lg text-sm font-medium transition-all flex items-center gap-2 hover:scale-[1.02] self-start"
|
||||||
style={{ color: "var(--text-muted)" }}
|
style={{
|
||||||
/>
|
backgroundColor: "#8b5cf6",
|
||||||
</div>
|
color: "white",
|
||||||
<h4
|
}}
|
||||||
className="font-semibold mb-1"
|
>
|
||||||
style={{ color: "var(--text-primary)" }}
|
Подробнее
|
||||||
>
|
<ChevronRight className="w-4 h-4" />
|
||||||
{action.name}
|
</button>
|
||||||
</h4>
|
</div>
|
||||||
<p
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
className="text-sm"
|
<div
|
||||||
style={{ color: "var(--text-secondary)" }}
|
className="p-4 rounded-xl transition-all hover:scale-[1.02]"
|
||||||
>
|
style={{ backgroundColor: "var(--bg-secondary)" }}
|
||||||
{action.description}
|
>
|
||||||
</p>
|
<p
|
||||||
</button>
|
className="text-sm font-medium mb-2"
|
||||||
);
|
style={{ color: "var(--text-primary)" }}
|
||||||
})}
|
>
|
||||||
|
🔍 Обнаружена аномалия
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
className="text-xs"
|
||||||
|
style={{ color: "var(--text-secondary)" }}
|
||||||
|
>
|
||||||
|
Повышенная активность с IP-адресов из диапазона
|
||||||
|
185.xxx.xx.xx
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="p-4 rounded-xl transition-all hover:scale-[1.02]"
|
||||||
|
style={{ backgroundColor: "var(--bg-secondary)" }}
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
className="text-sm font-medium mb-2"
|
||||||
|
style={{ color: "var(--text-primary)" }}
|
||||||
|
>
|
||||||
|
💡 Предложено правил
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
className="text-xs"
|
||||||
|
style={{ color: "var(--text-secondary)" }}
|
||||||
|
>
|
||||||
|
AI предлагает 3 новых правила для блокировки бот-сканеров
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="p-4 rounded-xl transition-all hover:scale-[1.02]"
|
||||||
|
style={{ backgroundColor: "var(--bg-secondary)" }}
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
className="text-sm font-medium mb-2"
|
||||||
|
style={{ color: "var(--text-primary)" }}
|
||||||
|
>
|
||||||
|
⚡ Оптимизация
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
className="text-xs"
|
||||||
|
style={{ color: "var(--text-secondary)" }}
|
||||||
|
>
|
||||||
|
Рекомендуется обновить 5 существующих правил для повышения
|
||||||
|
эффективности
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
|
) : (
|
||||||
{/* Recent Activity */}
|
/* CTA Section для неавторизованных */
|
||||||
<div
|
<div
|
||||||
className="rounded-2xl p-6"
|
className="rounded-2xl p-8 text-center"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "var(--card-bg)",
|
backgroundColor: "var(--card-bg)",
|
||||||
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
|
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex justify-between items-center mb-6">
|
<h3
|
||||||
<h3
|
className="text-2xl font-bold mb-2"
|
||||||
className="text-xl font-bold"
|
style={{ color: "var(--text-primary)" }}
|
||||||
style={{ color: "var(--text-primary)" }}
|
|
||||||
>
|
|
||||||
Последние события
|
|
||||||
</h3>
|
|
||||||
<Activity
|
|
||||||
className="w-5 h-5"
|
|
||||||
style={{ color: "var(--text-muted)" }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-4">
|
|
||||||
{recentActivities.map((activity) => {
|
|
||||||
const severityStyles = getSeverityStyles(activity.severity);
|
|
||||||
const Icon = severityStyles.icon;
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={activity.id}
|
|
||||||
className="p-3 rounded-lg transition-all hover:scale-[1.01]"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "var(--bg-secondary)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="flex gap-3">
|
|
||||||
<div className="flex-shrink-0">
|
|
||||||
<Icon
|
|
||||||
className="w-4 h-4 mt-0.5"
|
|
||||||
style={{ color: severityStyles.text }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex-1 min-w-0">
|
|
||||||
<p
|
|
||||||
className="text-sm mb-1"
|
|
||||||
style={{ color: "var(--text-primary)" }}
|
|
||||||
>
|
|
||||||
{activity.message}
|
|
||||||
</p>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Clock
|
|
||||||
className="w-3 h-3"
|
|
||||||
style={{ color: "var(--text-muted)" }}
|
|
||||||
/>
|
|
||||||
<p
|
|
||||||
className="text-xs"
|
|
||||||
style={{ color: "var(--text-muted)" }}
|
|
||||||
>
|
|
||||||
{activity.time}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
className="w-full mt-4 py-2 rounded-lg text-sm font-medium transition-all hover:scale-[1.02]"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "var(--bg-secondary)",
|
|
||||||
color: "var(--text-secondary)",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Показать всю историю
|
Готовы начать?
|
||||||
</button>
|
</h3>
|
||||||
</div>
|
<p
|
||||||
</div>
|
className="text-sm mb-6"
|
||||||
|
style={{ color: "var(--text-secondary)" }}
|
||||||
{/* AI Insights */}
|
>
|
||||||
<div
|
Присоединяйтесь к IPS Manager и получите полный контроль над
|
||||||
className="rounded-2xl p-6 mt-8 transition-all hover:shadow-xl"
|
безопасностью
|
||||||
style={{
|
</p>
|
||||||
backgroundColor: "var(--card-bg)",
|
|
||||||
border: `1px solid var(--border)`,
|
|
||||||
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-4 mb-6">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div
|
|
||||||
className="w-10 h-10 rounded-xl flex items-center justify-center"
|
|
||||||
style={{ backgroundColor: "#8b5cf620" }}
|
|
||||||
>
|
|
||||||
<Bot className="w-5 h-5" style={{ color: "#8b5cf6" }} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3
|
|
||||||
className="text-xl font-bold"
|
|
||||||
style={{ color: "var(--text-primary)" }}
|
|
||||||
>
|
|
||||||
AI Аналитика
|
|
||||||
</h3>
|
|
||||||
<p
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "var(--text-secondary)" }}
|
|
||||||
>
|
|
||||||
Новые предложения на основе анализа логов
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
<button
|
||||||
className="px-4 py-2 rounded-lg text-sm font-medium transition-all flex items-center gap-2 hover:scale-[1.02] self-start"
|
onClick={() => navigate("/auth")}
|
||||||
|
className="px-6 py-2 rounded-lg font-medium transition-all hover:scale-105"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#8b5cf6",
|
backgroundColor: "var(--accent)",
|
||||||
color: "white",
|
color: "white",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Подробнее
|
Начать работу
|
||||||
<ChevronRight className="w-4 h-4" />
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
)}
|
||||||
<div
|
|
||||||
className="p-4 rounded-xl transition-all hover:scale-[1.02]"
|
|
||||||
style={{ backgroundColor: "var(--bg-secondary)" }}
|
|
||||||
>
|
|
||||||
<p
|
|
||||||
className="text-sm font-medium mb-2"
|
|
||||||
style={{ color: "var(--text-primary)" }}
|
|
||||||
>
|
|
||||||
🔍 Обнаружена аномалия
|
|
||||||
</p>
|
|
||||||
<p className="text-xs" style={{ color: "var(--text-secondary)" }}>
|
|
||||||
Повышенная активность с IP-адресов из диапазона 185.xxx.xx.xx
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="p-4 rounded-xl transition-all hover:scale-[1.02]"
|
|
||||||
style={{ backgroundColor: "var(--bg-secondary)" }}
|
|
||||||
>
|
|
||||||
<p
|
|
||||||
className="text-sm font-medium mb-2"
|
|
||||||
style={{ color: "var(--text-primary)" }}
|
|
||||||
>
|
|
||||||
💡 Предложено правил
|
|
||||||
</p>
|
|
||||||
<p className="text-xs" style={{ color: "var(--text-secondary)" }}>
|
|
||||||
AI предлагает 3 новых правила для блокировки бот-сканеров
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="p-4 rounded-xl transition-all hover:scale-[1.02]"
|
|
||||||
style={{ backgroundColor: "var(--bg-secondary)" }}
|
|
||||||
>
|
|
||||||
<p
|
|
||||||
className="text-sm font-medium mb-2"
|
|
||||||
style={{ color: "var(--text-primary)" }}
|
|
||||||
>
|
|
||||||
⚡ Оптимизация
|
|
||||||
</p>
|
|
||||||
<p className="text-xs" style={{ color: "var(--text-secondary)" }}>
|
|
||||||
Рекомендуется обновить 5 существующих правил для повышения
|
|
||||||
эффективности
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user