mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
v1.0.5
This commit is contained in:
@@ -17,6 +17,9 @@ build/
|
||||
logs/
|
||||
*.log
|
||||
|
||||
# Reports
|
||||
reports/
|
||||
|
||||
# IDE and editor files
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
+22
-20
@@ -1,28 +1,30 @@
|
||||
FROM node:18-alpine as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /app/package*.json ./
|
||||
COPY --from=builder /app/dist ./dist
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
COPY frontend/package*.json ./frontend/
|
||||
|
||||
RUN npm ci --only=production
|
||||
# Install dependencies
|
||||
RUN npm ci
|
||||
RUN cd frontend && npm ci
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||
CMD wget -qO- http://localhost:${PORT:-3000}/api/health || exit 1
|
||||
# Copy application files
|
||||
COPY . .
|
||||
|
||||
# Expose the port
|
||||
EXPOSE ${PORT:-3000}
|
||||
# Make the startup script executable
|
||||
RUN chmod +x start-pulse.sh
|
||||
|
||||
# Start the application
|
||||
CMD ["node", "dist/server.js"]
|
||||
# Set environment variables
|
||||
ENV NODE_ENV=development
|
||||
ENV LOG_LEVEL=info
|
||||
ENV ENABLE_DEV_TOOLS=true
|
||||
ENV PORT=3000
|
||||
ENV DOCKER_CONTAINER=true
|
||||
|
||||
# Expose the backend and frontend ports
|
||||
EXPOSE 3000 5173
|
||||
|
||||
# Start both the backend and frontend (using the start-pulse.sh script)
|
||||
CMD ["./start-pulse.sh"]
|
||||
@@ -7,9 +7,7 @@ A lightweight, responsive ProxMox monitoring application that displays real-time
|
||||
- Real-time monitoring of ProxMox nodes, VMs, and containers
|
||||
- Dashboard with summary cards for nodes, guests, and resources
|
||||
- Responsive design that works on desktop and mobile
|
||||
- WebSocket connection for real-time updates
|
||||
- Development tools for easier debugging
|
||||
- Configurable polling intervals for optimal performance
|
||||
- WebSocket connection for live updates
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -18,15 +16,50 @@ A lightweight, responsive ProxMox monitoring application that displays real-time
|
||||
```
|
||||
npm install
|
||||
```
|
||||
3. Create a `.env` file based on the `.env.example` file
|
||||
4. Build the application:
|
||||
3. Install frontend dependencies:
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
5. Start the application:
|
||||
```
|
||||
npm start
|
||||
cd frontend && npm install && cd ..
|
||||
```
|
||||
4. Create a `.env` file based on the `.env.example` file
|
||||
|
||||
## Running the Application
|
||||
|
||||
The simplest way to run the application is to use one of these methods:
|
||||
|
||||
### Using the startup script directly
|
||||
|
||||
```bash
|
||||
# Make the script executable (only needed once)
|
||||
chmod +x start-pulse.sh
|
||||
|
||||
# Run the application
|
||||
./start-pulse.sh
|
||||
```
|
||||
|
||||
### Using npm
|
||||
|
||||
```bash
|
||||
# Run the application
|
||||
npm run pulse
|
||||
```
|
||||
|
||||
### Using Docker
|
||||
|
||||
```bash
|
||||
# Build the Docker image
|
||||
docker build -t proxmox-pulse .
|
||||
|
||||
# Run the Docker container
|
||||
docker run -p 3000:3000 -p 5173:5173 --env-file .env proxmox-pulse
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Kill any existing server processes
|
||||
2. Start the backend server in development mode
|
||||
3. Start the frontend Vite server
|
||||
4. Host the application at http://192.168.0.130:5173/
|
||||
|
||||
The application will show real-time metrics from your ProxMox servers configured in the .env file.
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -37,120 +70,35 @@ The application uses environment variables for configuration. You can create a `
|
||||
PROXMOX_NODE_1_NAME=Proxmox Node 1
|
||||
PROXMOX_NODE_1_HOST=https://192.168.0.132:8006
|
||||
PROXMOX_NODE_1_TOKEN_ID=root@pam!pulse
|
||||
PROXMOX_NODE_1_TOKEN_SECRET=e1850350-6afc-4b8e-ae28-472152af84f9
|
||||
PROXMOX_NODE_1_TOKEN_SECRET=your-token-secret
|
||||
|
||||
# Node 2
|
||||
PROXMOX_NODE_2_NAME=Proxmox Node 2
|
||||
PROXMOX_NODE_2_HOST=https://192.168.0.141:8006
|
||||
PROXMOX_NODE_2_TOKEN_ID=root@pam!pulse
|
||||
PROXMOX_NODE_2_TOKEN_SECRET=63e21f63-4cfd-4ba0-9b14-fc681c59d932
|
||||
PROXMOX_NODE_2_TOKEN_SECRET=your-token-secret
|
||||
|
||||
# App Configuration
|
||||
PORT=3000
|
||||
NODE_ENV=development
|
||||
LOG_LEVEL=debug
|
||||
LOG_LEVEL=info
|
||||
ENABLE_DEV_TOOLS=true
|
||||
METRICS_HISTORY_MINUTES=60
|
||||
IGNORE_SSL_ERRORS=true
|
||||
|
||||
# Polling Intervals (in milliseconds)
|
||||
NODE_POLLING_INTERVAL_MS=10000
|
||||
EVENT_POLLING_INTERVAL_MS=2000
|
||||
```
|
||||
|
||||
### Polling Intervals
|
||||
|
||||
The application uses polling to fetch data from ProxMox nodes:
|
||||
|
||||
- `NODE_POLLING_INTERVAL_MS`: How often to poll for node status, VMs, and containers (default: 10000ms)
|
||||
- `EVENT_POLLING_INTERVAL_MS`: How often to poll for events (default: 2000ms)
|
||||
|
||||
The application also implements adaptive polling for events:
|
||||
- When events are detected, polling frequency temporarily increases
|
||||
- Quick follow-up polls occur 500ms after receiving events
|
||||
- Polling frequency remains higher for 10 seconds after activity is detected
|
||||
|
||||
Decreasing these values will make the application more responsive but may increase server load. Increasing them will reduce server load but make updates less frequent.
|
||||
|
||||
### Important Note on API Tokens
|
||||
|
||||
If your ProxMox API token ID contains special characters (like `!`, `?`, `&`, etc.), you may encounter issues when using it in shell commands or other contexts. The application handles this internally, but if you're testing the connection manually, make sure to properly escape or quote the token ID.
|
||||
|
||||
For example, when using curl:
|
||||
|
||||
```bash
|
||||
# INCORRECT - will cause issues with the ! character
|
||||
curl -k -v -H "Authorization: PVEAPIToken=root@pam!pulse=your-token-secret" https://your-proxmox-host:8006/api2/json/version
|
||||
|
||||
# CORRECT - use single quotes around the token ID
|
||||
curl -k -v -H "Authorization: PVEAPIToken='root@pam!pulse'=your-token-secret" https://your-proxmox-host:8006/api2/json/version
|
||||
```
|
||||
|
||||
## Testing the Connection
|
||||
|
||||
The application includes a script to test the connection to your ProxMox nodes. This is useful for troubleshooting connection issues.
|
||||
|
||||
```bash
|
||||
npm run test:connection
|
||||
```
|
||||
|
||||
This script will:
|
||||
1. Validate your configuration
|
||||
2. Test the connection to each configured ProxMox node
|
||||
3. Check for potential issues with your API tokens
|
||||
4. Provide helpful error messages and suggestions if the connection fails
|
||||
|
||||
If you encounter connection issues, the script will provide detailed information about what went wrong and how to fix it.
|
||||
|
||||
## Development
|
||||
|
||||
To run the application in development mode:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
This will start the application with hot reloading enabled.
|
||||
|
||||
### Development Tools
|
||||
|
||||
When `ENABLE_DEV_TOOLS` is set to `true`, the application provides additional endpoints for debugging:
|
||||
|
||||
- `/dev/api-reference`: API reference documentation
|
||||
- `/dev/config`: Current configuration (with sensitive information redacted)
|
||||
- `/dev/state`: Current application state
|
||||
- `/dev/refresh/:nodeId`: Manually refresh data for a node
|
||||
If your ProxMox API token ID contains special characters (like `!`, `?`, `&`, etc.), make sure your `.env` file has the correct format. The application handles this internally, but it's important for the configuration to be correct.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Issues
|
||||
|
||||
If you're having trouble connecting to your ProxMox nodes, check the following:
|
||||
|
||||
1. **Network Connectivity**: Make sure you can reach the ProxMox host from the machine running the application.
|
||||
```bash
|
||||
ping your-proxmox-host
|
||||
```
|
||||
|
||||
2. **API Access**: Verify that the ProxMox API is accessible on the specified port.
|
||||
```bash
|
||||
curl -k https://your-proxmox-host:8006/api2/json/version
|
||||
```
|
||||
|
||||
3. **API Token**: Ensure that your API token has the correct permissions and is properly formatted.
|
||||
- If your token ID contains special characters, make sure to properly escape or quote it.
|
||||
- Run the connection test script to check for issues with your token:
|
||||
```bash
|
||||
npm run test:connection
|
||||
```
|
||||
|
||||
4. **SSL Certificates**: If you're using self-signed certificates, make sure `IGNORE_SSL_ERRORS` is set to `true`.
|
||||
|
||||
### Common Errors
|
||||
|
||||
- **Timeout**: The connection to the ProxMox API is timing out. Check your network configuration and firewall settings.
|
||||
- **401 Unauthorized**: The API token is invalid or doesn't have the necessary permissions.
|
||||
- **SSL Certificate Error**: The SSL certificate is not trusted. Set `IGNORE_SSL_ERRORS` to `true` or install a valid certificate.
|
||||
1. **Network Connectivity**: Make sure you can reach the ProxMox host from your machine
|
||||
2. **API Access**: Verify that the ProxMox API is accessible on the specified port
|
||||
3. **API Token**: Ensure that your API token has the correct permissions and is properly formatted
|
||||
4. **SSL Certificates**: If you're using self-signed certificates, make sure `IGNORE_SSL_ERRORS` is set to `true`
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
|
||||
> pulse_basic@1.0.0 test:connection
|
||||
> ts-node src/scripts/test-connection.ts
|
||||
|
||||
2025-02-27 14:52:10 [32minfo[39m [TestConnection]: Running comprehensive connection tests...
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [32minfo[39m [StartupCheck]: Running startup checks...
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [32minfo[39m [StartupCheck]: Validating configuration...
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [32minfo[39m [ConfigValidator]: Validating application configuration...
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [32minfo[39m [ConfigValidator]: Validating node configuration: Proxmox Node 1 (node-1)
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [33mwarn[39m [ConfigValidator]: Node node-1: Token ID contains special characters that may cause issues with shell commands: !
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [33mwarn[39m [ConfigValidator]: When using in curl or similar commands, make sure to properly escape or quote the token ID.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [32minfo[39m [ConfigValidator]: Node node-1: Successfully connected to ProxMox API version 8.3.4
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [32minfo[39m [ConfigValidator]: Validating node configuration: Proxmox Node 2 (node-2)
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [33mwarn[39m [ConfigValidator]: Node node-2: Token ID contains special characters that may cause issues with shell commands: !
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [33mwarn[39m [ConfigValidator]: When using in curl or similar commands, make sure to properly escape or quote the token ID.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [32minfo[39m [ConfigValidator]: Node node-2: Successfully connected to ProxMox API version 8.3.4
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [32minfo[39m [StartupCheck]: ✅ Configuration validation passed.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [32minfo[39m [StartupCheck]: Testing connections to all ProxMox nodes...
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [33mwarn[39m [ProxmoxClient][node-1]: SSL certificate validation is disabled. This is not recommended for production.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [33mwarn[39m [ProxmoxClient][node-2]: SSL certificate validation is disabled. This is not recommended for production.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [34mdebug[39m [ProxmoxClient][node-1]: API Request: GET /version
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:10 [34mdebug[39m [ProxmoxClient][node-2]: API Request: GET /version
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:11 [34mdebug[39m [ProxmoxClient][node-2]: API Response: 200 GET /version
|
||||
{
|
||||
"service": "proxmox-monitor",
|
||||
"data": {
|
||||
"data": {
|
||||
"release": "8.3",
|
||||
"repoid": "65224a0f9cd294a3",
|
||||
"version": "8.3.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
2025-02-27 14:52:11 [32minfo[39m [ProxmoxClient][node-2]: Connected to ProxMox API version 8.3.4
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:11 [34mdebug[39m [ProxmoxClient][node-1]: API Response: 200 GET /version
|
||||
{
|
||||
"service": "proxmox-monitor",
|
||||
"data": {
|
||||
"data": {
|
||||
"version": "8.3.4",
|
||||
"repoid": "65224a0f9cd294a3",
|
||||
"release": "8.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
2025-02-27 14:52:11 [32minfo[39m [ProxmoxClient][node-1]: Connected to ProxMox API version 8.3.4
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:11 [32minfo[39m [StartupCheck]: ✅ Successfully connected to all 2 ProxMox nodes.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:52:11 [32minfo[39m [TestConnection]: ✅ All checks passed successfully!
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
Generated
+338
-25
@@ -13,8 +13,6 @@
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^6.4.6",
|
||||
"@mui/material": "^6.4.6",
|
||||
"@types/react": "^19.0.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"axios": "^1.8.1",
|
||||
"react": "^19.0.0",
|
||||
@@ -22,8 +20,11 @@
|
||||
"react-router-dom": "^7.2.0",
|
||||
"recharts": "^2.15.1",
|
||||
"socket.io-client": "^4.8.1",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^6.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^9.1.2",
|
||||
"kill-port": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
@@ -1531,19 +1532,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz",
|
||||
"integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-dom": {
|
||||
"version": "19.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz",
|
||||
"integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-transition-group": {
|
||||
"version": "4.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
|
||||
@@ -1572,6 +1565,32 @@
|
||||
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
@@ -1678,6 +1697,51 @@
|
||||
],
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk/node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
@@ -1687,6 +1751,26 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
@@ -1699,6 +1783,32 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/concurrently": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.2.tgz",
|
||||
"integrity": "sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.2",
|
||||
"lodash": "^4.17.21",
|
||||
"rxjs": "^7.8.1",
|
||||
"shell-quote": "^1.8.1",
|
||||
"supports-color": "^8.1.1",
|
||||
"tree-kill": "^1.2.2",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
"conc": "dist/bin/concurrently.js",
|
||||
"concurrently": "dist/bin/concurrently.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
|
||||
@@ -1928,6 +2038,13 @@
|
||||
"integrity": "sha512-dJr1o6yCntRkXElnhsHh1bAV19bo/hKyFf7tCcWgpXbuFIF0Lakjgqv5LRfSDaNzAII8Fnxg2tqgHkgCvxdbxw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
"version": "6.6.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz",
|
||||
@@ -2170,6 +2287,16 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
@@ -2207,6 +2334,13 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/get-them-args": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/get-them-args/-/get-them-args-1.3.2.tgz",
|
||||
"integrity": "sha512-LRn8Jlk+DwZE4GTlDbT3Hikd1wSHgLMme/+7ddlqKd7ldwR6LjJgTVWzBnR01wnYGe4KgrXjg287RaI22UHmAw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "11.12.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
||||
@@ -2228,6 +2362,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
@@ -2328,6 +2472,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -2364,6 +2518,20 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/kill-port": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/kill-port/-/kill-port-2.0.1.tgz",
|
||||
"integrity": "sha512-e0SVOV5jFo0mx8r7bS29maVWp17qGqLBZ5ricNSajON6//kmb7qqqNnml4twNE8Dtj97UQD+gNFOaipS/q1zzQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-them-args": "1.3.2",
|
||||
"shell-exec": "1.0.2"
|
||||
},
|
||||
"bin": {
|
||||
"kill-port": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
@@ -2719,6 +2887,16 @@
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.10",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||
@@ -2786,6 +2964,16 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz",
|
||||
@@ -2807,6 +2995,26 @@
|
||||
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/shell-exec": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/shell-exec/-/shell-exec-1.0.2.tgz",
|
||||
"integrity": "sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/shell-quote": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz",
|
||||
"integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-client": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
|
||||
@@ -2887,12 +3095,56 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/stylis": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
|
||||
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
@@ -2911,25 +3163,29 @@
|
||||
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tree-kill": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
|
||||
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"tree-kill": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/turbo-stream": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
|
||||
"integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.7.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
|
||||
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
|
||||
@@ -3053,6 +3309,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
@@ -3082,6 +3356,16 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
@@ -3101,6 +3385,35 @@
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,5 +25,9 @@
|
||||
"recharts": "^2.15.1",
|
||||
"socket.io-client": "^4.8.1",
|
||||
"vite": "^6.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^9.1.2",
|
||||
"kill-port": "^2.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
+167
-20
@@ -3,21 +3,117 @@ import { ThemeProvider, createTheme } from '@mui/material/styles';
|
||||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
import { Container, Box, Typography, AppBar, Toolbar, Paper } from '@mui/material';
|
||||
import NetworkDisplay from './components/NetworkDisplay';
|
||||
// Import connection test utility
|
||||
import './utils/testConnection';
|
||||
|
||||
// Create a theme instance
|
||||
// Create a theme instance with improved colors and styling
|
||||
const theme = createTheme({
|
||||
palette: {
|
||||
mode: 'light',
|
||||
primary: {
|
||||
main: '#1976d2',
|
||||
main: '#3a7bd5',
|
||||
light: '#5e9cf5',
|
||||
dark: '#2c5ea3',
|
||||
contrastText: '#ffffff',
|
||||
},
|
||||
secondary: {
|
||||
main: '#dc004e',
|
||||
main: '#00b8d4',
|
||||
light: '#62ebff',
|
||||
dark: '#0088a3',
|
||||
contrastText: '#ffffff',
|
||||
},
|
||||
background: {
|
||||
default: '#f5f5f5',
|
||||
default: '#f8f9fa',
|
||||
paper: '#ffffff',
|
||||
},
|
||||
success: {
|
||||
main: '#4caf50',
|
||||
light: '#80e27e',
|
||||
dark: '#087f23',
|
||||
},
|
||||
warning: {
|
||||
main: '#ff9800',
|
||||
light: '#ffc947',
|
||||
dark: '#c66900',
|
||||
},
|
||||
error: {
|
||||
main: '#f44336',
|
||||
light: '#ff7961',
|
||||
dark: '#ba000d',
|
||||
},
|
||||
info: {
|
||||
main: '#2196f3',
|
||||
light: '#64b5f6',
|
||||
dark: '#0069c0',
|
||||
},
|
||||
grey: {
|
||||
50: '#fafafa',
|
||||
100: '#f5f5f5',
|
||||
200: '#eeeeee',
|
||||
300: '#e0e0e0',
|
||||
400: '#bdbdbd',
|
||||
500: '#9e9e9e',
|
||||
600: '#757575',
|
||||
700: '#616161',
|
||||
800: '#424242',
|
||||
900: '#212121',
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
|
||||
h6: {
|
||||
fontWeight: 500,
|
||||
letterSpacing: '0.0075em',
|
||||
},
|
||||
body1: {
|
||||
fontSize: '0.9rem',
|
||||
},
|
||||
body2: {
|
||||
fontSize: '0.8rem',
|
||||
},
|
||||
},
|
||||
shape: {
|
||||
borderRadius: 8,
|
||||
},
|
||||
components: {
|
||||
MuiAppBar: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
boxShadow: '0 2px 10px rgba(0, 0, 0, 0.05)',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiPaper: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
boxShadow: '0 2px 10px rgba(0, 0, 0, 0.05)',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableCell: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: '12px 16px',
|
||||
},
|
||||
head: {
|
||||
fontWeight: 600,
|
||||
color: '#424242',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableRow: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&:last-child td, &:last-child th': {
|
||||
border: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiChip: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -26,30 +122,81 @@ function App() {
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', minHeight: '100vh' }}>
|
||||
<AppBar position="static">
|
||||
<Toolbar>
|
||||
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
minHeight: '100vh',
|
||||
background: 'linear-gradient(to bottom, #f8f9fa, #e8eaf6)',
|
||||
}}>
|
||||
<AppBar position="static" color="primary" elevation={0}>
|
||||
<Toolbar sx={{ px: { xs: 2, sm: 3 } }}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
component="div"
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontWeight: 600,
|
||||
letterSpacing: '0.02em',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
component="span"
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
mr: 1.5,
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: '50%',
|
||||
bgcolor: 'rgba(255, 255, 255, 0.2)',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
component="span"
|
||||
sx={{
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: '50%',
|
||||
bgcolor: 'white',
|
||||
boxShadow: '0 0 0 2px rgba(255, 255, 255, 0.5)',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
System Monitor
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
|
||||
<Container maxWidth="lg" sx={{ mt: 4, mb: 4, flexGrow: 1 }}>
|
||||
<Box sx={{ my: 4 }}>
|
||||
<Typography variant="h4" component="h1" gutterBottom>
|
||||
Live System Metrics
|
||||
</Typography>
|
||||
<Typography variant="subtitle1" color="text.secondary" paragraph>
|
||||
Real-time monitoring of system resources and network activity
|
||||
</Typography>
|
||||
|
||||
<Container
|
||||
maxWidth="lg"
|
||||
sx={{
|
||||
mt: { xs: 2, sm: 4 },
|
||||
mb: { xs: 2, sm: 4 },
|
||||
flexGrow: 1,
|
||||
px: { xs: 2, sm: 3 },
|
||||
}}
|
||||
>
|
||||
<Box sx={{ my: { xs: 2, sm: 4 } }}>
|
||||
{/* Network Display Component */}
|
||||
<NetworkDisplay />
|
||||
</Box>
|
||||
</Container>
|
||||
|
||||
<Paper sx={{ padding: 2, marginTop: 'auto' }} component="footer">
|
||||
<Paper
|
||||
sx={{
|
||||
padding: 2,
|
||||
marginTop: 'auto',
|
||||
borderRadius: 0,
|
||||
bgcolor: 'background.paper',
|
||||
borderTop: '1px solid',
|
||||
borderColor: 'grey.200',
|
||||
}}
|
||||
component="footer"
|
||||
elevation={0}
|
||||
>
|
||||
<Typography variant="body2" color="text.secondary" align="center">
|
||||
System Monitor © {new Date().getFullYear()}
|
||||
</Typography>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,37 +0,0 @@
|
||||
import { io } from 'socket.io-client';
|
||||
|
||||
// This function can be called from the browser console to help debug WebSocket connections
|
||||
const testWebSocketConnection = (url = 'http://localhost:3000') => {
|
||||
console.log(`Testing connection to: ${url}`);
|
||||
|
||||
const socket = io(url, {
|
||||
transports: ['websocket', 'polling'],
|
||||
reconnectionAttempts: 5,
|
||||
reconnectionDelay: 500,
|
||||
timeout: 3000
|
||||
});
|
||||
|
||||
socket.on('connect', () => {
|
||||
console.log('✅ CONNECTED SUCCESSFULLY!');
|
||||
console.log('Socket ID:', socket.id);
|
||||
});
|
||||
|
||||
socket.on('connect_error', (err) => {
|
||||
console.error('❌ CONNECTION ERROR:', err);
|
||||
console.error('Message:', err.message);
|
||||
});
|
||||
|
||||
socket.on('message', (msg) => {
|
||||
console.log('📩 RECEIVED MESSAGE:', msg);
|
||||
});
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
console.log('❌ DISCONNECTED');
|
||||
});
|
||||
|
||||
return socket;
|
||||
};
|
||||
|
||||
window.testConnection = testWebSocketConnection;
|
||||
|
||||
export default testWebSocketConnection;
|
||||
@@ -5,19 +5,20 @@ import react from '@vitejs/plugin-react';
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
host: '192.168.0.130',
|
||||
port: 5173,
|
||||
proxy: {
|
||||
// Proxy WebSocket connections to the backend
|
||||
// Proxy WebSocket connections to the real backend
|
||||
'/socket.io': {
|
||||
target: 'http://localhost:3000',
|
||||
ws: true,
|
||||
},
|
||||
// Proxy API requests to the backend
|
||||
// Proxy API requests to the real backend
|
||||
'/api': {
|
||||
target: 'http://localhost:3000',
|
||||
changeOrigin: true,
|
||||
}
|
||||
},
|
||||
host: true
|
||||
},
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
|
||||
Generated
+323
@@ -24,6 +24,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.17",
|
||||
"concurrently": "^9.1.2",
|
||||
"nodemon": "^3.1.9",
|
||||
"ts-node-dev": "^2.0.0"
|
||||
}
|
||||
@@ -287,6 +288,52 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles/node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
@@ -458,6 +505,46 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk/node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk/node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
@@ -483,6 +570,21 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/color": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
||||
@@ -547,6 +649,58 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concurrently": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.2.tgz",
|
||||
"integrity": "sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.2",
|
||||
"lodash": "^4.17.21",
|
||||
"rxjs": "^7.8.1",
|
||||
"shell-quote": "^1.8.1",
|
||||
"supports-color": "^8.1.1",
|
||||
"tree-kill": "^1.2.2",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
"conc": "dist/bin/concurrently.js",
|
||||
"concurrently": "dist/bin/concurrently.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/concurrently/node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/concurrently/node_modules/supports-color": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
@@ -690,6 +844,13 @@
|
||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/enabled": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
|
||||
@@ -811,6 +972,16 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
@@ -999,6 +1170,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
@@ -1239,6 +1420,16 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
@@ -1280,6 +1471,13 @@
|
||||
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/logform": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz",
|
||||
@@ -1702,6 +1900,16 @@
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.10",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||
@@ -1737,6 +1945,16 @@
|
||||
"rimraf": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@@ -1845,6 +2063,19 @@
|
||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/shell-quote": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz",
|
||||
"integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||
@@ -2097,6 +2328,34 @@
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-bom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
||||
@@ -2297,6 +2556,13 @@
|
||||
"strip-json-comments": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
@@ -2427,6 +2693,24 @@
|
||||
"node": ">= 12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
@@ -2465,6 +2749,45 @@
|
||||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yn": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||
|
||||
+7
-1
@@ -9,7 +9,12 @@
|
||||
"lint": "eslint . --ext .ts",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"test:startup": "ts-node src/scripts/startup-check.ts",
|
||||
"test:api": "ts-node src/scripts/proxmox-api-test.ts"
|
||||
"test:api": "ts-node src/scripts/proxmox-api-test.ts",
|
||||
"kill:backend": "npx kill-port 3000",
|
||||
"kill:frontend": "npx kill-port 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200",
|
||||
"kill:all": "npm run kill:backend && npm run kill:frontend",
|
||||
"dev:frontend": "cd frontend && npm run dev",
|
||||
"pulse": "./start-pulse.sh"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
@@ -31,6 +36,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.17",
|
||||
"concurrently": "^9.1.2",
|
||||
"nodemon": "^3.1.9",
|
||||
"ts-node-dev": "^2.0.0"
|
||||
}
|
||||
|
||||
@@ -1,285 +0,0 @@
|
||||
# ProxMox Monitoring App Implementation Plan
|
||||
|
||||
## Project Overview
|
||||
|
||||
A lightweight, responsive ProxMox monitoring application that displays real-time metrics for CPU, memory, network, and disk usage across multiple nodes. The application will use the ProxMox API and event subscription for real-time updates.
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
The application will use environment variables for configuration with the following structure:
|
||||
|
||||
```
|
||||
# Node 1
|
||||
PROXMOX_NODE_1_NAME=Proxmox Node 1
|
||||
PROXMOX_NODE_1_HOST=https://192.168.0.132:8006
|
||||
PROXMOX_NODE_1_TOKEN_ID=root@pam!pulse
|
||||
PROXMOX_NODE_1_TOKEN_SECRET=e1850350-6afc-4b8e-ae28-472152af84f9
|
||||
|
||||
# Node 2
|
||||
PROXMOX_NODE_2_NAME=Proxmox Node 2
|
||||
PROXMOX_NODE_2_HOST=https://192.168.0.141:8006
|
||||
PROXMOX_NODE_2_TOKEN_ID=root@pam!pulse
|
||||
PROXMOX_NODE_2_TOKEN_SECRET=63e21f63-4cfd-4ba0-9b14-fc681c59d932
|
||||
|
||||
# App Configuration
|
||||
PORT=3000
|
||||
NODE_ENV=development
|
||||
LOG_LEVEL=debug
|
||||
ENABLE_DEV_TOOLS=true
|
||||
METRICS_HISTORY_MINUTES=60
|
||||
```
|
||||
|
||||
## Technology Stack
|
||||
|
||||
- **Backend**: Node.js with Express, TypeScript, Socket.io for real-time updates
|
||||
- **Frontend**: Simple HTML/CSS/TypeScript with grid layout
|
||||
- **Deployment**: Docker container
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
proxmox-monitor/
|
||||
├── src/
|
||||
│ ├── config/
|
||||
│ ├── types/
|
||||
│ ├── api/
|
||||
│ ├── services/
|
||||
│ ├── utils/
|
||||
│ ├── routes/
|
||||
│ ├── websocket/
|
||||
│ ├── public/
|
||||
│ └── server.ts
|
||||
├── .env
|
||||
├── .env.example
|
||||
├── .gitignore
|
||||
├── tsconfig.json
|
||||
├── package.json
|
||||
├── Dockerfile
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## Core Components
|
||||
|
||||
### 1. Configuration Module
|
||||
|
||||
- **Purpose**: Load and validate environment variables
|
||||
- **Features**:
|
||||
- Parse environment variables for multiple ProxMox nodes
|
||||
- Support dynamic number of nodes (PROXMOX_NODE_1, PROXMOX_NODE_2, etc.)
|
||||
- Validate configuration during startup
|
||||
- Keep credentials secure
|
||||
|
||||
### 2. ProxMox API Client
|
||||
|
||||
- **Purpose**: Interface with ProxMox API
|
||||
- **Features**:
|
||||
- Authentication with API tokens
|
||||
- Fetch node status information
|
||||
- Get virtual machines and containers
|
||||
- Get detailed metrics
|
||||
- Handle API errors with proper logging
|
||||
- Support HTTPS with option to ignore certificate validation for lab environments
|
||||
|
||||
### 3. Event Subscription Service
|
||||
|
||||
- **Purpose**: Receive real-time updates from ProxMox
|
||||
- **Features**:
|
||||
- Connect to ProxMox event stream
|
||||
- Process event data
|
||||
- Emit events to internal event system
|
||||
- Handle connection errors and auto-reconnect
|
||||
- Correlate events with specific nodes
|
||||
|
||||
### 4. Node Management Service
|
||||
|
||||
- **Purpose**: Manage multiple ProxMox nodes
|
||||
- **Features**:
|
||||
- Create and maintain API clients for each node
|
||||
- Manage event subscriptions
|
||||
- Aggregate data from multiple nodes
|
||||
- Track node connectivity status
|
||||
- Support dynamic node addition/removal
|
||||
|
||||
### 5. Metrics Collection Service
|
||||
|
||||
- **Purpose**: Collect and process metrics
|
||||
- **Features**:
|
||||
- Combine event-based and polling data
|
||||
- Normalize metrics across different sources
|
||||
- Calculate derived metrics (percentages, rates)
|
||||
- Store short-term history (configurable, default 60 minutes)
|
||||
- Support for different metric types (CPU, memory, network, disk)
|
||||
|
||||
### 6. WebSocket Server
|
||||
|
||||
- **Purpose**: Real-time communication with frontend
|
||||
- **Features**:
|
||||
- Push metrics updates to clients
|
||||
- Handle client connections/disconnections
|
||||
- Support filtering data sent to clients
|
||||
- Optimize data transfer (send only changed data)
|
||||
|
||||
### 7. REST API
|
||||
|
||||
- **Purpose**: Provide data to frontend
|
||||
- **Endpoints**:
|
||||
- `/api/nodes` - List all nodes
|
||||
- `/api/nodes/:nodeId` - Get node details
|
||||
- `/api/nodes/:nodeId/vms` - Get all VMs for a node
|
||||
- `/api/nodes/:nodeId/containers` - Get all containers for a node
|
||||
- `/api/status` - Get system status
|
||||
- `/api/metrics` - Get current metrics
|
||||
- `/api/metrics/history` - Get historical metrics
|
||||
|
||||
### 8. Development Tools
|
||||
|
||||
- **Purpose**: Assist in development with AI
|
||||
- **Features**:
|
||||
- Enhanced logging with context
|
||||
- API call visualization
|
||||
- State inspection
|
||||
- Error handling with suggestions
|
||||
- Development dashboard
|
||||
- API response recording/playback
|
||||
|
||||
### 9. Frontend Components
|
||||
|
||||
- **Purpose**: Display monitoring data
|
||||
- **Features**:
|
||||
- Grid layout for VMs/containers
|
||||
- Real-time metric updates
|
||||
- Node selector
|
||||
- Responsive design
|
||||
- Minimal but functional UI
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Project Setup
|
||||
|
||||
- Initialize TypeScript project
|
||||
- Configure environment
|
||||
- Set up basic project structure
|
||||
- Install core dependencies
|
||||
|
||||
### Phase 2: Core API Implementation
|
||||
|
||||
- Implement ProxMox API client
|
||||
- Create type definitions for API responses
|
||||
- Build node configuration loader
|
||||
- Implement enhanced logging system
|
||||
|
||||
### Phase 3: Event System
|
||||
|
||||
- Create event subscription service
|
||||
- Implement event processing
|
||||
- Set up WebSocket server
|
||||
- Build real-time data pipeline
|
||||
|
||||
### Phase 4: Metrics Collection
|
||||
|
||||
- Implement metrics normalization
|
||||
- Create polling fallback for missing metrics
|
||||
- Build short-term history storage
|
||||
- Implement derived metrics calculation
|
||||
|
||||
### Phase 5: Node Management
|
||||
|
||||
- Create multi-node support
|
||||
- Implement node discovery (if in cluster)
|
||||
- Build node status tracking
|
||||
- Create aggregated metrics view
|
||||
|
||||
### Phase 6: Frontend Development
|
||||
|
||||
- Create simple grid layout
|
||||
- Implement WebSocket client
|
||||
- Build real-time updates
|
||||
- Create node selector
|
||||
|
||||
### Phase 7: Development Tools
|
||||
|
||||
- Implement enhanced logging
|
||||
- Create development dashboard
|
||||
- Add API explorer
|
||||
- Build state visualization
|
||||
|
||||
### Phase 8: Containerization
|
||||
|
||||
- Create Docker configuration
|
||||
- Set up environment variable passing
|
||||
- Test container deployment
|
||||
|
||||
## API Type Definitions
|
||||
|
||||
The application should define TypeScript interfaces for:
|
||||
|
||||
1. **ProxmoxNodeStatus** - Node status information
|
||||
2. **ProxmoxVM** - Virtual machine information
|
||||
3. **ProxmoxContainer** - Container information
|
||||
4. **ProxmoxGuest** - Union type of VM and Container
|
||||
5. **ProxmoxEvent** - Event data structure
|
||||
6. **MetricsData** - Normalized metrics format
|
||||
7. **NodeConfig** - Node configuration structure
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. Keep API tokens in environment variables
|
||||
2. Don't commit .env files with credentials
|
||||
3. Use HTTPS for API communication
|
||||
4. Consider read-only API tokens with minimal permissions
|
||||
5. Validate all user inputs
|
||||
|
||||
## Development Context Helpers
|
||||
|
||||
1. **Configuration Validator and API Reference**:
|
||||
- **Purpose**: Provide a reliable reference for ProxMox API interactions
|
||||
- **Features**:
|
||||
- Validate environment configurations during startup
|
||||
- Test connectivity to all configured nodes
|
||||
- Sample and store actual API response structures for reference
|
||||
- Document endpoint patterns with examples
|
||||
- Create schema validators for request/response bodies
|
||||
- Generate TypeScript interfaces from actual API responses
|
||||
- Expose an endpoint that shows API structure for reference
|
||||
- Store successful API call patterns for the AI to reference
|
||||
- Cache sample responses for offline development
|
||||
- Provide helper functions to validate API calls before sending
|
||||
- Create a "cheat sheet" of common API patterns
|
||||
- **Implementation**:
|
||||
- Create a startup validation process that tests all endpoints
|
||||
- Build an in-memory reference database of API interactions
|
||||
- Expose `/dev/api-reference` endpoint with interactive documentation
|
||||
- Log all successful API interactions for pattern recognition
|
||||
- Create a validation library the AI can use to check its work
|
||||
|
||||
2. **Enhanced Logging**:
|
||||
- Include node ID, component, operation in logs
|
||||
- Different log levels (debug, info, warn, error)
|
||||
- Contextual error information
|
||||
- Log reference to successful patterns when errors occur
|
||||
|
||||
3. **State Inspection**:
|
||||
- Endpoint to view current system state
|
||||
- Connection status visualization
|
||||
- Event subscription status
|
||||
- Configuration status and validation results
|
||||
|
||||
4. **API Explorer**:
|
||||
- Test API calls directly
|
||||
- View recent API calls and responses
|
||||
- Response visualization
|
||||
- Template library of working API calls
|
||||
- Side-by-side comparison of expected vs. actual responses
|
||||
|
||||
5. **Performance Monitoring**:
|
||||
- Track memory and CPU usage
|
||||
- Monitor event processing time
|
||||
- Connection statistics
|
||||
|
||||
## Docker Configuration
|
||||
|
||||
- Use Node.js Alpine image as base
|
||||
- Multi-stage build for smaller image
|
||||
- Expose configuration via environment variables
|
||||
- Volume mounting for persistent data (if needed)
|
||||
- Health check endpoint
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Kill any existing test servers
|
||||
pkill -f "node test-server.js" || true
|
||||
|
||||
# Start the test server
|
||||
echo "Starting test server..."
|
||||
node test-server.js &
|
||||
TEST_SERVER_PID=$!
|
||||
|
||||
# Wait a moment for the server to start
|
||||
sleep 2
|
||||
|
||||
# Start the frontend
|
||||
echo "Starting frontend..."
|
||||
cd frontend && npm run dev
|
||||
|
||||
# When the frontend exits, also kill the test server
|
||||
kill $TEST_SERVER_PID
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Make script executable if it isn't already
|
||||
chmod +x "$0"
|
||||
|
||||
# Kill any existing servers
|
||||
echo "Killing any existing servers..."
|
||||
pkill -f "node dist/server.js" || true
|
||||
npx kill-port 5173 3000
|
||||
|
||||
# Start the real backend server
|
||||
echo "Starting real backend server..."
|
||||
NODE_ENV=development LOG_LEVEL=info ENABLE_DEV_TOOLS=true npm run dev &
|
||||
BACKEND_PID=$!
|
||||
|
||||
# Wait a moment for the server to start
|
||||
sleep 3
|
||||
|
||||
# Get the host IP (use 0.0.0.0 in Docker, otherwise use 192.168.0.130 or the local IP)
|
||||
HOST_IP="0.0.0.0"
|
||||
if [[ -z "${DOCKER_CONTAINER}" ]]; then
|
||||
# Not in Docker, use the specific IP
|
||||
HOST_IP="192.168.0.130"
|
||||
fi
|
||||
|
||||
# Start the frontend Vite dev server
|
||||
echo "Starting Pulse interface..."
|
||||
cd frontend && npm run dev -- --host "${HOST_IP}"
|
||||
|
||||
# When the frontend exits, also kill the backend server
|
||||
kill $BACKEND_PID
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
|
||||
> pulse_basic@1.0.0 test:startup
|
||||
> ts-node src/scripts/startup-check.ts
|
||||
|
||||
2025-02-27 14:51:58 [32minfo[39m [StartupCheck]: Running startup checks...
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [32minfo[39m [StartupCheck]: Validating configuration...
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [32minfo[39m [ConfigValidator]: Validating application configuration...
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [32minfo[39m [ConfigValidator]: Validating node configuration: Proxmox Node 1 (node-1)
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [33mwarn[39m [ConfigValidator]: Node node-1: Token ID contains special characters that may cause issues with shell commands: !
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [33mwarn[39m [ConfigValidator]: When using in curl or similar commands, make sure to properly escape or quote the token ID.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [32minfo[39m [ConfigValidator]: Node node-1: Successfully connected to ProxMox API version 8.3.4
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [32minfo[39m [ConfigValidator]: Validating node configuration: Proxmox Node 2 (node-2)
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [33mwarn[39m [ConfigValidator]: Node node-2: Token ID contains special characters that may cause issues with shell commands: !
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [33mwarn[39m [ConfigValidator]: When using in curl or similar commands, make sure to properly escape or quote the token ID.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [32minfo[39m [ConfigValidator]: Node node-2: Successfully connected to ProxMox API version 8.3.4
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [32minfo[39m [StartupCheck]: ✅ Configuration validation passed.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [32minfo[39m [StartupCheck]: Testing connections to all ProxMox nodes...
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [33mwarn[39m [ProxmoxClient][node-1]: SSL certificate validation is disabled. This is not recommended for production.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [33mwarn[39m [ProxmoxClient][node-2]: SSL certificate validation is disabled. This is not recommended for production.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [34mdebug[39m [ProxmoxClient][node-1]: API Request: GET /version
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [34mdebug[39m [ProxmoxClient][node-2]: API Request: GET /version
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [34mdebug[39m [ProxmoxClient][node-2]: API Response: 200 GET /version
|
||||
{
|
||||
"service": "proxmox-monitor",
|
||||
"data": {
|
||||
"data": {
|
||||
"version": "8.3.4",
|
||||
"release": "8.3",
|
||||
"repoid": "65224a0f9cd294a3"
|
||||
}
|
||||
}
|
||||
}
|
||||
2025-02-27 14:51:58 [32minfo[39m [ProxmoxClient][node-2]: Connected to ProxMox API version 8.3.4
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [34mdebug[39m [ProxmoxClient][node-1]: API Response: 200 GET /version
|
||||
{
|
||||
"service": "proxmox-monitor",
|
||||
"data": {
|
||||
"data": {
|
||||
"repoid": "65224a0f9cd294a3",
|
||||
"release": "8.3",
|
||||
"version": "8.3.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
2025-02-27 14:51:58 [32minfo[39m [ProxmoxClient][node-1]: Connected to ProxMox API version 8.3.4
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [32minfo[39m [StartupCheck]: ✅ Successfully connected to all 2 ProxMox nodes.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
2025-02-27 14:51:58 [32minfo[39m [StartupCheck]: ✅ All startup checks passed.
|
||||
{
|
||||
"service": "proxmox-monitor"
|
||||
}
|
||||
-186
@@ -1,186 +0,0 @@
|
||||
const express = require('express');
|
||||
const http = require('http');
|
||||
const { Server } = require('socket.io');
|
||||
|
||||
const app = express();
|
||||
const server = http.createServer(app);
|
||||
const io = new Server(server, {
|
||||
cors: {
|
||||
origin: '*',
|
||||
methods: ['GET', 'POST']
|
||||
}
|
||||
});
|
||||
|
||||
const PORT = 3001;
|
||||
|
||||
// Create some sample nodes data
|
||||
const nodes = [
|
||||
{
|
||||
id: 'node-1',
|
||||
name: 'Primary Server',
|
||||
status: 'online',
|
||||
ip: '192.168.1.100',
|
||||
uptime: 86400 * 5 // 5 days in seconds
|
||||
},
|
||||
{
|
||||
id: 'node-2',
|
||||
name: 'Secondary Server',
|
||||
status: 'online',
|
||||
ip: '192.168.1.101',
|
||||
uptime: 86400 * 3 // 3 days in seconds
|
||||
}
|
||||
];
|
||||
|
||||
// Create some sample guests data
|
||||
const guests = [
|
||||
{
|
||||
id: 'guest-101',
|
||||
name: 'Web Server',
|
||||
status: 'running',
|
||||
type: 'lxc',
|
||||
node: 'node-1'
|
||||
},
|
||||
{
|
||||
id: 'guest-102',
|
||||
name: 'Database',
|
||||
status: 'running',
|
||||
type: 'lxc',
|
||||
node: 'node-1'
|
||||
},
|
||||
{
|
||||
id: 'guest-103',
|
||||
name: 'File Storage',
|
||||
status: 'stopped',
|
||||
type: 'qemu',
|
||||
node: 'node-2'
|
||||
}
|
||||
];
|
||||
|
||||
// Serve a simple message
|
||||
app.get('/', (req, res) => {
|
||||
res.send('Socket.IO Test Server');
|
||||
});
|
||||
|
||||
// Socket.IO connection handler
|
||||
io.on('connection', (socket) => {
|
||||
console.log('Client connected:', socket.id);
|
||||
|
||||
// Create consistent metrics for each guest to ensure stable data
|
||||
// This is more reliable than generating random values each time
|
||||
const initialMetrics = {
|
||||
'guest-101': { // Web Server
|
||||
inRate: 850000, // ~850 KB/s
|
||||
outRate: 420000 // ~420 KB/s
|
||||
},
|
||||
'guest-102': { // Database
|
||||
inRate: 650000, // ~650 KB/s
|
||||
outRate: 320000 // ~320 KB/s
|
||||
}
|
||||
};
|
||||
|
||||
// Send connection confirmation
|
||||
socket.emit('message', {
|
||||
type: 'CONNECTED',
|
||||
payload: {
|
||||
timestamp: Date.now(),
|
||||
message: 'Connected to Test Socket.IO Server'
|
||||
}
|
||||
});
|
||||
|
||||
// Send initial node data
|
||||
socket.emit('message', {
|
||||
type: 'NODE_STATUS_UPDATE',
|
||||
payload: nodes
|
||||
});
|
||||
console.log('Sent initial node data to', socket.id);
|
||||
|
||||
// Send initial guest data
|
||||
socket.emit('message', {
|
||||
type: 'GUEST_STATUS_UPDATE',
|
||||
payload: guests
|
||||
});
|
||||
console.log('Sent initial guest data to', socket.id);
|
||||
|
||||
// Send initial metrics data for running guests
|
||||
guests.forEach(guest => {
|
||||
if (guest.status === 'running') {
|
||||
// Use the consistent initial metrics for this guest
|
||||
const baseMetrics = initialMetrics[guest.id] || {
|
||||
inRate: 500000, // Default if not specified
|
||||
outRate: 250000
|
||||
};
|
||||
|
||||
// Add some randomness (±10%)
|
||||
const randomFactor = 0.9 + Math.random() * 0.2;
|
||||
|
||||
socket.emit('message', {
|
||||
type: 'METRICS_UPDATE',
|
||||
payload: {
|
||||
guestId: guest.id,
|
||||
nodeId: guest.node,
|
||||
timestamp: Date.now(),
|
||||
metrics: {
|
||||
network: {
|
||||
inRate: baseMetrics.inRate * randomFactor,
|
||||
outRate: baseMetrics.outRate * randomFactor
|
||||
},
|
||||
uptime: Math.floor(Math.random() * 86400)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`Sent initial metrics for ${guest.id} (${guest.name})`);
|
||||
}
|
||||
});
|
||||
console.log('Sent initial metrics data for running guests to', socket.id);
|
||||
|
||||
// Send test metrics data every 3 seconds
|
||||
const interval = setInterval(() => {
|
||||
// Create metrics for each guest
|
||||
guests.forEach(guest => {
|
||||
// Only send metrics for running guests
|
||||
if (guest.status === 'running') {
|
||||
// Use the consistent initial metrics with some random variation
|
||||
const baseMetrics = initialMetrics[guest.id] || {
|
||||
inRate: 500000,
|
||||
outRate: 250000
|
||||
};
|
||||
|
||||
// Add larger random variation (±30%)
|
||||
const randomFactor = 0.7 + Math.random() * 0.6;
|
||||
|
||||
const metrics = {
|
||||
type: 'METRICS_UPDATE',
|
||||
payload: {
|
||||
guestId: guest.id,
|
||||
nodeId: guest.node,
|
||||
timestamp: Date.now(),
|
||||
metrics: {
|
||||
network: {
|
||||
inRate: baseMetrics.inRate * randomFactor,
|
||||
outRate: baseMetrics.outRate * randomFactor
|
||||
},
|
||||
uptime: Math.floor(Math.random() * 86400)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
socket.emit('message', metrics);
|
||||
console.log(`Sent updated metrics for ${guest.id} (${guest.name})`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Sent metrics data to', socket.id);
|
||||
}, 3000);
|
||||
|
||||
// Clean up on disconnect
|
||||
socket.on('disconnect', () => {
|
||||
console.log('Client disconnected:', socket.id);
|
||||
clearInterval(interval);
|
||||
});
|
||||
});
|
||||
|
||||
// Start the server
|
||||
server.listen(PORT, () => {
|
||||
console.log(`Test server running on http://localhost:${PORT}`);
|
||||
});
|
||||
Reference in New Issue
Block a user