diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 3428ea0..e9b986d 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,4 @@ -import { Navbar, Hero, ProblemSolution, HowItWorks } from './components'; +import { Navbar, Hero, ProblemSolution, HowItWorks, InteractiveDemo } from './components'; import './App.css'; function App() { @@ -27,6 +27,7 @@ function App() { /> + ); diff --git a/frontend/src/components/index.ts b/frontend/src/components/index.ts index 395a21f..9222460 100644 --- a/frontend/src/components/index.ts +++ b/frontend/src/components/index.ts @@ -1,4 +1,5 @@ export { Navbar } from './layout/Navbar'; export { Hero } from './sections/Hero'; export { ProblemSolution } from './sections/ProblemSolution'; -export { HowItWorks } from './sections/HowItWorks'; \ No newline at end of file +export { HowItWorks } from './sections/HowItWorks'; +export { InteractiveDemo } from './sections/InteractiveDemo'; \ No newline at end of file diff --git a/frontend/src/components/sections/InteractiveDemo.tsx b/frontend/src/components/sections/InteractiveDemo.tsx new file mode 100644 index 0000000..c347449 --- /dev/null +++ b/frontend/src/components/sections/InteractiveDemo.tsx @@ -0,0 +1,282 @@ +import React, { useState } from 'react'; +import { Terminal, Copy, Check, Loader2, AlertCircle, Activity } from 'lucide-react'; + +// Mock data for demo logs +const DEMO_LOGS = [ + { + id: 'postgres-oom', + label: 'PostgreSQL OOM', + icon: , + logContent: `FATAL: database system is out of memory +DETAIL: Failed on request of size 8192 +HINT: Check memory usage and limits +CONTEXT: automatic vacuum of table "public.events"`, + analysis: { + title: 'PostgreSQL Out of Memory', + description: 'Il database ha esaurito la memoria disponibile durante un\'operazione di vacuum automatico su una tabella molto grande.', + command: 'ps aux | grep postgres | head -5 && free -h', + isSafe: true, + note: 'Verifica processi Postgres e memoria disponibile. Se necessario, aumenta work_mem o shared_buffers.', + }, + }, + { + id: 'nginx-502', + label: 'Nginx 502 Bad Gateway', + icon: , + logContent: `2024/01/15 14:32:15 [error] 1234#1234: *56789 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.1.100, server: api.example.com, upstream: "127.0.0.1:3000"`, + analysis: { + title: 'Nginx 502 - Backend Non Raggiungibile', + description: 'Nginx non riesce a connettersi al backend sulla porta 3000. Probabilmente il servizio è down.', + command: 'sudo systemctl status app-service && netstat -tlnp | grep 3000', + isSafe: true, + note: 'Verifica stato del servizio backend. Se stopped, avvia con: sudo systemctl start app-service', + }, + }, + { + id: 'node-exception', + label: 'Node.js Exception', + icon: , + logContent: `Error: connect ECONNREFUSED 127.0.0.1:5432 + at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16) + at emitErrorNT (internal/streams/destroy.js:92:8) + at processTicksAndRejections (internal/process/task_queues.js:80:21)`, + analysis: { + title: 'Node.js - Connessione Database Rifiutata', + description: 'L\'applicazione Node non riesce a connettersi al database PostgreSQL sulla porta 5432.', + command: 'sudo systemctl status postgresql && sudo netstat -tlnp | grep 5432', + isSafe: true, + note: 'Verifica che PostgreSQL sia in esecuzione. Se down, avvia con: sudo systemctl start postgresql', + }, + }, +]; + +// Icon components +function Database(props: React.SVGProps) { + return ( + + + + + + ); +} + +function Globe(props: React.SVGProps) { + return ( + + + + + + ); +} + +function Code(props: React.SVGProps) { + return ( + + + + + ); +} + +interface LogAnalysis { + title: string; + description: string; + command: string; + isSafe: boolean; + note: string; +} + +export const InteractiveDemo: React.FC = () => { + const [selectedLog, setSelectedLog] = useState(null); + const [isAnalyzing, setIsAnalyzing] = useState(false); + const [analysis, setAnalysis] = useState(null); + const [copied, setCopied] = useState(false); + + const handleLogSelect = (logId: string) => { + setSelectedLog(logId); + setIsAnalyzing(true); + setAnalysis(null); + setCopied(false); + + // Simulate AI analysis delay + setTimeout(() => { + const log = DEMO_LOGS.find((l) => l.id === logId); + if (log) { + setAnalysis(log.analysis); + setIsAnalyzing(false); + } + }, 1500); + }; + + const handleCopyCommand = () => { + if (analysis?.command) { + navigator.clipboard.writeText(analysis.command); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } + }; + + const selectedLogData = DEMO_LOGS.find((l) => l.id === selectedLog); + + return ( +
+
+ {/* Section Header */} +
+

+ Prova la Demo Interattiva +

+

+ Seleziona un log di esempio e vedi come l'AI lo trasforma in un comando risolutivo in pochi secondi. +

+
+ + {/* Two Column Layout */} +
+ {/* Left Panel - Terminal Input */} +
+ {/* Terminal Header */} +
+
+
+
+ + + {/* Right Panel - AI Analysis Output */} +
+ {!selectedLog && !isAnalyzing && !analysis && ( +
+
+ )} + + {isAnalyzing && ( +
+
+ )} + + {analysis && !isAnalyzing && ( +
+ {/* Analysis Header */} +
+
+
+
+

{analysis.title}

+

{analysis.description}

+
+
+ + {/* Command Box */} +
+
+ Comando suggerito: + {analysis.isSafe && ( + + + )} +
+ + {analysis.command} + + +
+ + {/* Additional Notes */} +
+

+ Nota: {analysis.note} +

+
+
+ )} +
+
+
+
+ ); +}; + +export default InteractiveDemo; \ No newline at end of file