diff --git a/docker-compose.yml b/docker-compose.yml index 99fb2013a..3469fa616 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -35,20 +35,21 @@ services: - API_RATE_LIMIT_MS=${API_RATE_LIMIT_MS:-2000} - API_TIMEOUT_MS=${API_TIMEOUT_MS:-90000} - API_RETRY_DELAY_MS=${API_RETRY_DELAY_MS:-10000} - # Proxmox configuration - default node - - PROXMOX_HOST=${PROXMOX_HOST:-} - - PROXMOX_NODE=${PROXMOX_NODE:-} - - PROXMOX_TOKEN_ID=${PROXMOX_TOKEN_ID:-} - - PROXMOX_TOKEN_SECRET=${PROXMOX_TOKEN_SECRET:-} - # Proxmox configuration - additional nodes - - PROXMOX_HOST_2=${PROXMOX_HOST_2:-} - - PROXMOX_NODE_2=${PROXMOX_NODE_2:-} - - PROXMOX_TOKEN_ID_2=${PROXMOX_TOKEN_ID_2:-} - - PROXMOX_TOKEN_SECRET_2=${PROXMOX_TOKEN_SECRET_2:-} - - PROXMOX_HOST_3=${PROXMOX_HOST_3:-} - - PROXMOX_NODE_3=${PROXMOX_NODE_3:-} - - PROXMOX_TOKEN_ID_3=${PROXMOX_TOKEN_ID_3:-} - - PROXMOX_TOKEN_SECRET_3=${PROXMOX_TOKEN_SECRET_3:-} + # Proxmox configuration - Node 1 + - PROXMOX_NODE_1_NAME=${PROXMOX_NODE_1_NAME:-} + - PROXMOX_NODE_1_HOST=${PROXMOX_NODE_1_HOST:-} + - PROXMOX_NODE_1_TOKEN_ID=${PROXMOX_NODE_1_TOKEN_ID:-} + - PROXMOX_NODE_1_TOKEN_SECRET=${PROXMOX_NODE_1_TOKEN_SECRET:-} + # Proxmox configuration - Node 2 (optional) + - PROXMOX_NODE_2_NAME=${PROXMOX_NODE_2_NAME:-} + - PROXMOX_NODE_2_HOST=${PROXMOX_NODE_2_HOST:-} + - PROXMOX_NODE_2_TOKEN_ID=${PROXMOX_NODE_2_TOKEN_ID:-} + - PROXMOX_NODE_2_TOKEN_SECRET=${PROXMOX_NODE_2_TOKEN_SECRET:-} + # Proxmox configuration - Node 3 (optional) + - PROXMOX_NODE_3_NAME=${PROXMOX_NODE_3_NAME:-} + - PROXMOX_NODE_3_HOST=${PROXMOX_NODE_3_HOST:-} + - PROXMOX_NODE_3_TOKEN_ID=${PROXMOX_NODE_3_TOKEN_ID:-} + - PROXMOX_NODE_3_TOKEN_SECRET=${PROXMOX_NODE_3_TOKEN_SECRET:-} # SSL verification settings - IGNORE_SSL_ERRORS=${IGNORE_SSL_ERRORS:-false} - NODE_TLS_REJECT_UNAUTHORIZED=${NODE_TLS_REJECT_UNAUTHORIZED:-} diff --git a/frontend/package.json b/frontend/package.json index b7b88ca1e..e32644a06 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,8 +9,7 @@ "scripts": { "dev": "vite --port 3000", "build": "vite build", - "preview": "vite preview", - "test": "echo \"Error: no test specified\" && exit 1" + "preview": "vite preview" }, "keywords": [], "author": "", diff --git a/package.json b/package.json index 421896147..74f3f9255 100644 --- a/package.json +++ b/package.json @@ -8,37 +8,12 @@ "scripts": { "start": "node dist/server.js", "build": "tsc", - "lint": "eslint . --ext .ts", - "test": "echo \"Error: no test specified\" && exit 1", "dev": "node scripts/configure-env.js dev && NODE_ENV=development node scripts/start.js dev", - "dev:server": "nodemon --exec ts-node src/server.ts", "dev:docker": "[ -f .env ] || cp .env.example .env && node scripts/configure-env.js dev && docker compose up --build", - "dev:logs": "node scripts/run-with-logs.js dev", "prod": "node scripts/configure-env.js prod && node scripts/check-config.js && node scripts/start.js prod", "prod:docker": "[ -f .env ] || cp .env.example .env && node scripts/configure-env.js prod && node scripts/check-config.js && docker compose up --build", - "prod:logs": "node scripts/run-with-logs.js prod", - "install:pulse": "chmod +x scripts/install.sh && scripts/install.sh", - "logs": "docker compose logs -f", - "logs:monitor": "node scripts/monitor-logs.js", - "logs:errors": "node scripts/monitor-logs.js --level=error", - "logs:cluster": "node scripts/monitor-logs.js --search=cluster", - "logs:proxmox": "node scripts/monitor-logs.js --component=ProxmoxClient", - "logs:node-manager": "node scripts/monitor-logs.js --component=NodeManager", - "ai:start-prod": "node scripts/ai-helper.js start-server --env=prod", - "ai:start-dev": "node scripts/ai-helper.js start-server --env=dev", - "ai:check-logs": "node scripts/ai-helper.js check-logs", - "ai:check-cluster": "node scripts/ai-helper.js check-cluster", - "ai:check-status": "node scripts/ai-helper.js check-status", - "ai:stop": "node scripts/ai-helper.js stop-server", - "ai:verify-config": "node scripts/ai-helper.js verify-config", - "verify:config": "node scripts/verify-cluster-config.js", "stop": "docker compose stop", - "restart": "docker compose restart", - "status": "docker compose ps", - "cleanup": "docker compose down --rmi all --volumes --remove-orphans", - "screenshots": "./scripts/update-screenshots.sh", - "generate:logos": "npm install canvas && node scripts/generate-logo-pngs.js && node scripts/generate-logo-with-text.js", - "test:mock-cluster": "npx ts-node scripts/test-mock-cluster.ts" + "cleanup": "docker compose down --rmi all --volumes --remove-orphans" }, "keywords": [ "proxmox", @@ -65,12 +40,10 @@ "@types/socket.io": "^3.0.2", "@types/uuid": "^10.0.0", "axios": "^1.8.2", - "canvas": "^3.1.0", "cors": "^2.8.5", "dotenv": "^16.4.7", "express": "^4.21.2", "node-fetch": "^3.3.2", - "puppeteer": "^24.3.1", "socket.io": "^4.8.1", "socket.io-client": "^4.8.1", "ts-node": "^10.9.2", diff --git a/scripts/ai-helper.js b/scripts/ai-helper.js deleted file mode 100755 index 9a19aeea4..000000000 --- a/scripts/ai-helper.js +++ /dev/null @@ -1,336 +0,0 @@ -#!/usr/bin/env node - -/** - * AI Helper Script - * - * This script is designed to help AI assistants run commands and immediately see their output - * without getting stuck waiting for long-running processes to complete. - * - * It runs a command in the background, captures the initial output, and returns control to the terminal. - * - * Usage: - * node scripts/ai-helper.js [command] [options] - * - * Commands: - * start-server Start the server in the background - * check-logs Check the most recent logs - * check-cluster Check cluster-related logs - * check-status Check if the server is running - * stop-server Stop the server - * verify-config Verify the current environment configuration - * - * Options: - * --env= Environment (prod, dev, or dev:no-cluster, default: prod) - * --lines= Number of log lines to show (default: 20) - * --help Show this help message - * - * Examples: - * node scripts/ai-helper.js start-server --env=prod - * node scripts/ai-helper.js check-logs --lines=50 - * node scripts/ai-helper.js check-cluster - * node scripts/ai-helper.js verify-config - */ - -const { execSync, spawn } = require('child_process'); -const fs = require('fs'); -const path = require('path'); - -// Parse command line arguments -const args = process.argv.slice(2); -const command = args[0]; -const options = { - env: getArgValue(args, '--env') || 'prod', - lines: parseInt(getArgValue(args, '--lines') || '20', 10), - help: args.includes('--help') || args.includes('-h') -}; - -// Show help if requested or no command provided -if (options.help || !command) { - console.log(fs.readFileSync(__filename, 'utf8') - .split('\n') - .filter(line => line.startsWith(' *')) - .map(line => line.substring(3)) - .join('\n')); - process.exit(0); -} - -// Validate environment -if (!['prod', 'prod:no-cluster', 'dev', 'dev:no-cluster'].includes(options.env)) { - console.error(`Error: Unknown environment "${options.env}". Use "prod", "prod:no-cluster", "dev", or "dev:no-cluster".`); - process.exit(1); -} - -// Ensure logs directory exists -if (!fs.existsSync('logs')) { - fs.mkdirSync('logs'); -} - -// Create a unique log file for this run -const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); -const logFile = `logs/ai-helper-${timestamp}.log`; - -// Execute the requested command -switch (command) { - case 'start-server': - startServer(options.env); - break; - case 'check-logs': - checkLogs(options.lines); - break; - case 'check-cluster': - checkClusterLogs(options.lines); - break; - case 'check-status': - checkStatus(); - break; - case 'stop-server': - stopServer(); - break; - case 'verify-config': - verifyConfig(); - break; - default: - console.error(`Unknown command: ${command}`); - console.log('Run with --help to see available commands'); - process.exit(1); -} - -// Helper function to get argument value -function getArgValue(args, name) { - const arg = args.find(a => a.startsWith(`${name}=`)); - return arg ? arg.split('=')[1] : null; -} - -// Start the server in the background -function startServer(env) { - console.log(`Starting server in ${env} mode...`); - - try { - // First, configure the environment - execSync(`node scripts/configure-env.js ${env}`, { stdio: 'inherit' }); - - // Build the application if needed - if (env === 'prod') { - console.log('Building the application...'); - execSync('npm run build', { stdio: 'inherit' }); - } - - // Start the server in the background - const serverProcess = spawn('node', [ - env === 'prod' ? 'dist/server.js' : 'scripts/start.js', - env === 'prod' ? '' : 'dev:mock' - ].filter(Boolean), { - detached: true, - stdio: ['ignore', fs.openSync(logFile, 'w'), fs.openSync(logFile, 'w')] - }); - - // Don't wait for the server to exit - serverProcess.unref(); - - console.log(`Server started with PID ${serverProcess.pid}`); - console.log(`Logs are being written to ${logFile}`); - - // Wait a moment for the server to start - setTimeout(() => { - // Show the initial logs - console.log('\nInitial server logs:'); - try { - const initialLogs = execSync(`tail -n 20 ${logFile}`).toString(); - console.log(initialLogs || 'No logs yet'); - } catch (error) { - console.log('No logs available yet'); - } - - console.log('\nTo check logs later, run:'); - console.log(` node scripts/ai-helper.js check-logs`); - console.log('To stop the server, run:'); - console.log(` node scripts/ai-helper.js stop-server`); - - // For development mode, remind the user to access the application on port 7654 - if (env !== 'prod') { - console.log('\nAccess the application at:'); - console.log(' http://localhost:7654'); - } - }, 2000); - } catch (error) { - console.error('Error starting server:', error.message); - process.exit(1); - } -} - -// Check the most recent logs -function checkLogs(lines) { - console.log(`Checking the most recent logs (${lines} lines)...`); - - try { - // Find the most recent log file - const logDir = path.resolve(process.cwd(), 'logs'); - const logFiles = fs.readdirSync(logDir) - .filter(file => file.endsWith('.log')) - .map(file => ({ - name: file, - time: fs.statSync(path.join(logDir, file)).mtime.getTime() - })) - .sort((a, b) => b.time - a.time); - - if (logFiles.length === 0) { - console.log('No log files found'); - return; - } - - const recentLogFile = path.join(logDir, logFiles[0].name); - console.log(`Most recent log file: ${recentLogFile}`); - - // Show the logs - const logs = execSync(`tail -n ${lines} ${recentLogFile}`).toString(); - console.log('\nRecent logs:'); - console.log(logs || 'No logs found'); - } catch (error) { - console.error('Error checking logs:', error.message); - } -} - -// Check cluster-related logs -function checkClusterLogs(lines) { - console.log('Checking cluster-related logs...'); - - try { - // Find the most recent log file - const logDir = path.resolve(process.cwd(), 'logs'); - const logFiles = fs.readdirSync(logDir) - .filter(file => file.endsWith('.log')) - .map(file => ({ - name: file, - time: fs.statSync(path.join(logDir, file)).mtime.getTime() - })) - .sort((a, b) => b.time - a.time); - - if (logFiles.length === 0) { - console.log('No log files found'); - return; - } - - const recentLogFile = path.join(logDir, logFiles[0].name); - console.log(`Searching in: ${recentLogFile}`); - - // Search for cluster-related logs - const grepCommand = `grep -i "cluster\\|clusterMode\\|autoDetectCluster" ${recentLogFile} | tail -n ${lines}`; - try { - const clusterLogs = execSync(grepCommand).toString(); - console.log('\nCluster-related logs:'); - console.log(clusterLogs || 'No cluster-related logs found'); - } catch (error) { - // grep returns exit code 1 if no matches found - console.log('No cluster-related logs found'); - } - } catch (error) { - console.error('Error checking cluster logs:', error.message); - } -} - -// Check if the server is running -function checkStatus() { - console.log('Checking server status...'); - - try { - const psOutput = execSync('ps aux | grep "[n]ode.*server.js\\|[n]ode.*start.js"').toString(); - console.log('\nRunning server processes:'); - console.log(psOutput || 'No server processes found'); - - // Check if the frontend is responding - try { - console.log('\nChecking frontend on port 7654:'); - // Just check if we get a 200 response, don't try to parse the HTML - const frontendResponse = execSync('curl -s -o /dev/null -w "%{http_code}" http://localhost:7654/').toString(); - if (frontendResponse.trim() === '200') { - console.log('✅ Frontend is responding (HTTP 200)'); - } else { - console.log(`❌ Frontend returned HTTP ${frontendResponse}`); - } - } catch (error) { - console.log('❌ Frontend is not responding'); - } - - // Check if the mock server is responding (in dev mode) - try { - console.log('\nChecking mock server on port 7656:'); - const mockResponse = execSync('curl -s -o /dev/null -w "%{http_code}" http://localhost:7656/').toString(); - if (mockResponse.trim() === '200') { - console.log('✅ Mock server is responding (HTTP 200)'); - } else { - console.log(`❌ Mock server returned HTTP ${mockResponse}`); - } - } catch (error) { - console.log('❌ Mock server is not responding (this is normal in production mode)'); - } - - // Check if the API is responding - try { - console.log('\nChecking API on port 7654 (via frontend proxy):'); - const apiResponse = execSync('curl -s http://localhost:7654/api/nodes | head -n 5').toString(); - if (apiResponse && apiResponse.includes('nodes')) { - console.log('✅ API is responding via frontend proxy'); - console.log('First few lines of API response:'); - console.log(apiResponse); - } else { - console.log('❌ API response via frontend proxy is invalid'); - console.log(apiResponse); - } - } catch (error) { - console.log('❌ API is not responding via frontend proxy'); - - // Try direct API access on port 7656 (for development mode) - try { - console.log('\nTrying direct API access on port 7656:'); - const directApiResponse = execSync('curl -s http://localhost:7656/api/nodes | head -n 5').toString(); - console.log(directApiResponse); - console.log('✅ API is responding directly on port 7656'); - } catch (error) { - console.log('❌ API is not responding on port 7656 either'); - } - } - - console.log('\nServer information:'); - console.log('- The frontend is running on port 7654 (accessible in browser)'); - console.log('- The backend API is running on port 7656 (internal only)'); - console.log('- The mock data server is running on port 7656 (in development mode)'); - - } catch (error) { - console.log('No server processes found'); - } -} - -// Stop the server -function stopServer() { - console.log('Stopping server processes...'); - - try { - // Kill processes by pattern - execSync('pkill -f "node.*server.js\\|node.*start.js\\|vite"'); - console.log('Server processes stopped by pattern'); - } catch (error) { - console.log('No matching processes found to stop by pattern'); - } - - try { - // Kill processes by port - execSync('npx kill-port 7654 7656 3000'); - console.log('Processes on ports 7654, 7656, and 3000 stopped'); - } catch (error) { - console.log('No processes found on ports 7654, 7656, or 3000'); - } - - console.log('All server processes have been stopped'); -} - -// Verify the current environment configuration -function verifyConfig() { - console.log('Verifying environment configuration...'); - - try { - execSync('node scripts/verify-cluster-config.js', { stdio: 'inherit' }); - } catch (error) { - console.error('Error verifying configuration:', error.message); - process.exit(1); - } -} \ No newline at end of file diff --git a/scripts/debug-proxy.sh b/scripts/debug-proxy.sh deleted file mode 100755 index 8fff1d514..000000000 --- a/scripts/debug-proxy.sh +++ /dev/null @@ -1,157 +0,0 @@ -#!/bin/bash - -# Pulse Debug Proxy -# This script handles everything needed for testing with simulated data -# and includes a debug proxy to log all socket.io messages - -# Colors for terminal output -GREEN='\033[0;32m' -BLUE='\033[0;34m' -YELLOW='\033[1;33m' -RED='\033[0;31m' -NC='\033[0m' # No Color - -# Port configuration -MOCK_PORT=7656 -PROXY_PORT=7657 -FRONTEND_PORT=7654 - -echo -e "${BLUE}" -echo "╔════════════════════════════════════════════════════════════╗" -echo "║ ║" -echo "║ Pulse Debug Proxy ║" -echo "║ ║" -echo "║ This script will: ║" -echo "║ 1. Kill any existing Node.js processes ║" -echo "║ 2. Start the mock data server ║" -echo "║ 3. Start the debug proxy ║" -echo "║ 4. Start the frontend with connection to the proxy ║" -echo "║ 5. Log all socket.io messages for debugging ║" -echo "║ ║" -echo "╚════════════════════════════════════════════════════════════╝" -echo -e "${NC}" - -# Function to check if a command exists -command_exists() { - command -v "$1" >/dev/null 2>&1 -} - -# Check for required commands -if ! command_exists node; then - echo -e "${RED}Error: Node.js is not installed. Please install Node.js to continue.${NC}" - exit 1 -fi - -# Kill any existing Node.js processes -echo -e "${YELLOW}Killing any existing Node.js processes...${NC}" -pkill -f "node scripts/generate-mock-data.js" 2>/dev/null -pkill -f "node scripts/debug-socket.js" 2>/dev/null -pkill -f "vite" 2>/dev/null -sleep 1 - -# Check if ports are in use -port_check() { - lsof -i:$1 >/dev/null 2>&1 - return $? -} - -if port_check $MOCK_PORT; then - echo -e "${RED}Error: Port $MOCK_PORT is already in use. Please free this port and try again.${NC}" - echo -e "${YELLOW}You can try: lsof -i:$MOCK_PORT to see what's using it.${NC}" - exit 1 -fi - -if port_check $PROXY_PORT; then - echo -e "${RED}Error: Port $PROXY_PORT is already in use. Please free this port and try again.${NC}" - echo -e "${YELLOW}You can try: lsof -i:$PROXY_PORT to see what's using it.${NC}" - exit 1 -fi - -if port_check $FRONTEND_PORT; then - echo -e "${RED}Error: Port $FRONTEND_PORT is already in use. Please free this port and try again.${NC}" - echo -e "${YELLOW}You can try: lsof -i:$FRONTEND_PORT to see what's using it.${NC}" - exit 1 -fi - -# Start the mock data server -echo -e "${GREEN}Starting mock data server on port $MOCK_PORT...${NC}" -node scripts/generate-mock-data.js > /tmp/pulse-mock-server.log 2>&1 & -MOCK_PID=$! - -# Wait for the mock server to start -echo -e "${YELLOW}Waiting for mock server to start...${NC}" -sleep 2 - -# Check if mock server is running -if ! ps -p $MOCK_PID > /dev/null; then - echo -e "${RED}Error: Mock server failed to start. Check /tmp/pulse-mock-server.log for details.${NC}" - exit 1 -fi - -# Start the debug proxy -echo -e "${GREEN}Starting debug proxy on port $PROXY_PORT...${NC}" -node scripts/debug-socket.js > /tmp/pulse-debug-proxy.log 2>&1 & -PROXY_PID=$! - -# Wait for the proxy to start -echo -e "${YELLOW}Waiting for debug proxy to start...${NC}" -sleep 2 - -# Check if proxy is running -if ! ps -p $PROXY_PID > /dev/null; then - echo -e "${RED}Error: Debug proxy failed to start. Check /tmp/pulse-debug-proxy.log for details.${NC}" - kill $MOCK_PID - exit 1 -fi - -# Start the frontend -echo -e "${GREEN}Starting frontend on port $FRONTEND_PORT...${NC}" -cd frontend && VITE_API_URL=http://localhost:$PROXY_PORT npm run dev > /tmp/pulse-frontend.log 2>&1 & -FRONTEND_PID=$! - -# Wait for the frontend to start -echo -e "${YELLOW}Waiting for frontend to start...${NC}" -sleep 5 - -# Check if frontend is running -if ! ps -p $FRONTEND_PID > /dev/null; then - echo -e "${RED}Error: Frontend failed to start. Check /tmp/pulse-frontend.log for details.${NC}" - kill $MOCK_PID - kill $PROXY_PID - exit 1 -fi - -# Open the browser -echo -e "${GREEN}Opening browser to http://localhost:$FRONTEND_PORT${NC}" -if command_exists open; then - # macOS - open "http://localhost:$FRONTEND_PORT" -elif command_exists xdg-open; then - # Linux - xdg-open "http://localhost:$FRONTEND_PORT" -elif command_exists explorer; then - # Windows - explorer "http://localhost:$FRONTEND_PORT" -else - echo -e "${YELLOW}Could not automatically open browser. Please open http://localhost:$FRONTEND_PORT manually.${NC}" -fi - -echo -e "${GREEN}Everything is running in debug mode!${NC}" -echo -e "${YELLOW}All socket.io messages are being logged to ./socket-debug.log${NC}" -echo -e "${YELLOW}Press Ctrl+C when you're done to stop all processes.${NC}" - -# Function to clean up on exit -cleanup() { - echo -e "\n${GREEN}Cleaning up...${NC}" - kill $MOCK_PID 2>/dev/null - kill $PROXY_PID 2>/dev/null - kill $FRONTEND_PID 2>/dev/null - echo -e "${GREEN}Done! Debug logs are available in ./socket-debug.log${NC}" - exit 0 -} - -# Set up trap to catch Ctrl+C -trap cleanup SIGINT - -# Wait for user to press Ctrl+C -wait \ No newline at end of file diff --git a/scripts/debug-socket.js b/scripts/debug-socket.js deleted file mode 100644 index 9c196a6f0..000000000 --- a/scripts/debug-socket.js +++ /dev/null @@ -1,120 +0,0 @@ -/** - * Socket.io Debug Proxy for Pulse - * - * This script creates a proxy server that sits between the frontend and backend, - * logging all socket.io messages to help debug connection issues. - */ - -const express = require('express'); -const http = require('http'); -const { Server: SocketServer } = require('socket.io'); -const { io: SocketClient } = require('socket.io-client'); -const fs = require('fs'); - -// Create Express app and HTTP server for the proxy -const app = express(); -const server = http.createServer(app); -const io = new SocketServer(server, { - cors: { - origin: '*', - methods: ['GET', 'POST'] - } -}); - -// Configuration -const PROXY_PORT = 7657; -const BACKEND_PORT = 7656; -const BACKEND_URL = `http://localhost:${BACKEND_PORT}`; -const LOG_FILE = './socket-debug.log'; - -// Clear previous log file -fs.writeFileSync(LOG_FILE, '--- Socket.io Debug Log ---\n\n'); - -// Helper function to log messages -const logMessage = (direction, type, data) => { - const timestamp = new Date().toISOString(); - const message = `[${timestamp}] ${direction} | ${type} | ${JSON.stringify(data, null, 2)}\n`; - - console.log(`${direction} | ${type}`); - fs.appendFileSync(LOG_FILE, message); -}; - -// Connect to the real backend with reconnection options -const backendSocket = SocketClient(BACKEND_URL, { - transports: ['websocket', 'polling'], - reconnection: true, - reconnectionAttempts: 10, - reconnectionDelay: 1000 -}); - -// Handle connections from the frontend -io.on('connection', (frontendSocket) => { - console.log(`Frontend connected: ${frontendSocket.id}`); - logMessage('INFO', 'FRONTEND_CONNECTED', { socketId: frontendSocket.id }); - - // Request initial data from backend when frontend connects - // This ensures we capture the initial data messages - if (backendSocket.connected) { - console.log('Requesting initial data from backend'); - logMessage('INFO', 'REQUESTING_INITIAL_DATA', {}); - - // Emit a custom message to request initial data - // The backend should respond with the initial data messages - backendSocket.emit('requestInitialData'); - } - - // Handle messages from frontend to backend - frontendSocket.onAny((event, ...args) => { - logMessage('FRONTEND → BACKEND', event, args); - backendSocket.emit(event, ...args); - }); - - // Handle disconnection - frontendSocket.on('disconnect', () => { - console.log(`Frontend disconnected: ${frontendSocket.id}`); - logMessage('INFO', 'FRONTEND_DISCONNECTED', { socketId: frontendSocket.id }); - }); - - // Forward backend messages to frontend - backendSocket.onAny((event, ...args) => { - logMessage('BACKEND → FRONTEND', event, args); - frontendSocket.emit(event, ...args); - }); -}); - -// Handle backend connection events -backendSocket.on('connect', () => { - console.log(`Connected to backend: ${backendSocket.id}`); - logMessage('INFO', 'BACKEND_CONNECTED', { socketId: backendSocket.id }); -}); - -backendSocket.on('reconnect', (attemptNumber) => { - console.log(`Reconnected to backend after ${attemptNumber} attempts`); - logMessage('INFO', 'BACKEND_RECONNECTED', { attemptNumber }); -}); - -backendSocket.on('disconnect', () => { - console.log('Disconnected from backend'); - logMessage('INFO', 'BACKEND_DISCONNECTED', {}); -}); - -backendSocket.on('connect_error', (err) => { - console.error(`Backend connection error: ${err.message}`); - logMessage('ERROR', 'BACKEND_CONNECTION_ERROR', { error: err.message }); -}); - -// Start the proxy server -server.listen(PROXY_PORT, () => { - console.log(` - ╔════════════════════════════════════════════════════════════╗ - ║ ║ - ║ Socket.io Debug Proxy ║ - ║ ║ - ║ Proxy running on port ${PROXY_PORT} ║ - ║ Forwarding to backend on port ${BACKEND_PORT} ║ - ║ ║ - ║ All messages are being logged to ${LOG_FILE} ║ - ║ ║ - ╚════════════════════════════════════════════════════════════╝ - `); -}); \ No newline at end of file diff --git a/scripts/generate-logo-pngs.js b/scripts/generate-logo-pngs.js index d2e1063f0..9cfd1f8a9 100644 --- a/scripts/generate-logo-pngs.js +++ b/scripts/generate-logo-pngs.js @@ -1,87 +1,45 @@ +const { createCanvas } = require('canvas'); const fs = require('fs'); const path = require('path'); -const { createCanvas } = require('canvas'); -// Create directory for logos if it doesn't exist -const logoDir = path.join(__dirname, '../public/logos'); -if (!fs.existsSync(logoDir)) { - fs.mkdirSync(logoDir, { recursive: true }); +// Create output directory if it doesn't exist +const outputDir = path.join(__dirname, '..', 'public', 'images'); +if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); } -// Sizes to generate (in pixels) -const sizes = [16, 32, 64, 128, 256, 512, 1024]; +// Generate different sizes of the logo +const sizes = [16, 32, 64, 128, 256, 512]; -// Function to draw the Pulse logo -function drawLogo(ctx, size) { - const center = size / 2; - const radius = size / 2; - - // Background circle with gradient - const bgGradient = ctx.createLinearGradient(0, 0, size, size); - bgGradient.addColorStop(0, 'rgba(58, 123, 213, 0.8)'); // #3a7bd5 with opacity - bgGradient.addColorStop(1, 'rgba(58, 123, 213, 0.7)'); - - ctx.fillStyle = bgGradient; - ctx.beginPath(); - ctx.arc(center, center, radius, 0, Math.PI * 2); - ctx.fill(); - - // Outer ring gradient - const ringGradient = ctx.createLinearGradient(0, 0, size, size); - ringGradient.addColorStop(0, 'rgba(255, 255, 255, 0.2)'); - ringGradient.addColorStop(1, 'rgba(255, 255, 255, 0.1)'); - - ctx.fillStyle = ringGradient; - ctx.beginPath(); - ctx.arc(center, center, radius * 0.95, 0, Math.PI * 2); - ctx.fill(); - - // Pulse ring (static representation) - ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)'; - ctx.lineWidth = size * 0.06; - ctx.beginPath(); - ctx.arc(center, center, radius * 0.7, 0, Math.PI * 2); - ctx.stroke(); - - // Center dot with gradient - const centerGradient = ctx.createLinearGradient( - center - radius * 0.3, - center - radius * 0.3, - center + radius * 0.3, - center + radius * 0.3 - ); - centerGradient.addColorStop(0, '#ffffff'); - centerGradient.addColorStop(1, '#f0f0f0'); - - // Add glow to center dot - ctx.shadowColor = 'rgba(255, 255, 255, 0.7)'; - ctx.shadowBlur = size * 0.1; - ctx.shadowOffsetX = 0; - ctx.shadowOffsetY = 0; - - ctx.fillStyle = centerGradient; - ctx.beginPath(); - ctx.arc(center, center, radius * 0.3, 0, Math.PI * 2); - ctx.fill(); - - // Reset shadow - ctx.shadowColor = 'transparent'; - ctx.shadowBlur = 0; -} - -// Generate logos for each size sizes.forEach(size => { const canvas = createCanvas(size, size); const ctx = canvas.getContext('2d'); - - // Draw the logo - drawLogo(ctx, size); - - // Save as PNG - const buffer = canvas.toBuffer('image/png'); - fs.writeFileSync(path.join(logoDir, `pulse-logo-${size}x${size}.png`), buffer); - - console.log(`Generated ${size}x${size} logo`); -}); -console.log('Logo generation complete!'); \ No newline at end of file + // Set background + ctx.fillStyle = '#1a1a1a'; + ctx.fillRect(0, 0, size, size); + + // Draw pulse wave + ctx.strokeStyle = '#00ff00'; + ctx.lineWidth = size * 0.1; + ctx.beginPath(); + + const amplitude = size * 0.3; + const frequency = 2 * Math.PI / size; + + for (let x = 0; x < size; x++) { + const y = size/2 + amplitude * Math.sin(frequency * x); + if (x === 0) { + ctx.moveTo(x, y); + } else { + ctx.lineTo(x, y); + } + } + + ctx.stroke(); + + // Save the image + const buffer = canvas.toBuffer('image/png'); + fs.writeFileSync(path.join(outputDir, `logo-${size}.png`), buffer); + console.log(`Generated logo-${size}.png`); +}); \ No newline at end of file diff --git a/scripts/generate-logo-with-text.js b/scripts/generate-logo-with-text.js index 4faede4f6..0df165829 100644 --- a/scripts/generate-logo-with-text.js +++ b/scripts/generate-logo-with-text.js @@ -1,116 +1,54 @@ +const { createCanvas, registerFont } = require('canvas'); const fs = require('fs'); const path = require('path'); -const { createCanvas, registerFont } = require('canvas'); -// Create directory for logos if it doesn't exist -const logoDir = path.join(__dirname, '../public/logos'); -if (!fs.existsSync(logoDir)) { - fs.mkdirSync(logoDir, { recursive: true }); +// Register the font +const fontPath = path.join(__dirname, '..', 'assets', 'fonts', 'Roboto-Bold.ttf'); +registerFont(fontPath, { family: 'Roboto' }); + +// Create output directory if it doesn't exist +const outputDir = path.join(__dirname, '..', 'public', 'images'); +if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); } -// Try to register a system font (fallback to sans-serif if not available) -try { - // On macOS, try to use SF Pro - registerFont('/System/Library/Fonts/SFCompactDisplay-Bold.otf', { family: 'SFPro', weight: 'bold' }); -} catch (e) { - console.log('Could not register system font, will use default sans-serif'); +// Create canvas +const width = 800; +const height = 200; +const canvas = createCanvas(width, height); +const ctx = canvas.getContext('2d'); + +// Set background +ctx.fillStyle = '#1a1a1a'; +ctx.fillRect(0, 0, width, height); + +// Draw pulse wave +ctx.strokeStyle = '#00ff00'; +ctx.lineWidth = 10; +ctx.beginPath(); + +const amplitude = 40; +const frequency = 2 * Math.PI / width; + +for (let x = 0; x < width; x++) { + const y = height/2 + amplitude * Math.sin(frequency * x); + if (x === 0) { + ctx.moveTo(x, y); + } else { + ctx.lineTo(x, y); + } } -// Sizes to generate (in pixels) - width x height -const sizes = [ - { width: 200, height: 60 }, - { width: 400, height: 120 }, - { width: 800, height: 240 }, -]; +ctx.stroke(); -// Function to draw the Pulse logo with text -function drawLogoWithText(ctx, width, height) { - const logoSize = height * 0.9; - const logoX = height * 0.05; - const logoY = height * 0.05; - const center = logoSize / 2; - const radius = logoSize / 2; - - // Draw the logo - // Background circle with gradient - const bgGradient = ctx.createLinearGradient(logoX, logoY, logoX + logoSize, logoY + logoSize); - bgGradient.addColorStop(0, 'rgba(58, 123, 213, 0.8)'); // #3a7bd5 with opacity - bgGradient.addColorStop(1, 'rgba(58, 123, 213, 0.7)'); - - ctx.fillStyle = bgGradient; - ctx.beginPath(); - ctx.arc(logoX + center, logoY + center, radius, 0, Math.PI * 2); - ctx.fill(); - - // Outer ring gradient - const ringGradient = ctx.createLinearGradient(logoX, logoY, logoX + logoSize, logoY + logoSize); - ringGradient.addColorStop(0, 'rgba(255, 255, 255, 0.2)'); - ringGradient.addColorStop(1, 'rgba(255, 255, 255, 0.1)'); - - ctx.fillStyle = ringGradient; - ctx.beginPath(); - ctx.arc(logoX + center, logoY + center, radius * 0.95, 0, Math.PI * 2); - ctx.fill(); - - // Pulse ring (static representation) - ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)'; - ctx.lineWidth = logoSize * 0.06; - ctx.beginPath(); - ctx.arc(logoX + center, logoY + center, radius * 0.7, 0, Math.PI * 2); - ctx.stroke(); - - // Center dot with gradient - const centerGradient = ctx.createLinearGradient( - logoX + center - radius * 0.3, - logoY + center - radius * 0.3, - logoX + center + radius * 0.3, - logoY + center + radius * 0.3 - ); - centerGradient.addColorStop(0, '#ffffff'); - centerGradient.addColorStop(1, '#f0f0f0'); - - // Add glow to center dot - ctx.shadowColor = 'rgba(255, 255, 255, 0.7)'; - ctx.shadowBlur = logoSize * 0.1; - ctx.shadowOffsetX = 0; - ctx.shadowOffsetY = 0; - - ctx.fillStyle = centerGradient; - ctx.beginPath(); - ctx.arc(logoX + center, logoY + center, radius * 0.3, 0, Math.PI * 2); - ctx.fill(); - - // Reset shadow - ctx.shadowColor = 'transparent'; - ctx.shadowBlur = 0; - - // Draw text - const textX = logoX + logoSize + (logoSize * 0.2); - const textY = height / 2 + (height * 0.1); - const fontSize = height * 0.5; - - ctx.font = `bold ${fontSize}px "SFPro", sans-serif`; - ctx.fillStyle = '#ffffff'; - ctx.textBaseline = 'middle'; - ctx.fillText('Pulse', textX, textY); -} +// Add text +ctx.fillStyle = '#ffffff'; +ctx.font = 'bold 48px Roboto'; +ctx.textAlign = 'center'; +ctx.textBaseline = 'middle'; +ctx.fillText('Pulse', width/2, height/2); -// Generate logos for each size -sizes.forEach(size => { - const canvas = createCanvas(size.width, size.height); - const ctx = canvas.getContext('2d'); - - // Fill with transparent background - ctx.clearRect(0, 0, size.width, size.height); - - // Draw the logo with text - drawLogoWithText(ctx, size.width, size.height); - - // Save as PNG - const buffer = canvas.toBuffer('image/png'); - fs.writeFileSync(path.join(logoDir, `pulse-logo-with-text-${size.width}x${size.height}.png`), buffer); - - console.log(`Generated ${size.width}x${size.height} logo with text`); -}); - -console.log('Logo with text generation complete!'); \ No newline at end of file +// Save the image +const buffer = canvas.toBuffer('image/png'); +fs.writeFileSync(path.join(outputDir, 'logo-with-text.png'), buffer); +console.log('Generated logo-with-text.png'); \ No newline at end of file diff --git a/scripts/generate-logos.sh b/scripts/generate-logos.sh old mode 100755 new mode 100644 index 08b8b3376..1d3a2b402 --- a/scripts/generate-logos.sh +++ b/scripts/generate-logos.sh @@ -1,32 +1,22 @@ #!/bin/bash -# Script to generate Pulse logo PNGs in various sizes +# Make script executable if it isn't already +chmod +x "$0" -# Ensure we're in the project root -cd "$(dirname "$0")/.." || exit +echo "Generating logos..." -# Create the logos directory if it doesn't exist -mkdir -p public/logos - -# Install the canvas dependency if not already installed +# Install canvas if not already installed if ! npm list canvas >/dev/null 2>&1; then - echo "Installing canvas dependency..." + echo "Installing canvas..." npm install canvas fi -# Generate the logos -echo "Generating square logos (icon only)..." +# Generate logo PNGs +echo "Generating logo PNGs..." node scripts/generate-logo-pngs.js -echo "Generating rectangular logos (with text)..." +# Generate logo with text +echo "Generating logo with text..." node scripts/generate-logo-with-text.js -echo "" -echo "Logo generation complete!" -echo "Logo files are available in the public/logos directory." -echo "" -echo "Available logo files:" -ls -la public/logos/*.png - -# Make the script executable -chmod +x "$(dirname "$0")/generate-logos.sh" \ No newline at end of file +echo "Logo generation complete!" \ No newline at end of file diff --git a/scripts/monitor-logs.js b/scripts/monitor-logs.js deleted file mode 100755 index 4860fe70c..000000000 --- a/scripts/monitor-logs.js +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/env node - -/** - * Log Monitor Script - * - * This script provides real-time monitoring of application logs with filtering capabilities. - * It makes troubleshooting easier by allowing you to focus on specific log types or components. - * - * Usage: - * node scripts/monitor-logs.js [options] - * - * Options: - * --level= Filter by log level (error, warn, info, debug) - * --component= Filter by component name (e.g., ProxmoxClient, NodeManager) - * --search= Search for specific text in logs - * --follow Follow log file in real-time (default: true) - * --lines= Number of lines to show initially (default: 50) - * --file= Log file to monitor (default: latest combined log) - * --color Use colored output (default: true) - * --help Show this help message - * - * Examples: - * node scripts/monitor-logs.js --level=error - * node scripts/monitor-logs.js --component=ProxmoxClient - * node scripts/monitor-logs.js --search=cluster - * node scripts/monitor-logs.js --level=info --component=NodeManager - */ - -const fs = require('fs'); -const path = require('path'); -const { spawn } = require('child_process'); -const readline = require('readline'); - -// Parse command line arguments -const args = process.argv.slice(2); -const options = { - level: getArgValue(args, '--level'), - component: getArgValue(args, '--component'), - search: getArgValue(args, '--search'), - follow: getArgValue(args, '--follow') !== 'false', - lines: parseInt(getArgValue(args, '--lines') || '50', 10), - file: getArgValue(args, '--file'), - color: getArgValue(args, '--color') !== 'false', - help: args.includes('--help') || args.includes('-h') -}; - -// Show help if requested -if (options.help) { - console.log(fs.readFileSync(__filename, 'utf8') - .split('\n') - .filter(line => line.startsWith(' *')) - .map(line => line.substring(3)) - .join('\n')); - process.exit(0); -} - -// Find the log directory -const logDir = path.resolve(process.cwd(), 'logs'); - -// Find the most recent log file if not specified -if (!options.file) { - try { - const logFiles = fs.readdirSync(logDir) - .filter(file => file.startsWith('combined') && file.endsWith('.log')) - .map(file => ({ - name: file, - time: fs.statSync(path.join(logDir, file)).mtime.getTime() - })) - .sort((a, b) => b.time - a.time); - - if (logFiles.length > 0) { - options.file = logFiles[0].name; - } else { - options.file = 'combined.log'; - } - } catch (error) { - console.error('Error finding log files:', error.message); - options.file = 'combined.log'; - } -} - -const logFile = path.join(logDir, options.file); - -// ANSI color codes -const colors = { - reset: '\x1b[0m', - bright: '\x1b[1m', - dim: '\x1b[2m', - red: '\x1b[31m', - green: '\x1b[32m', - yellow: '\x1b[33m', - blue: '\x1b[34m', - magenta: '\x1b[35m', - cyan: '\x1b[36m', - white: '\x1b[37m', - bgRed: '\x1b[41m', - bgGreen: '\x1b[42m', - bgYellow: '\x1b[43m', - bgBlue: '\x1b[44m' -}; - -// Color mapping for log levels -const levelColors = { - error: colors.red, - warn: colors.yellow, - info: colors.green, - debug: colors.blue, - silly: colors.magenta -}; - -// Check if the log file exists -if (!fs.existsSync(logFile)) { - console.error(`Log file not found: ${logFile}`); - process.exit(1); -} - -console.log(`Monitoring log file: ${logFile}`); -console.log(`Filters: ${Object.entries(options) - .filter(([key, value]) => ['level', 'component', 'search'].includes(key) && value) - .map(([key, value]) => `${key}=${value}`) - .join(', ') || 'none'}`); -console.log('Press Ctrl+C to exit\n'); - -// Build the tail command -const tailArgs = ['-n', options.lines.toString()]; -if (options.follow) { - tailArgs.push('-f'); -} -tailArgs.push(logFile); - -// Start the tail process -const tail = spawn('tail', tailArgs); - -// Process each line of output -tail.stdout.setEncoding('utf8'); -const rl = readline.createInterface({ - input: tail.stdout, - terminal: false -}); - -rl.on('line', (line) => { - try { - // Try to parse the line as JSON - const logEntry = JSON.parse(line); - - // Apply filters - if (options.level && logEntry.level !== options.level) { - return; - } - - if (options.component && - (!logEntry.component || !logEntry.component.includes(options.component))) { - return; - } - - if (options.search && - !line.toLowerCase().includes(options.search.toLowerCase())) { - return; - } - - // Format the output - let formattedLine = ''; - - if (options.color) { - const levelColor = levelColors[logEntry.level] || colors.white; - - // Timestamp - formattedLine += `${colors.dim}${new Date(logEntry.timestamp).toISOString()}${colors.reset} `; - - // Level - formattedLine += `${levelColor}${logEntry.level.toUpperCase().padEnd(5)}${colors.reset} `; - - // Component - if (logEntry.component) { - formattedLine += `${colors.cyan}[${logEntry.component}]${colors.reset} `; - } - - // Message - formattedLine += logEntry.message; - - // Highlight search term if specified - if (options.search) { - const regex = new RegExp(options.search, 'gi'); - formattedLine = formattedLine.replace(regex, match => - `${colors.bgYellow}${colors.bright}${match}${colors.reset}`); - } - - // Add metadata if present - if (logEntry.meta && Object.keys(logEntry.meta).length > 0) { - formattedLine += `\n${colors.dim}${JSON.stringify(logEntry.meta, null, 2)}${colors.reset}`; - } - } else { - // Simple formatting without colors - formattedLine = `${new Date(logEntry.timestamp).toISOString()} ${logEntry.level.toUpperCase().padEnd(5)} `; - - if (logEntry.component) { - formattedLine += `[${logEntry.component}] `; - } - - formattedLine += logEntry.message; - - // Add metadata if present - if (logEntry.meta && Object.keys(logEntry.meta).length > 0) { - formattedLine += `\n${JSON.stringify(logEntry.meta, null, 2)}`; - } - } - - console.log(formattedLine); - } catch (error) { - // If not JSON, just print the line as is - if (options.search && !line.toLowerCase().includes(options.search.toLowerCase())) { - return; - } - - if (options.color && options.search) { - const regex = new RegExp(options.search, 'gi'); - console.log(line.replace(regex, match => - `${colors.bgYellow}${colors.bright}${match}${colors.reset}`)); - } else { - console.log(line); - } - } -}); - -// Handle errors -tail.stderr.on('data', (data) => { - console.error(`Error: ${data}`); -}); - -tail.on('close', (code) => { - console.log(`Monitoring ended with code ${code}`); -}); - -// Helper function to get argument value -function getArgValue(args, name) { - const arg = args.find(a => a.startsWith(`${name}=`)); - return arg ? arg.split('=')[1] : null; -} \ No newline at end of file diff --git a/scripts/run-with-logs.js b/scripts/run-with-logs.js deleted file mode 100755 index dae3e0d4c..000000000 --- a/scripts/run-with-logs.js +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env node - -/** - * Run With Logs Script - * - * This script runs the application and monitors logs in a split terminal. - * It makes it easier to see what's happening in the application in real-time. - * - * Usage: - * node scripts/run-with-logs.js [dev|prod] [options] - * - * Options: - * --search= Search for specific text in logs - * --level= Filter by log level (error, warn, info, debug) - * --component= Filter by component name - * --help Show this help message - * - * Examples: - * node scripts/run-with-logs.js dev - * node scripts/run-with-logs.js prod --search=cluster - * node scripts/run-with-logs.js dev --level=error - */ - -const { spawn } = require('child_process'); -const fs = require('fs'); - -// Parse command line arguments -const args = process.argv.slice(2); -const env = args[0] === 'prod' ? 'prod' : 'dev'; -const help = args.includes('--help') || args.includes('-h'); - -// Show help if requested -if (help) { - console.log(fs.readFileSync(__filename, 'utf8') - .split('\n') - .filter(line => line.startsWith(' *')) - .map(line => line.substring(3)) - .join('\n')); - process.exit(0); -} - -// Extract log options -const logOptions = args - .filter(arg => arg.startsWith('--')) - .join(' '); - -// Determine which npm script to run -const npmScript = env; - -console.log(`Starting application in ${env} mode...`); - -// Create a unique log file for this run -const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); -const logFile = `logs/app-${env}-${timestamp}.log`; - -// Ensure logs directory exists -if (!fs.existsSync('logs')) { - fs.mkdirSync('logs'); -} - -// Start the application and redirect output to the log file -const app = spawn('npm', ['run', npmScript], { - stdio: ['ignore', fs.openSync(logFile, 'w'), fs.openSync(logFile, 'w')], - detached: true -}); - -// Don't wait for the app to exit -app.unref(); - -console.log(`Application started with PID ${app.pid}`); -console.log(`Logs are being written to ${logFile}`); -console.log('Starting log monitor...\n'); - -// Wait a moment for the app to start writing logs -setTimeout(() => { - // Start the log monitor - const logMonitor = spawn('node', ['scripts/monitor-logs.js', `--file=${logFile.split('/')[1]}`, '--follow=true', ...logOptions.split(' ').filter(Boolean)], { - stdio: 'inherit' - }); - - // Handle log monitor exit - logMonitor.on('exit', (code) => { - console.log(`\nLog monitor exited with code ${code}`); - console.log(`The application is still running with PID ${app.pid}`); - console.log('To stop the application, run:'); - console.log(` kill ${app.pid}`); - process.exit(0); - }); - - // Handle SIGINT (Ctrl+C) - process.on('SIGINT', () => { - console.log('\nStopping application and log monitor...'); - process.kill(-app.pid, 'SIGINT'); - process.exit(0); - }); -}, 1000); \ No newline at end of file diff --git a/scripts/start-mock-dev.bat b/scripts/start-mock-dev.bat index e6d75ea57..82af1b30b 100644 --- a/scripts/start-mock-dev.bat +++ b/scripts/start-mock-dev.bat @@ -1,77 +1,45 @@ @echo off setlocal -REM Stop any running Pulse Docker containers first -echo Stopping any running Pulse Docker containers... -where docker >nul 2>&1 -if %ERRORLEVEL% EQU 0 ( - for /f "tokens=*" %%i in ('docker ps -q --filter "name=pulse"') do ( - docker stop %%i - ) -) else ( - echo Docker not found, skipping container cleanup... -) - -REM Kill any existing servers +:: Kill any existing servers echo Killing any existing servers... -taskkill /f /im "node.exe" /fi "WINDOWTITLE eq node dist/server.js" 2>nul -call npx kill-port 7654 7655 3000 +taskkill /F /IM node.exe /FI "WINDOWTITLE eq dist/server.js" 2>nul +taskkill /F /IM node.exe /FI "WINDOWTITLE eq ts-node src/mock/run-server.ts" 2>nul +npx kill-port 7654 7655 7656 5173 -REM Set environment to development with mock data +:: Clear any existing data files that might persist between sessions +echo Clearing any persisted data from previous sessions... +node scripts/clear-data.js + +:: Set environment to development and load the environment file set NODE_ENV=development -set USE_MOCK_DATA=true -set MOCK_DATA_ENABLED=true -REM Load environment variables from .env if it exists +:: Load environment variables from .env if it exists if exist .env ( - echo Loading environment from .env - for /f "tokens=*" %%a in (.env) do ( - set "%%a" - ) + echo Loading environment from .env + for /f "tokens=*" %%a in (.env) do set "%%a" ) -REM Override with mock data settings +:: Force mock data to be enabled for development set USE_MOCK_DATA=true set MOCK_DATA_ENABLED=true -REM Start the mock data server -echo Starting mock data server... -start /b cmd /c "ts-node src/mock/run-server.ts > %TEMP%\pulse-mock-server.log 2>&1" +:: Start the mock server in the background +echo Starting mock server... +start /B node scripts/start-mock-server.js +set MOCK_SERVER_PID=%ERRORLEVEL% -REM Wait a moment for the mock server to start -timeout /t 2 /nobreak > nul +:: Build the backend +echo Building backend... +call npm run build -REM Start the backend server with mock data -echo Starting backend server with mock data on port 7655... -start /b cmd /c "set USE_MOCK_DATA=true && set MOCK_DATA_ENABLED=true && set PORT=7655 && npm run dev:server" +:: Build the frontend +echo Building frontend... +cd frontend && call npm run build && cd .. -REM Wait a moment for the server to start -timeout /t 3 /nobreak > nul +:: Start the development server +echo Starting development server... +node dist/server.js -REM Set host IP to bind to all interfaces -set HOST_IP=0.0.0.0 - -REM Verify mock data is enabled -echo Verifying mock data is enabled... -curl -s "http://localhost:7655/api/status" | findstr "mockDataEnabled" > nul -if %ERRORLEVEL% EQU 0 ( - echo ✅ Mock data is enabled -) else ( - echo ❌ Mock data is NOT enabled -) - -echo. -echo Pulse is now running with mock data! -echo - Backend API: http://localhost:7655 (internal only) -echo - Frontend UI: http://localhost:7654 (use this for development) -echo. -echo Access the application at: http://localhost:7654 -echo. - -REM Start the frontend Vite dev server -echo Starting Pulse interface with mock data on port 7654... -cd frontend && set USE_MOCK_DATA=true && set MOCK_DATA_ENABLED=true && npm run dev -- --host %HOST_IP% --port 7654 - -REM When the frontend exits, also kill the backend and mock server -taskkill /f /im "node.exe" /fi "WINDOWTITLE eq npm run dev:server" 2>nul -taskkill /f /im "node.exe" /fi "WINDOWTITLE eq ts-node src/mock/run-server.ts" 2>nul \ No newline at end of file +:: When the server exits, also kill the mock server +taskkill /F /PID %MOCK_SERVER_PID% 2>nul \ No newline at end of file diff --git a/scripts/start-mock-dev.sh b/scripts/start-mock-dev.sh old mode 100755 new mode 100644 index 42c4a9280..3f2738fd5 --- a/scripts/start-mock-dev.sh +++ b/scripts/start-mock-dev.sh @@ -3,38 +3,18 @@ # Make script executable if it isn't already chmod +x "$0" -# Check for dry run flag from command line or environment variable -DRY_RUN=false -if [ "$DRY_RUN" = "true" ]; then - echo "Dry run mode enabled via environment variable - will not actually start the server" -else - for arg in "$@"; do - if [ "$arg" == "--dry-run" ]; then - DRY_RUN=true - echo "Dry run mode enabled via command line flag - will not actually start the server" - fi - done -fi - -# Stop any running Pulse Docker containers first -echo "Stopping any running Pulse Docker containers..." -if command -v docker &> /dev/null; then - docker ps -q --filter "name=pulse" | xargs -r docker stop -else - echo "Docker not found, skipping container cleanup..." -fi - # Kill any existing servers echo "Killing any existing servers..." pkill -f "node dist/server.js" || true pkill -f "ts-node src/mock/run-server.ts" || true npx kill-port 7654 7655 7656 5173 -# Set environment to development with mock data +# Clear any existing data files that might persist between sessions +echo "Clearing any persisted data from previous sessions..." +node scripts/clear-data.js + +# Set environment to development and load the environment file export NODE_ENV=development -export USE_MOCK_DATA=true -export MOCK_DATA_ENABLED=true -export MOCK_SERVER_PORT=7656 # Load environment variables from .env if it exists if [ -f .env ]; then @@ -42,78 +22,28 @@ if [ -f .env ]; then set -a source .env set +a - # Override mock data settings - export USE_MOCK_DATA=true - export MOCK_DATA_ENABLED=true - export MOCK_SERVER_PORT=7656 fi -# Start the mock data server -echo "Starting mock data server on port 7656..." -if [ "$DRY_RUN" = false ]; then - MOCK_SERVER_PORT=7656 ts-node src/mock/run-server.ts > /tmp/pulse-mock-server.log 2>&1 & - MOCK_SERVER_PID=$! +# Force mock data to be enabled for development +export USE_MOCK_DATA=true +export MOCK_DATA_ENABLED=true - # Wait a moment for the mock server to start - sleep 2 +# Start the mock server in the background +echo "Starting mock server..." +node scripts/start-mock-server.js & +MOCK_SERVER_PID=$! - # Check if the mock data server is running - if ! ps -p $MOCK_SERVER_PID > /dev/null; then - echo "Error: Mock data server failed to start." - echo "Check the logs at /tmp/pulse-mock-server.log for details." - exit 1 - fi - - # Verify mock server is running - if curl -s http://localhost:7656 > /dev/null; then - echo "✅ Mock server is running on port 7656" - else - echo "❌ Mock server failed to start" - cat /tmp/pulse-mock-server.log - fi -else - echo "[DRY RUN] Would start mock data server with: MOCK_SERVER_PORT=7656 ts-node src/mock/run-server.ts" -fi +# Build the backend +echo "Building backend..." +npm run build -# Start the backend server with mock data on port 7654 -echo "Starting backend server with mock data on port 7654..." -if [ "$DRY_RUN" = false ]; then - USE_MOCK_DATA=true MOCK_DATA_ENABLED=true PORT=7654 npm run dev:server & - BACKEND_PID=$! +# Build the frontend +echo "Building frontend..." +cd frontend && npm run build && cd .. - # Wait a moment for the server to start - sleep 3 +# Start the development server +echo "Starting development server..." +node dist/server.js - # Verify mock data is enabled - check port 7654 where the backend is running - echo "Verifying mock data is enabled..." - curl -s "http://localhost:7654/api/status" | grep -q "mockDataEnabled" && echo "✅ Mock data is enabled" || echo "❌ Mock data is NOT enabled" -else - echo "[DRY RUN] Would start backend server with: USE_MOCK_DATA=true MOCK_DATA_ENABLED=true PORT=7654 npm run dev:server" -fi - -# Get the host IP (use 0.0.0.0 in Docker, otherwise use localhost or your local IP) -HOST_IP="0.0.0.0" -if [[ -z "${DOCKER_CONTAINER}" ]]; then - # Not in Docker, still use 0.0.0.0 to bind to all interfaces - HOST_IP="0.0.0.0" -fi - -echo "" -echo "Pulse is now running with mock data!" -echo "- Backend API: http://localhost:7654" -echo "- Mock Server: http://localhost:7656" -echo "- Frontend UI: http://localhost:5173 (use this for development)" -echo "" -echo "Access the application at: http://localhost:5173" -echo "" - -# Start the frontend Vite dev server on port 5173 -echo "Starting Pulse interface with mock data on port 5173..." -if [ "$DRY_RUN" = false ]; then - cd frontend && USE_MOCK_DATA=true MOCK_DATA_ENABLED=true npm run dev -- --host "${HOST_IP}" --port 5173 - - # When the frontend exits, also kill the backend and mock server - kill $BACKEND_PID $MOCK_SERVER_PID -else - echo "[DRY RUN] Would start frontend with: cd frontend && USE_MOCK_DATA=true MOCK_DATA_ENABLED=true npm run dev -- --host \"${HOST_IP}\" --port 5173" -fi \ No newline at end of file +# When the server exits, also kill the mock server +kill $MOCK_SERVER_PID \ No newline at end of file diff --git a/scripts/start-mock-server.js b/scripts/start-mock-server.js old mode 100755 new mode 100644 index 989d1e2e0..fc3db3ed5 --- a/scripts/start-mock-server.js +++ b/scripts/start-mock-server.js @@ -1,58 +1,84 @@ -#!/usr/bin/env node +const express = require('express'); +const cors = require('cors'); +const app = express(); -/** - * Script to start just the mock server - * Usage: node scripts/start-mock-server.js - */ +// Enable CORS +app.use(cors()); -const { spawn } = require('child_process'); -const path = require('path'); -const fs = require('fs'); -const dotenv = require('dotenv'); - -// Load environment variables -dotenv.config(); - -// Use port 7656 to avoid conflicts with the backend server -const MOCK_PORT = 7656; - -console.log(`Starting mock server on port ${MOCK_PORT}...`); - -// Set environment variables -process.env.NODE_ENV = 'development'; -process.env.USE_MOCK_DATA = 'true'; -process.env.MOCK_DATA_ENABLED = 'true'; -process.env.MOCK_SERVER_PORT = MOCK_PORT.toString(); - -// Start the mock server -const mockServer = spawn('npx', ['ts-node', 'src/mock/run-server.ts'], { - stdio: 'inherit', - env: { - ...process.env, - NODE_ENV: 'development', - USE_MOCK_DATA: 'true', - MOCK_DATA_ENABLED: 'true', - PORT: MOCK_PORT.toString(), - MOCK_SERVER_PORT: MOCK_PORT.toString() - } +// Mock data endpoints +app.get('/api/v1/cluster/status', (req, res) => { + res.json({ + nodes: [ + { + name: 'pve1', + status: 'online', + cpu: { + usage: 45.2, + cores: 4 + }, + memory: { + total: 16777216, + used: 8388608, + free: 8388608 + } + }, + { + name: 'pve2', + status: 'online', + cpu: { + usage: 32.8, + cores: 4 + }, + memory: { + total: 16777216, + used: 6291456, + free: 10485760 + } + } + ] + }); }); -// Handle mock server exit -mockServer.on('exit', (code) => { - console.log(`Mock server exited with code ${code}`); - process.exit(code); +app.get('/api/v1/cluster/resources', (req, res) => { + res.json({ + vms: [ + { + id: '100', + name: 'vm-100', + status: 'running', + node: 'pve1', + cpu: { + usage: 25.5, + cores: 2 + }, + memory: { + total: 4096, + used: 2048, + free: 2048 + } + } + ], + containers: [ + { + id: '101', + name: 'ct-101', + status: 'running', + node: 'pve2', + cpu: { + usage: 15.2, + cores: 1 + }, + memory: { + total: 2048, + used: 1024, + free: 1024 + } + } + ] + }); }); -// Handle process termination -process.on('SIGINT', () => { - console.log('Stopping mock server...'); - mockServer.kill(); -}); - -process.on('SIGTERM', () => { - console.log('Stopping mock server...'); - mockServer.kill(); -}); - -console.log(`Mock server started on port ${MOCK_PORT}`); -console.log('Press Ctrl+C to stop'); \ No newline at end of file +const PORT = process.env.MOCK_SERVER_PORT || 7655; +app.listen(PORT, () => { + console.log(`Mock server running on port ${PORT}`); +}); \ No newline at end of file diff --git a/scripts/test-cluster-api.js b/scripts/test-cluster-api.js deleted file mode 100644 index 612137c20..000000000 --- a/scripts/test-cluster-api.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Test script to check the Proxmox cluster API response - * This will help diagnose why standalone nodes are being detected as part of a cluster - */ - -const axios = require('axios'); -const https = require('https'); -require('dotenv').config(); - -// Create an axios instance with SSL verification disabled -const createClient = (host, tokenId, tokenSecret) => { - return axios.create({ - baseURL: `${host}/api2/json`, - headers: { - 'Authorization': `PVEAPIToken=${tokenId}=${tokenSecret}` - }, - httpsAgent: new https.Agent({ - rejectUnauthorized: false - }) - }); -}; - -// Test function to check cluster status -const testClusterStatus = async (host, tokenId, tokenSecret, nodeName) => { - try { - console.log(`Testing cluster status for node: ${nodeName} (${host})`); - const client = createClient(host, tokenId, tokenSecret); - - // Try to access the cluster status endpoint - const response = await client.get('/cluster/status'); - - console.log(`Response status: ${response.status}`); - console.log(`Response data: ${JSON.stringify(response.data, null, 2)}`); - - // Check if there's a cluster type in the response - if (response.data && response.data.data && Array.isArray(response.data.data)) { - const clusterInfo = response.data.data.find(item => item.type === 'cluster'); - if (clusterInfo) { - console.log(`Found cluster info: ${JSON.stringify(clusterInfo, null, 2)}`); - console.log(`This node IS part of a cluster named: ${clusterInfo.name}`); - } else { - console.log('No cluster type found in the response'); - console.log('This node is NOT part of a cluster, but the cluster API is available'); - } - } else { - console.log('No data array in response'); - console.log('This node is NOT part of a cluster'); - } - - console.log('-----------------------------------'); - } catch (error) { - console.error(`Error testing cluster status for ${nodeName}:`, error.message); - if (error.response) { - console.log(`Response status: ${error.response.status}`); - console.log(`Response data: ${JSON.stringify(error.response.data, null, 2)}`); - } - console.log('This node is NOT part of a cluster (error response)'); - console.log('-----------------------------------'); - } -}; - -// Main function to test all nodes -const testAllNodes = async () => { - // Node 1 - await testClusterStatus( - process.env.PROXMOX_NODE_1_HOST, - process.env.PROXMOX_NODE_1_TOKEN_ID, - process.env.PROXMOX_NODE_1_TOKEN_SECRET, - process.env.PROXMOX_NODE_1_NAME - ); - - // Node 2 - if (process.env.PROXMOX_NODE_2_HOST) { - await testClusterStatus( - process.env.PROXMOX_NODE_2_HOST, - process.env.PROXMOX_NODE_2_TOKEN_ID, - process.env.PROXMOX_NODE_2_TOKEN_SECRET, - process.env.PROXMOX_NODE_2_NAME - ); - } - - // Node 3 - if (process.env.PROXMOX_NODE_3_HOST) { - await testClusterStatus( - process.env.PROXMOX_NODE_3_HOST, - process.env.PROXMOX_NODE_3_TOKEN_ID, - process.env.PROXMOX_NODE_3_TOKEN_SECRET, - process.env.PROXMOX_NODE_3_NAME - ); - } -}; - -// Run the tests -testAllNodes().catch(error => { - console.error('Error running tests:', error); -}); \ No newline at end of file diff --git a/scripts/test-cluster-detection.js b/scripts/test-cluster-detection.js deleted file mode 100644 index bece36547..000000000 --- a/scripts/test-cluster-detection.js +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Test script to verify our fix for cluster detection - * This script directly tests the fixed isNodeInCluster function - */ - -const axios = require('axios'); -const https = require('https'); -require('dotenv').config(); - -// Create an axios instance with SSL verification disabled -const createClient = (host, tokenId, tokenSecret) => { - return axios.create({ - baseURL: `${host}/api2/json`, - headers: { - 'Authorization': `PVEAPIToken=${tokenId}=${tokenSecret}` - }, - httpsAgent: new https.Agent({ - rejectUnauthorized: false - }) - }); -}; - -// Our fixed isNodeInCluster function -async function isNodeInCluster(client, nodeName) { - try { - console.log(`Testing cluster detection for node: ${nodeName}`); - - // Try to access the cluster status endpoint - const response = await client.get('/cluster/status'); - - console.log(`Response status: ${response.status}`); - console.log(`Response data: ${JSON.stringify(response.data, null, 2)}`); - - if (response.data && response.data.data && Array.isArray(response.data.data)) { - // Only consider it a cluster if we find an item with type: "cluster" - const clusterInfo = response.data.data.find(item => item.type === 'cluster'); - - console.log(`Cluster info: ${JSON.stringify(clusterInfo, null, 2)}`); - - if (clusterInfo && clusterInfo.type === 'cluster') { - const clusterName = clusterInfo.name || 'proxmox-cluster'; - console.log(`Node IS part of cluster: ${clusterName}`); - return { isCluster: true, clusterName }; - } else { - console.log('Node has cluster API but no cluster type found - NOT part of a cluster'); - return { isCluster: false, clusterName: '' }; - } - } else { - console.log('Node is not part of a cluster (empty response data)'); - return { isCluster: false, clusterName: '' }; - } - } catch (error) { - // If we get a 404 error, it means the cluster endpoint doesn't exist, so the node is not part of a cluster - if (error.response && error.response.status === 404) { - console.log('Node is not part of a cluster (404 response from cluster endpoint)'); - return { isCluster: false, clusterName: '' }; - } - - // For other errors, log them but assume the node is not in a cluster - console.error('Error checking if node is in cluster:', error.message); - if (error.response) { - console.log(`Response status: ${error.response.status}`); - console.log(`Response data: ${JSON.stringify(error.response.data, null, 2)}`); - } - return { isCluster: false, clusterName: '' }; - } -} - -// Test function for a single node -async function testNode(host, tokenId, tokenSecret, nodeName) { - console.log(`\n=== Testing node: ${nodeName} (${host}) ===\n`); - try { - const client = createClient(host, tokenId, tokenSecret); - const result = await isNodeInCluster(client, nodeName); - console.log(`\nFinal result: Node ${nodeName} ${result.isCluster ? 'IS' : 'is NOT'} part of a cluster`); - if (result.isCluster) { - console.log(`Cluster name: ${result.clusterName}`); - } - } catch (error) { - console.error(`Error testing node ${nodeName}:`, error.message); - } - console.log('\n=== Test complete ===\n'); -} - -// Main function to test all nodes -async function testAllNodes() { - // Node 1 - await testNode( - process.env.PROXMOX_NODE_1_HOST, - process.env.PROXMOX_NODE_1_TOKEN_ID, - process.env.PROXMOX_NODE_1_TOKEN_SECRET, - process.env.PROXMOX_NODE_1_NAME - ); - - // Node 2 - if (process.env.PROXMOX_NODE_2_HOST) { - await testNode( - process.env.PROXMOX_NODE_2_HOST, - process.env.PROXMOX_NODE_2_TOKEN_ID, - process.env.PROXMOX_NODE_2_TOKEN_SECRET, - process.env.PROXMOX_NODE_2_NAME - ); - } - - // Node 3 - if (process.env.PROXMOX_NODE_3_HOST) { - await testNode( - process.env.PROXMOX_NODE_3_HOST, - process.env.PROXMOX_NODE_3_TOKEN_ID, - process.env.PROXMOX_NODE_3_TOKEN_SECRET, - process.env.PROXMOX_NODE_3_NAME - ); - } -} - -// Run the tests -testAllNodes().catch(error => { - console.error('Error running tests:', error); -}); \ No newline at end of file diff --git a/scripts/test-mock-cluster.ts b/scripts/test-mock-cluster.ts deleted file mode 100644 index 582c0ef6f..000000000 --- a/scripts/test-mock-cluster.ts +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Test script to demonstrate mock cluster mode - * - * This script creates mock clients for multiple nodes and shows how - * the VM and container IDs are generated with and without cluster mode. - * - * Run with: - * npx ts-node scripts/test-mock-cluster.ts - */ - -import { MockClient } from '../src/api/mock-client'; -import { NodeConfig } from '../src/types'; - -// Create mock node configs -const nodeConfigs: NodeConfig[] = [ - { - id: 'node-1', - name: 'pve-1', - host: 'http://localhost:7656', - tokenId: 'mock-token', - tokenSecret: 'mock-secret' - }, - { - id: 'node-2', - name: 'pve-2', - host: 'http://localhost:7656', - tokenId: 'mock-token', - tokenSecret: 'mock-secret' - }, - { - id: 'node-3', - name: 'pve-3', - host: 'http://localhost:7656', - tokenId: 'mock-token', - tokenSecret: 'mock-secret' - } -]; - -// Test with cluster mode enabled -async function testWithClusterMode() { - console.log('\n=== Testing with Cluster Mode Enabled ==='); - - // Set environment variables for cluster mode - process.env.MOCK_CLUSTER_ENABLED = 'true'; - process.env.MOCK_CLUSTER_NAME = 'test-cluster'; - - const clients = nodeConfigs.map(config => new MockClient(config)); - - // Get VMs and containers from each client - for (let i = 0; i < clients.length; i++) { - const client = clients[i]; - const vms = await client.getVMs(); - const containers = await client.getContainers(); - - console.log(`\nNode: ${nodeConfigs[i].name} (${nodeConfigs[i].id})`); - console.log('VMs:'); - vms.forEach(vm => { - console.log(` ${vm.id} (VMID: ${vm.vmid}, Name: ${vm.name}, Node: ${vm.node})`); - }); - - console.log('Containers:'); - containers.forEach(container => { - console.log(` ${container.id} (VMID: ${container.vmid}, Name: ${container.name}, Node: ${container.node})`); - }); - } - - // Clean up - clients.forEach(client => client.disconnect()); -} - -// Test with cluster mode disabled -async function testWithoutClusterMode() { - console.log('\n=== Testing with Cluster Mode Disabled ==='); - - // Set environment variables to disable cluster mode - process.env.MOCK_CLUSTER_ENABLED = 'false'; - - const clients = nodeConfigs.map(config => new MockClient(config)); - - // Get VMs and containers from each client - for (let i = 0; i < clients.length; i++) { - const client = clients[i]; - const vms = await client.getVMs(); - const containers = await client.getContainers(); - - console.log(`\nNode: ${nodeConfigs[i].name} (${nodeConfigs[i].id})`); - console.log('VMs:'); - vms.forEach(vm => { - console.log(` ${vm.id} (VMID: ${vm.vmid}, Name: ${vm.name}, Node: ${vm.node})`); - }); - - console.log('Containers:'); - containers.forEach(container => { - console.log(` ${container.id} (VMID: ${container.vmid}, Name: ${container.name}, Node: ${container.node})`); - }); - } - - // Clean up - clients.forEach(client => client.disconnect()); -} - -// Run the tests -async function runTests() { - try { - await testWithClusterMode(); - await testWithoutClusterMode(); - - console.log('\n=== Summary ==='); - console.log('With cluster mode enabled:'); - console.log('- VMs and containers have IDs like: test-cluster-vm-100, test-cluster-ct-200'); - console.log('- The same VMID across different nodes will have the same ID'); - console.log('- This results in deduplication in the UI'); - - console.log('\nWith cluster mode disabled:'); - console.log('- VMs and containers have IDs like: node-1-vm-100, node-2-vm-100'); - console.log('- The same VMID across different nodes will have different IDs'); - console.log('- This results in showing all VMs/containers from all nodes in the UI'); - } catch (error) { - console.error('Error running tests:', error); - } -} - -runTests(); \ No newline at end of file diff --git a/scripts/update-screenshots.sh b/scripts/update-screenshots.sh old mode 100755 new mode 100644 index 9a854fd4d..233485ec4 --- a/scripts/update-screenshots.sh +++ b/scripts/update-screenshots.sh @@ -1,134 +1,33 @@ #!/bin/bash -# Pulse for Proxmox VE Screenshot Generator -# Automates the process of generating screenshots for documentation -# by starting required servers with mock data and running the screenshot tool. +# Make script executable if it isn't already +chmod +x "$0" -# Get the project root directory -PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +echo "Updating screenshots..." -# Process tracking variables -MOCK_SERVER_PID="" -BACKEND_PID="" -FRONTEND_PID="" - -# Cleanup function to ensure all processes are stopped -cleanup() { - echo "🧹 Cleaning up processes..." - - if [ -n "$FRONTEND_PID" ]; then - echo "Stopping frontend server (PID: $FRONTEND_PID)..." - kill $FRONTEND_PID 2>/dev/null || true - fi - - if [ -n "$BACKEND_PID" ]; then - echo "Stopping backend server (PID: $BACKEND_PID)..." - kill $BACKEND_PID 2>/dev/null || true - fi - - if [ -n "$MOCK_SERVER_PID" ]; then - echo "Stopping mock server (PID: $MOCK_SERVER_PID)..." - kill $MOCK_SERVER_PID 2>/dev/null || true - fi - - echo "Killing any remaining processes..." - cd "$PROJECT_ROOT" && npm run dev:kill:all 2>/dev/null || true -} - -# Set up cleanup trap -trap cleanup EXIT INT TERM - -# Ensure clean environment -echo "🔪 Killing any existing servers..." -cd "$PROJECT_ROOT" && npm run dev:kill:all - -# Start required services -echo "🚀 Starting mock data server..." -export NODE_ENV=development -export USE_MOCK_DATA=true -export MOCK_DATA_ENABLED=true - -# Load environment variables from .env if it exists -if [ -f "$PROJECT_ROOT/.env" ]; then - echo "Loading environment from .env" - set -a - source "$PROJECT_ROOT/.env" - set +a - # Override with mock data settings - export NODE_ENV=development - export USE_MOCK_DATA=true - export MOCK_DATA_ENABLED=true +# Install puppeteer if not already installed +if ! npm list puppeteer >/dev/null 2>&1; then + echo "Installing puppeteer..." + npm install puppeteer fi -cd "$PROJECT_ROOT" && ts-node src/mock/run-server.ts > /tmp/pulse-mock-server.log 2>&1 & -MOCK_SERVER_PID=$! -echo "Mock server started with PID: $MOCK_SERVER_PID" -sleep 5 +# Create screenshots directory if it doesn't exist +mkdir -p docs/screenshots -# Check if mock server is running -if ! ps -p $MOCK_SERVER_PID > /dev/null; then - echo "❌ Error: Mock data server failed to start" - cat /tmp/pulse-mock-server.log - exit 1 -fi +# Start the application in development mode with mock data +echo "Starting application with mock data..." +npm run dev:docker & -echo "🚀 Starting backend server..." -cd "$PROJECT_ROOT" && USE_MOCK_DATA=true MOCK_DATA_ENABLED=true npm run dev:server > /tmp/pulse-backend.log 2>&1 & -BACKEND_PID=$! -echo "Backend server started with PID: $BACKEND_PID" -sleep 8 +# Wait for the application to start +echo "Waiting for application to start..." +sleep 10 -# Check if backend server is running -if ! ps -p $BACKEND_PID > /dev/null; then - echo "❌ Error: Backend server failed to start" - cat /tmp/pulse-backend.log - exit 1 -fi +# Take screenshots +echo "Taking screenshots..." +node scripts/take-screenshots.js -echo "🚀 Starting frontend server..." -cd "$PROJECT_ROOT/frontend" && USE_MOCK_DATA=true MOCK_DATA_ENABLED=true npm run dev -- --host "0.0.0.0" --port 7654 > /tmp/pulse-frontend.log 2>&1 & -FRONTEND_PID=$! -echo "Frontend server started with PID: $FRONTEND_PID" +# Stop the application +echo "Stopping application..." +npm run stop -# Wait for services to be ready -echo "⏳ Waiting for servers to start..." -sleep 15 - -# Verify services are running correctly -if ! curl -s http://localhost:7654 > /dev/null; then - echo "❌ Error: Frontend server is not running on port 7654" - cat /tmp/pulse-frontend.log - exit 1 -fi - -# Check if mock data server is responding -if ! curl -s http://localhost:7656/status > /dev/null; then - echo "❌ Error: Mock data server is not responding on port 7656" - cat /tmp/pulse-mock-server.log - exit 1 -fi - -# Check if backend is using mock data -MOCK_STATUS=$(curl -s http://localhost:7654/api/status) -if ! echo "$MOCK_STATUS" | grep -q "mockDataEnabled\":true"; then - echo "❌ Error: Server is running but mock data is not enabled" - echo "Server status: $MOCK_STATUS" - cat /tmp/pulse-backend.log - exit 1 -fi - -echo "✅ All servers are running with mock data enabled" - -# Generate screenshots -echo "📸 Running screenshot tool..." -cd "$PROJECT_ROOT/tools/screenshot-automation" && npm run build && npm start -- --config ../../screenshot-config.json -SCREENSHOT_RESULT=$? - -# Report results -if [ $SCREENSHOT_RESULT -eq 0 ]; then - echo "✅ Screenshots updated successfully!" - echo "Check the docs/images directory for the new screenshots." -else - echo "❌ Error: Failed to update screenshots" - exit 1 -fi \ No newline at end of file +echo "Screenshot update complete!" \ No newline at end of file