A
Anonymous

Onboarding Page - Copy this React, Tailwind Component to your project

Ho bisogno che ispirandoit allo stile di questa apgina: import React, { useState, useEffect } from "react"; import { FiChevronLeft, FiChevronRight } from "react icons/fi"; import { BiCode, BiBot, BiShield, BiRocket } from "react icons/bi"; import { motion, AnimatePresence } from "framer motion"; const OnboardingPage = () => { const [currentStep, setCurrentStep] = useState(1); const [hasSeenOnboarding, setHasSeenOnboarding] = useState(false); useEffect(() => { const onboardingStatus = localStorage.getItem("hasSeenOnboarding"); if (onboardingStatus) setHasSeenOnboarding(true); }, []); const handleSkip = () => { localStorage.setItem("hasSeenOnboarding", "true"); setHasSeenOnboarding(true); }; const agents = [ { icon: <BiBot />, title: "Reconnaissance Agent", desc: "Automated asset discovery and mapping" }, { icon: <BiShield />, title: "Vulnerability Scanner", desc: "AI powered vulnerability detection" }, { icon: <BiCode />, title: "Exploit Agent", desc: "Smart exploit development and testing" }, { icon: <BiRocket />, title: "Report Generator", desc: "Intelligent report compilation" } ]; const StepProgress = () => ( <div className="flex justify center mb 8"> {[1, 2, 3, 4].map((step) => ( <div key={step} className="flex items center"> <div className={`w 8 h 8 rounded full flex items center justify center ${currentStep >= step ? "bg blue 600" : "bg gray 700"}`} > {step} </div> {step < 4 && ( <div className={`w 16 h 1 ${currentStep > step ? "bg blue 600" : "bg gray 700"}`} /> )} </div> ))} </div> ); const NavigationButtons = () => ( <div className="flex justify between mt 8"> <button onClick={() => setCurrentStep(currentStep 1)} disabled={currentStep === 1} className={`px 6 py 2 rounded lg flex items center ${currentStep === 1 ? "opacity 50 cursor not allowed" : "hover:bg blue 700"} bg blue 600 text white`} > <FiChevronLeft className="mr 2" /> Previous </button> <button onClick={() => currentStep === 4 ? handleSkip() : setCurrentStep(currentStep + 1)} className="px 6 py 2 rounded lg flex items center bg blue 600 hover:bg blue 700 text white" > {currentStep === 4 ? "Get Started" : "Next"} <FiChevronRight className="ml 2" /> </button> </div> ); const renderStepContent = () => { switch (currentStep) { case 1: return ( <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: 20 }} className="text center" > <h1 className="text 4xl font bold bg gradient to r from blue 400 to purple 500 bg clip text text transparent mb 6"> AI Driven Penetration Testing Framework </h1> <p className="text gray 300 text lg mb 8"> Welcome to the next generation of security testing. Powered by advanced AI, our framework automates and enhances your penetration testing workflow. </p> </motion.div> ); case 2: return ( <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: 20 }} > <h2 className="text 3xl font bold mb 6 text center">How It Works</h2> <div className="bg gray 800 p 4 rounded lg font mono text sm text green 400"> <p>$ initializing_ai_framework</p> <p>$ loading_neural_models...</p> <p>$ configuring_attack_vectors...</p> <p>$ ready_for_engagement ✓</p> </div> </motion.div> ); case 3: return ( <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: 20 }} > <h2 className="text 3xl font bold mb 6 text center">MCP Agents Overview</h2> <div className="grid grid cols 1 md:grid cols 2 gap 4"> {agents.map((agent, index) => ( <div key={index} className="bg gray 800 p 4 rounded lg hover:bg gray 700 transition colors"> <div className="text 3xl text blue 400 mb 2">{agent.icon}</div> <h3 className="text xl font bold mb 2">{agent.title}</h3> <p className="text gray 400">{agent.desc}</p> </div> ))} </div> </motion.div> ); case 4: return ( <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: 20 }} className="text center" > <h2 className="text 3xl font bold mb 6">Ready to Begin?</h2> <p className="text gray 300 text lg mb 8"> Your AI powered security journey starts here. Let's revolutionize your penetration testing workflow together. </p> </motion.div> ); default: return null; } }; if (hasSeenOnboarding) { return null; // Or redirect to main application } return ( <div className="min h screen bg gray 900 text white p 6 relative overflow hidden"> <div className="absolute inset 0 opacity 10"> <div className="absolute w 96 h 96 bg blue 500 rounded full blur 3xl top 20 left 20" /> <div className="absolute w 96 h 96 bg purple 500 rounded full blur 3xl bottom 20 right 20" /> </div> <div className="max w 3xl mx auto relative z 10"> <button onClick={handleSkip} className="absolute top 0 right 0 text gray 400 hover:text white" > Skip </button> <StepProgress /> <div className="min h [400px] flex items center justify center"> <AnimatePresence mode="wait"> {renderStepContent()} </AnimatePresence> </div> <NavigationButtons /> </div> </div> ); }; export default OnboardingPage;, fai anche questa che ti do ora dello stesso stile non cambiare la disposizione ma almagama solo lo stile:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF 8"> <meta name="viewport" content="width=device width, initial scale=1.0"> <title>Pentration Testing Framework</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0 alpha1/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdnjs.cloudflare.com/ajax/libs/font awesome/6.4.0/css/all.min.css" rel="stylesheet"> <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> <style> /* Use livemonitor color scheme */ :root { primary bg: #1a1d29; secondary bg: #252936; accent bg: #2a2f3f; glass bg: rgba(42, 47, 63, 0.85); text primary: #e8eaed; text secondary: #9aa0a6; text accent: #4285f4; border color: rgba(255, 255, 255, 0.1); success color: #34a853; warning color: #fbbc04; danger color: #ea4335; shadow: 0 8px 32px rgba(0, 0, 0, 0.3); } body { background: linear gradient(135deg, #1a1d29 0%, #252936 100%); font family: 'Segoe UI', system ui, apple system, sans serif; color: var( text primary); min height: 100vh; line height: 1.6; margin: 0; padding: 0; position: relative; overflow x: hidden; } /* Beautiful onboarding style blur effects */ body::before { content: ''; position: fixed; top: 80px; left: 80px; width: 384px; height: 384px; background: #3b82f6; border radius: 50%; filter: blur(96px); opacity: 0.1; z index: 0; pointer events: none; } body::after { content: ''; position: fixed; bottom: 80px; right: 80px; width: 384px; height: 384px; background: #9333ea; border radius: 50%; filter: blur(96px); opacity: 0.1; z index: 0; pointer events: none; } /* Splash Screen Iniziale */ .splash screen { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: linear gradient(135deg, var( primary bg) 0%, var( secondary bg) 100%); display: flex; align items: center; justify content: center; z index: 10001; opacity: 1; transition: opacity 0.5s ease, visibility 0.5s ease; } .splash screen.hidden { opacity: 0; visibility: hidden; } .splash logo { text align: center; animation: splashPulse 1.5s ease in out; } .splash logo i { font size: 4rem; color: var( text accent); margin bottom: 1rem; display: block; filter: drop shadow(0 0 20px rgba(66, 133, 244, 0.6)); } .splash logo h1 { font size: 2rem; font weight: 700; color: var( text primary); margin: 0; letter spacing: 2px; } .splash logo p { font size: 1rem; color: var( text secondary); margin: 0.5rem 0 0 0; font weight: 300; } @keyframes splashPulse { 0% { transform: scale(0.8); opacity: 0; } 50% { transform: scale(1.05); } 100% { transform: scale(1); opacity: 1; } } /* Animazioni di entrata per contenuto principale */ .main container { max width: 1200px; margin: 0 auto; padding: 2rem; min height: 100vh; position: relative; z index: 10; } .main container.animate entrance { opacity: 0; transform: translateY(30px); animation: slideInUp 0.8s ease 0.5s forwards; } @keyframes slideInUp { to { opacity: 1; transform: translateY(0); } } .header { background: var( glass bg); border: 1px solid var( border color); border radius: 12px; padding: 2rem; margin bottom: 2rem; box shadow: var( shadow); backdrop filter: blur(20px); } .header.animate entrance { opacity: 0; transform: translateY( 20px); animation: slideInDown 0.6s ease 0.8s forwards; } @keyframes slideInDown { to { opacity: 1; transform: translateY(0); } } .glass card { background: var( glass bg); border: 1px solid var( border color); border radius: 12px; padding: 2rem; box shadow: var( shadow); backdrop filter: blur(20px); max width: 800px; margin: 0 auto; position: relative; } .glass card.animate entrance { opacity: 0; transform: scale(0.95); animation: fadeInScale 0.7s ease 1.1s forwards; } @keyframes fadeInScale { to { opacity: 1; transform: scale(1); } } .header content { text align: center; } .header content.animate entrance { opacity: 0; transform: translateY(20px); animation: slideInUp 0.6s ease 0.7s forwards; } .header text { display: flex; flex direction: column; } .header h1 { font size: 2rem; font weight: 600; color: var( text primary); margin: 0 0 0.5rem 0; display: flex; align items: center; gap: 0.75rem; justify content: center; } .header h1 i { color: var( text accent); font size: 2.2rem; filter: drop shadow(0 0 10px rgba(66, 133, 244, 0.6)); animation: pulse glow 3s ease in out infinite alternate; } @keyframes pulse glow { 0% { filter: drop shadow(0 0 10px rgba(66, 133, 244, 0.6)); } 100% { filter: drop shadow(0 0 20px rgba(66, 133, 244, 0.8)); } } .subtitle { font size: 1rem; color: var( text secondary); font weight: 400; margin: 0; } .btn primary { background: linear gradient(135deg, var( text accent) 0%, #5a9bff 100%); color: white; border: none; padding: 0.75rem 1.5rem; border radius: 8px; font size: 0.95rem; font weight: 500; cursor: pointer; box shadow: 0 4px 15px rgba(66, 133, 244, 0.3); transition: all 0.05s; } .btn primary:hover { background: linear gradient(135deg, #5a9bff 0%, var( text accent) 100%); transform: translateY( 2px); box shadow: 0 8px 25px rgba(66, 133, 244, 0.4); } .btn primary:disabled { background: var( accent bg); color: var( text secondary); cursor: not allowed; transform: none; box shadow: none; } .card title { color: var( text primary); font size: 1.1rem; font weight: 600; margin bottom: 1rem; display: flex; align items: center; gap: 0.5rem; } .card title i { color: var( text accent); font size: 1.3rem; filter: drop shadow(0 0 8px rgba(66, 133, 244, 0.5)); } .card icon { display: inline flex; align items: center; justify content: center; width: 2.5rem; height: 2.5rem; background: linear gradient(135deg, var( text accent) 0%, #5a9bff 100%); border radius: 8px; margin right: 0.75rem; box shadow: 0 4px 15px rgba(66, 133, 244, 0.3); font size: 1.8rem !important; } .card icon i { color: white !important; font size: 1.4rem !important; filter: none !important; } .form group { margin bottom: 1.5rem; } .form group label { display: block; margin bottom: 0.5rem; color: var( text primary); font weight: 500; display: flex; align items: center; gap: 0.5rem; } .form group label i { color: var( text accent); } .form control { width: 100%; padding: 0.75rem; border: 1px solid var( border color); border radius: 8px; font size: 0.95rem; background: rgba(255, 255, 255, 0.05); color: var( text primary) !important; backdrop filter: blur(10px); transition: all 0.1s; } /* Assicura che il testo sia sempre bianco */ .form control, .form control:focus, .form control:active, .form control:valid { color: var( text primary) !important; } .form control:focus { outline: none; border color: var( text accent); box shadow: 0 0 0 3px rgba(66, 133, 244, 0.2); background: rgba(255, 255, 255, 0.08); } .form control::placeholder { color: var( text secondary); } .header actions { display: flex; align items: center; justify content: flex end; } .form section { margin top: 2rem; } .agents status { background: rgba(52, 168, 83, 0.1); border: 1px solid rgba(52, 168, 83, 0.3); color: var( success color); padding: 1rem; border radius: 8px; margin bottom: 2rem; display: none; backdrop filter: blur(10px); } /* Custom error alert styling */ .alert danger { background: rgba(234, 67, 53, 0.1) !important; border: 1px solid rgba(234, 67, 53, 0.3) !important; color: var( danger color) !important; padding: 1.5rem !important; border radius: 12px !important; margin bottom: 2rem !important; backdrop filter: blur(10px) !important; box shadow: 0 8px 32px rgba(234, 67, 53, 0.2) !important; font size: 1rem !important; line height: 1.6 !important; white space: pre line !important; } .alert danger i { color: var( danger color) !important; margin right: 0.75rem !important; font size: 1.2rem !important; } .alert danger strong { color: var( danger color) !important; font weight: 600 !important; } small { color: var( text secondary); } /* Top Navigation Bar MIGLIORATA */ .top navbar { background: var( glass bg); border bottom: 1px solid var( border color); padding: 1.5rem 0; backdrop filter: blur(20px); box shadow: 0 4px 20px rgba(0, 0, 0, 0.1); position: sticky; top: 0; z index: 1000; } .top navbar.animate entrance { opacity: 0; transform: translateY( 20px); animation: slideInDown 0.6s ease 0.6s forwards; } .navbar content { max width: 1400px; margin: 0 auto; padding: 0 2rem; display: flex; justify content: space between; align items: center; } .navbar brand { color: var( text primary); font weight: 700; font size: 1.4rem; text decoration: none; display: flex; align items: center; gap: 0.75rem; transition: transform 0.2s ease; } .navbar brand:hover { transform: scale(1.05); } .navbar brand i { color: var( text accent); font size: 1.5rem; filter: drop shadow(0 0 8px rgba(66, 133, 244, 0.5)); } .navbar nav { display: flex; flex direction: row; align items: center; gap: 0.5rem; } .nav link { color: var( text secondary); text decoration: none; padding: 0.75rem 1.25rem; border radius: 8px; font size: 0.95rem; font weight: 500; white space: nowrap; transition: all 0.2s ease; display: flex; align items: center; gap: 0.5rem; border: 1px solid transparent; } .nav link:hover { color: var( text primary); background: rgba(255, 255, 255, 0.08); border color: rgba(255, 255, 255, 0.1); transform: translateY( 1px); } .nav link.active { color: var( text accent); background: rgba(66, 133, 244, 0.15); border color: rgba(66, 133, 244, 0.3); box shadow: 0 4px 12px rgba(66, 133, 244, 0.2); } .nav link i { font size: 1rem; transition: transform 0.2s ease; } .nav link:hover i { transform: scale(1.1); } /* Responsive Design */ @media (max width: 768px) { .navbar content { padding: 0 1rem; flex direction: column; gap: 1rem; } .navbar brand { font size: 1.2rem; } .navbar nav { gap: 0.25rem; } .nav link { padding: 0.5rem 0.75rem; font size: 0.85rem; } } /* Loading Overlay MANTENUTO IDENTICO */ #loadingOverlay { display: none; position: fixed; z index: 9999; top: 0; left: 0; width: 100vw; height: 100vh; background: linear gradient(135deg, var( primary bg) 0%, var( secondary bg) 100%); backdrop filter: blur(10px); color: #ffffff; font family: 'Segoe UI', system ui, apple system, sans serif; align items: center; justify content: center; flex direction: column; text align: center; } .loading container { background: rgba(255, 255, 255, 0.08); backdrop filter: blur(20px); border: 1px solid rgba(255, 255, 255, 0.1); border radius: 20px; padding: 3rem 4rem; box shadow: 0 25px 50px rgba(0, 0, 0, 0.3); max width: 400px; width: 90%; } .loading icon { width: 60px; height: 60px; margin: 0 auto 1.5rem; position: relative; } .loading spinner { width: 100%; height: 100%; border: 3px solid rgba(66, 133, 244, 0.3); border top: 3px solid #4285f4; border radius: 50%; animation: spin 0.6s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .security icon { position: absolute; top: 50%; left: 50%; transform: translate( 50%, 50%); font size: 1.5rem; color: #4285f4; } .loading title { font size: 1.5rem; font weight: 600; margin bottom: 0.5rem; color: #ffffff; } .loading subtitle { font size: 1rem; color: #94a3b8; margin bottom: 1.5rem; } .loading progress { width: 100%; height: 4px; background: rgba(255, 255, 255, 0.1); border radius: 2px; overflow: hidden; margin bottom: 1rem; } .loading progress bar { height: 100%; background: linear gradient(90deg, #4285f4, #5a9bff); border radius: 2px; width: 0%; transition: width 0.01s ease; animation: progressPulse 1.5s ease in out infinite alternate; box shadow: 0 0 10px rgba(66, 133, 244, 0.5); position: relative; overflow: hidden; } .loading progress bar::after { content: ''; position: absolute; top: 0; left: 100%; width: 100%; height: 100%; background: linear gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); animation: shimmer 2s infinite; } @keyframes shimmer { 0% { left: 100%; } 100% { left: 100%; } } @keyframes progressPulse { 0% { box shadow: 0 0 10px rgba(66, 133, 244, 0.5); } 100% { box shadow: 0 0 20px rgba(66, 133, 244, 0.8); } } .loading status { font size: 0.9rem; color: #cbd5e1; font weight: 400; } .loading dots::after { content: ''; animation: dots 1.5s infinite; } @keyframes dots { 0%, 20% { content: ''; } 40% { content: '.'; } 60% { content: '..'; } 80%, 100% { content: '...'; } } /* Validation Modal mantenuto stile livemonitor */ .modal overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.7); display: flex; align items: center; justify content: center; z index: 10000; backdrop filter: blur(5px); } .modal content { background: #1a1d29; border: 1px solid #4285f4; border radius: 12px; padding: 2rem; max width: 500px; width: 90%; color: #e8eaed; box shadow: 0 20px 60px rgba(0, 0, 0, 0.4); } .modal header { display: flex; align items: center; margin bottom: 1rem; } .modal header i { color: #fbbc04; font size: 1.5rem; margin right: 0.75rem; } .modal header h3 { margin: 0; color: #e8eaed; } .modal body { margin: 1rem 0; white space: pre line; line height: 1.5; } .modal button { background: #4285f4; color: white; border: none; padding: 0.75rem 1.5rem; border radius: 6px; cursor: pointer; font size: 1rem; width: 100%; margin top: 1rem; transition: all 0.1s; } .modal button:hover { background: #5a9bff; } </style> </head> <body> <! Splash Screen > <div id="splashScreen" class="splash screen"> <div class="splash logo"> <i class="fas fa shield halved"></i> <h1>PTF FRAMEWORK</h1> <p>Initializing Security Suite...</p> </div> </div> <! Top Navigation Bar > <nav class="top navbar"> <div class="navbar content"> <a href="/dashboard" class="navbar brand"> <i class="fas fa shield halved"></i> PTF Console </a> <div class="navbar nav"> <a href="/dashboard" class="nav link active"> <i class="fas fa home"></i> Dashboard </a> <a href="/reports" class="nav link"> <i class="fas fa file alt"></i> Reports </a> <a href="/analytics" class="nav link"> <i class="fas fa chart line"></i> Analytics </a> <a href="/chat" class="nav link"> <i class="fas fa comments"></i> Chat Support </a> <a href="/" class="nav link"> <i class="fas fa rocket"></i> Tour </a> <a href="/settings" class="nav link"> <i class="fas fa cog"></i> Settings </a> </div> </div> </nav> <! Loading Overlay > <div id="loadingOverlay"> <div class="loading container"> <div class="loading icon"> <div class="loading spinner"></div> <div class="security icon">🛡️</div> </div> <div class="loading title">Initializing MCP Agents</div> <div class="loading subtitle">Loading penetration testing modules...</div> <div class="loading progress"> <div class="loading progress bar"></div> </div> <div class="loading status" id="loadingStatus"> Starting system<span class="loading dots"></span> </div> </div> </div> <div class="main container"> <! Header senza riquadro > <div class="header content" style="text align: center; margin bottom: 3rem;"> <h1 style="font size: 2.5rem; font weight: 700; margin bottom: 0.5rem;"> <i class="fas fa shield halved" style="color: var( text accent); margin right: 0.75rem;"></i>Penetration Testing Framework </h1> <p style="font size: 1.1rem; color: var( text secondary); margin: 0;"> Automated Penetration Testing with Human in the Loop Control </p> </div> <! Security Analysis Form > <div class="glass card"> <div class="card title"> <div class="card icon"> ⚡ </div> Security Analysis Console </div> <! Agents Status > <div id="agentsStatus" class="agents status"> <i class="fas fa check circle"></i> <span id="agentsStatusText">MCP agents loaded and ready</span> </div> <! Error Alert (for Flask errors) > {% if error %} <div class="alert alert danger"> <i class="fas fa exclamation triangle"></i> <strong>Error:</strong> {{ error }} </div> {% endif %} <! Form with Flask backend connection > <form action="{{ url_for('main.run_analysis') }}" method="post" autocomplete="off" id="analysisForm"> <div class="form group"> <label for="user_prompt" class="form label"> <i class="fas fa comment dots"></i> Analysis Request </label> <textarea class="form control" id="user_prompt" name="user_prompt" rows="5" placeholder="Example: 'Execute comprehensive vulnerability assessment and penetration testing on target infrastructure'" required style="font size: 1rem;" >{{ user_prompt or '' }}</textarea> </div> <div class="form group"> <label for="target" class="form label"> <i class="fas fa bullseye"></i> Target Specification </label> <input type="text" class="form control" id="target" name="target" value="{{ target or '' }}" placeholder="IP address, domain, or URL (e.g., 192.168.1.0/24, example.com)" style="font size: 1rem;" > <small style="color: var( text secondary); margin top: 0.5rem; display: block;"> Supports IP ranges, domains, URLs, and custom endpoints </small> </div> <button type="submit" class="btn primary" id="submitBtn" style="font size: 1.1rem; padding: 1.2rem;" disabled> <i class="fas fa spinner fa spin" id="submitSpinner" style="display: none;"></i> <i class="fas fa play" id="submitIcon"></i> <span id="submitText">Loading agents...</span> </button> </form> </div> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0 alpha1/dist/js/bootstrap.bundle.min.js"></script> <script> // Gestione Splash Screen Solo al primo avvio document.addEventListener("DOMContentLoaded", function() { const splashScreen = document.getElementById("splashScreen"); const navbar = document.querySelector(".top navbar"); const mainContainer = document.querySelector(".main container"); const headerContent = document.querySelector(".header content"); const glassCard = document.querySelector(".glass card"); // Controlla se è il primo caricamento della sessione const hasSeenSplash = sessionStorage.getItem('ptf_splash_shown'); if (!hasSeenSplash) { // Prima volta mostra splash screen con animazioni sessionStorage.setItem('ptf_splash_shown', 'true'); // Applica classi di animazione if (navbar) navbar.classList.add('animate entrance'); if (mainContainer) mainContainer.classList.add('animate entrance'); if (glassCard) glassCard.classList.add('animate entrance'); // Nascondi splash screen dopo 1.5 secondi setTimeout(() => { splashScreen.classList.add("hidden"); // Rimuovi completamente dopo la transizione setTimeout(() => { splashScreen.style.display = "none"; }, 500); }, 1500); } else { // Già visto nascondi immediatamente senza animazioni splashScreen.style.display = "none"; // IMPORTANTE: Rimuovi tutte le classi di animazione per navigazioni successive if (navbar) navbar.classList.remove('animate entrance'); if (mainContainer) mainContainer.classList.remove('animate entrance'); if (glassCard) glassCard.classList.remove('animate entrance'); // Assicurati che tutti gli elementi siano visibili immediatamente if (navbar) { navbar.style.opacity = '1'; navbar.style.transform = 'none'; } if (mainContainer) { mainContainer.style.opacity = '1'; mainContainer.style.transform = 'none'; } if (glassCard) { glassCard.style.opacity = '1'; glassCard.style.transform = 'none'; } } }); document.addEventListener("DOMContentLoaded", function() { const form = document.getElementById("analysisForm"); const overlay = document.getElementById("loadingOverlay"); const statusText = document.getElementById("loadingStatus"); const progressBar = document.querySelector(".loading progress bar"); const submitBtn = document.getElementById("submitBtn"); const submitText = document.getElementById("submitText"); const submitIcon = document.getElementById("submitIcon"); const submitSpinner = document.getElementById("submitSpinner"); const agentsStatus = document.getElementById("agentsStatus"); const agentsStatusText = document.getElementById("agentsStatusText"); // Show loading overlay initially overlay.style.display = "flex"; // Inizializza il caricamento degli agenti all'avvio initializeAgents(); async function initializeAgents() { try { const response = await fetch('/initialize_agents', { method: 'POST', headers: { 'Content Type': 'application/json' } }); if (response.ok) { // Inizia a controllare lo stato checkAgentsStatus(); } } catch (error) { console.error('Error initializing security agents:', error); hideLoadingOverlay(); showError("Error initializing security agents"); } } async function checkAgentsStatus() { try { const response = await fetch('/check_agents_status'); const status = await response.json(); if (status.is_loading) { // Aggiorna il messaggio di stato statusText.innerHTML = status.current_status + '<span class="loading dots"></span>'; // Aggiorna la progress bar se disponibile if (status.progress && progressBar) { progressBar.style.width = status.progress + '%'; } // Controlla di nuovo dopo 200ms per aggiornamenti più fluidi setTimeout(checkAgentsStatus, 200); } else { // Loading completed console.log(`✅ MCP agents loaded: ${status.loaded_agents.length} successful, ${status.failed_agents.length} failed`); // Hide overlay hideLoadingOverlay(); // Show agents status showAgentsStatus(status); // Enable form enableForm(); } } catch (error) { console.error('Error checking system status:', error); hideLoadingOverlay(); showError("Error checking security agent status"); } } function hideLoadingOverlay() { if (overlay) { overlay.style.display = 'none'; } } function showAgentsStatus(status) { if (agentsStatus && agentsStatusText) { agentsStatusText.textContent = `${status.loaded_agents.length} MCP agents loaded and ready`; agentsStatus.style.display = 'block'; } } function enableForm() { if (submitBtn && submitText && submitIcon) { submitBtn.disabled = false; submitText.textContent = 'Initiate Security Analysis'; submitIcon.style.display = 'inline'; } } function showError(message) { if (submitBtn && submitText) { submitBtn.disabled = true; submitText.textContent = message; submitBtn.style.background = '#dc3545'; } } // Validation helper functions function isValidTarget(target) { // IP address patterns (with optional CIDR) const ipPattern = /^(?:(?:25[0 5]|2[0 4][0 9]|[01]?[0 9][0 9]?)\.){3}(?:25[0 5]|2[0 4][0 9]|[01]?[0 9][0 9]?)(?:\/(?:[0 9]|[1 2][0 9]|3[0 2]))?$/; // Domain pattern (basic validation) const domainPattern = /^(?:[a zA Z0 9](?:[a zA Z0 9 ]{0,61}[a zA Z0 9])?\.)+[a zA Z]{2,}$/; // URL pattern const urlPattern = /^https?:\/\/(?:[a zA Z0 9](?:[a zA Z0 9 ]{0,61}[a zA Z0 9])?\.)+[a zA Z]{2,}(?:\/.*)?$/; // Localhost patterns const localhostPattern = /^(localhost|127\.0\.0\.1|::1)(?::\d+)?$/; return ipPattern.test(target) || domainPattern.test(target) || urlPattern.test(target) || localhostPattern.test(target); } function showValidationError(message) { // Create custom modal instead of alert for better UX const modal = document.createElement('div'); modal.className = 'modal overlay'; const content = document.createElement('div'); content.className = 'modal content'; content.innerHTML = ` <div class="modal header"> <i class="fas fa exclamation triangle"></i> <h3>Validation Error</h3> </div> <p class="modal body">${message}</p> <button class="modal button" id="closeValidationModal">OK</button> `; modal.appendChild(content); document.body.appendChild(modal); // Close modal functionality function closeModal() { document.body.removeChild(modal); } document.getElementById('closeValidationModal').addEventListener('click', closeModal); modal.addEventListener('click', function(e) { if (e.target === modal) closeModal(); }); // Focus the problematic field if (message.includes("target")) { setTimeout(() => { const targetField = document.getElementById("target"); if (targetField) { targetField.focus(); targetField.style.borderColor = "#ea4335"; } }, 100); } else if (message.includes("analysis request")) { setTimeout(() => { const promptField = document.getElementById("user_prompt"); if (promptField) { promptField.focus(); promptField.style.borderColor = "#ea4335"; } }, 100); } } if (form) { form.addEventListener("submit", async function(e) { e.preventDefault(); // Validate form fields const userPrompt = document.getElementById("user_prompt").value.trim(); const target = document.getElementById("target").value.trim(); if (!userPrompt) { showValidationError("Please enter an analysis request."); return; } if (!target) { showValidationError("Please enter a target (IP address, domain, or URL)."); return; } // Enhanced target validation if (!isValidTarget(target)) { showValidationError("Invalid target format. Please enter a valid IP address, domain name, or URL.\n\nExamples:\n IP: 192.168.1.1 or 192.168.1.0/24\n Domain: example.com\n URL: https://example.com"); return; } // Verifica che gli agenti siano caricati try { const statusResponse = await fetch('/check_agents_status'); const status = await statusResponse.json(); if (status.is_loading) { showValidationError("Gli agenti MCP sono ancora in caricamento. Attendere il completamento."); return; } if (status.loaded_agents.length === 0) { showValidationError("Nessun agente MCP disponibile. Verificare i log del server."); return; } } catch (error) { console.error('Errore nel controllo agenti:', error); showValidationError("Errore nel controllo degli agenti. Riprovare."); return; } // Mostra spinner sul bottone if (submitBtn && submitText && submitIcon && submitSpinner) { submitBtn.disabled = true; submitIcon.style.display = 'none'; submitSpinner.style.display = 'inline'; submitText.textContent = 'Avvio analisi...'; } // Submit del form direttamente (andrà al live monitor) form.submit(); }); } // Enhanced form validation const userPromptField = document.getElementById("user_prompt"); const targetField = document.getElementById("target"); if (userPromptField) { userPromptField.addEventListener('input', function() { if (this.value.trim().length > 0) { this.style.borderColor = "var( success color)"; } else { this.style.borderColor = "var( border color)"; } }); } if (targetField) { targetField.addEventListener('input', function() { const value = this.value.trim(); if (value.length === 0) { this.style.borderColor = "var( border color)"; return; } if (isValidTarget(value)) { this.style.borderColor = "var( success color)"; this.style.boxShadow = "0 0 0 2px rgba(76, 175, 80, 0.2)"; } else { this.style.borderColor = "#ea4335"; this.style.boxShadow = "0 0 0 2px rgba(234, 67, 53, 0.2)"; } }); // Reset border on focus targetField.addEventListener('focus', function() { if (this.style.borderColor === '#ea4335' || this.style.borderColor === 'rgb(234, 67, 53)') { this.style.borderColor = "var( border color)"; this.style.boxShadow = "none"; } }); } }); </script> </body> </html>

Prompt
Component Preview

About

OnboardingPage - A guided setup with step-by-step navigation, agent overviews, and AI integration, professionally built with React and Tailwind. Get code instantly!

Share

Last updated 1 month ago