mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-11 14:00:29 +00:00
fix: update Docker Compose environment variables to match .env.example format
This commit is contained in:
+15
-14
@@ -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:-}
|
||||
|
||||
@@ -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": "",
|
||||
|
||||
+1
-28
@@ -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",
|
||||
|
||||
@@ -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=<env> Environment (prod, dev, or dev:no-cluster, default: prod)
|
||||
* --lines=<number> 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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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} ║
|
||||
║ ║
|
||||
╚════════════════════════════════════════════════════════════╝
|
||||
`);
|
||||
});
|
||||
@@ -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!');
|
||||
// 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`);
|
||||
});
|
||||
@@ -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!');
|
||||
// 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');
|
||||
Executable → Regular
+10
-20
@@ -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"
|
||||
echo "Logo generation complete!"
|
||||
@@ -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=<level> Filter by log level (error, warn, info, debug)
|
||||
* --component=<name> Filter by component name (e.g., ProxmoxClient, NodeManager)
|
||||
* --search=<text> Search for specific text in logs
|
||||
* --follow Follow log file in real-time (default: true)
|
||||
* --lines=<number> Number of lines to show initially (default: 50)
|
||||
* --file=<filename> 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;
|
||||
}
|
||||
@@ -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=<text> Search for specific text in logs
|
||||
* --level=<level> Filter by log level (error, warn, info, debug)
|
||||
* --component=<n> 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);
|
||||
+28
-60
@@ -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
|
||||
:: When the server exits, also kill the mock server
|
||||
taskkill /F /PID %MOCK_SERVER_PID% 2>nul
|
||||
Executable → Regular
+23
-93
@@ -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
|
||||
# When the server exits, also kill the mock server
|
||||
kill $MOCK_SERVER_PID
|
||||
Executable → Regular
+78
-52
@@ -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');
|
||||
const PORT = process.env.MOCK_SERVER_PORT || 7655;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Mock server running on port ${PORT}`);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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();
|
||||
Executable → Regular
+22
-123
@@ -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
|
||||
echo "Screenshot update complete!"
|
||||
Reference in New Issue
Block a user