diff --git a/.gitignore b/.gitignore index 85806bb..8461d25 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ node_modules playwright-report test-results +.vscode # User configuration user_config.yaml diff --git a/Makefile b/Makefile index 06da8bd..367ba2b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ .PHONY: dev/server dev/server: go run github.com/goware/rerun/cmd/rerun@latest \ - -watch . \ + -watch cmd \ + -watch internal \ -ignore app \ -run "go run ./cmd/api" diff --git a/app/app/globals.css b/app/app/globals.css index dc98be7..4fcfdae 100644 --- a/app/app/globals.css +++ b/app/app/globals.css @@ -120,3 +120,61 @@ @apply bg-background text-foreground; } } + +@keyframes subtle-pulse { + 0%, + 100% { + border-color: rgb(59 130 246); + box-shadow: 0 0 15px rgba(59, 130, 246, 0.5); + } + 50% { + border-color: rgb(59 130 246 / 0.7); + box-shadow: 0 0 15px rgba(59, 130, 246, 0.3); + } +} +.animate-pulse-subtle { + animation: subtle-pulse 3s ease-in-out infinite; +} + +.shiny-text { + color: #b5b5b5a4; /* Adjust this color to change intensity/style */ + background: linear-gradient( + 120deg, + rgba(255, 255, 255, 0) 40%, + rgba(0, 0, 0, 1) 50%, + rgba(255, 255, 255, 0) 60% + ); + background-size: 200% 100%; + -webkit-background-clip: text; + background-clip: text; + display: inline-block; + animation: shine 5s linear infinite; +} + +@keyframes shine { + 0% { + background-position: 100%; + } + 100% { + background-position: -100%; + } +} + +.shiny-text.disabled { + animation: none; +} + +@keyframes fade-in { + from { + opacity: 0; + filter: blur(8px); + } + to { + opacity: 1; + filter: blur(0px); + } +} + +.animate-fade-in { + animation: fade-in 1.5s ease-out forwards; +} diff --git a/app/app/layout.tsx b/app/app/layout.tsx index 7ad5c8b..722c26c 100644 --- a/app/app/layout.tsx +++ b/app/app/layout.tsx @@ -30,7 +30,7 @@ export default function RootLayout({ className={`${geistSans.variable} ${geistMono.variable} antialiased`} > -
{children}
+
{children}
diff --git a/app/app/ui-demo/feedback.tsx b/app/app/ui-demo/feedback.tsx new file mode 100644 index 0000000..6748c88 --- /dev/null +++ b/app/app/ui-demo/feedback.tsx @@ -0,0 +1,17 @@ +interface FeedbackProps { + feedback: string; + className?: string; +} + +export default function Feedback({ feedback, className }: FeedbackProps) { + if (!feedback) { + return null; + } + + return ( +
+

Current feedback:

+

{feedback}

+
+ ); +} diff --git a/app/app/ui-demo/page.tsx b/app/app/ui-demo/page.tsx new file mode 100644 index 0000000..3fce75c --- /dev/null +++ b/app/app/ui-demo/page.tsx @@ -0,0 +1,248 @@ +"use client"; + +import { useState, useEffect, useRef } from "react"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardHeader, + CardTitle, + CardDescription, +} from "@/components/ui/card"; +import { Textarea } from "@/components/ui/textarea"; +import { Message } from "@/lib/types"; +import { Agent } from "@/components/agent"; +import { Tool } from "@/components/tool"; +import { TestFiles } from "./test-files"; +import Feedback from "./feedback"; + +export default function WebSocketDemo() { + const [messages, setMessages] = useState([]); + const [scenarioCount, setScenarioCount] = useState(0); + const [fileNames, setFileNames] = useState([]); + const [scenario, setScenario] = useState(""); + const [feedback, setFeedback] = useState(""); + const [inputValue, setInputValue] = useState( + "https://ai-hackathon-demo-delta.vercel.app/" + ); + const [isConnected, setIsConnected] = useState(false); + const [isPaused, setIsPaused] = useState(false); + const wsRef = useRef(null); + const scrollAreaRef = useRef(null); + + const addMessage = (message: string) => { + setMessages((prev) => [...prev, message]); + }; + + const handleClose = () => { + if (!wsRef.current) return; + wsRef.current.close(); + }; + + const handlePause = () => { + if (!wsRef.current) return; + if (isPaused) { + wsRef.current.send("RESUME"); + } else { + wsRef.current.send("PAUSE"); + } + }; + + const handleSend = () => { + if (!wsRef.current) { + try { + console.log("Attempting to connect to WebSocket..."); + wsRef.current = new WebSocket("ws://localhost:8080/ws"); + + wsRef.current.onopen = () => { + console.log("WebSocket connection opened successfully"); + setIsConnected(true); + addMessage("OPEN"); + addMessage(`SEND '${inputValue}'`); + if (wsRef.current) { + wsRef.current.send(inputValue); + } + }; + + wsRef.current.onclose = (event) => { + console.log("WebSocket connection closed:", event.code, event.reason); + setIsConnected(false); + setIsPaused(false); + addMessage( + `CLOSE '${event.code}${ + event.reason ? `, Reason: ${event.reason}` : "" + }'` + ); + wsRef.current = null; + }; + + wsRef.current.onmessage = (evt) => { + console.log(evt.data); + addMessage(evt.data); + const id = evt.data.split(" ")[0]; + if (id === "SCENARIOS") { + const numScenarios = parseInt(evt.data.split(" ")[1]); + setScenarioCount(numScenarios); + } + if (id === "FILENAME") { + const fileName = evt.data.split(" ")[1]; + setFileNames((prev) => [...prev, fileName]); + } + if (id === "SCENARIO") { + const scenario = evt.data.substring(evt.data.indexOf(" ") + 1); + setScenario(scenario); + } + if (id === "FEEDBACK") { + const feedback = evt.data.substring(evt.data.indexOf(" ") + 1); + setFeedback(feedback); + } + if (id === "STATUS") { + const status = evt.data.split(" ")[1]; + setIsPaused(status === "Paused"); + } + }; + + wsRef.current.onerror = (error) => { + console.error("WebSocket error:", error); + addMessage( + `ERROR 'Connection failed - check browser console for details'` + ); + }; + } catch (error: any) { + console.error("WebSocket connection error:", error); + addMessage( + `ERROR 'Failed to connect to WebSocket server - ${error.message}'` + ); + } + return; + } + addMessage(`SEND: ${inputValue}`); + wsRef.current.send(inputValue); + }; + + useEffect(() => { + if (scrollAreaRef.current) { + scrollAreaRef.current.scrollTop = scrollAreaRef.current.scrollHeight; + } + }, [messages]); + + return ( +
+ + + End-to-end Test Generation + + Generate end-to-end tests that are passing with just a prompt and + the website URL. + + + +
+
+
+
+