Remove study count showing on Activity column. Collapse Navigation bar by default. Show Active and Idle for router activity. Fixed card view count. Fixed card view router row info as per correct status. Show only one recent study on Activity column. Show router details on click of router id to expanded row.
This commit is contained in:
parent
8630a3e2c5
commit
dfa974fe6b
25
db-scripts/00-init-db.sh
Normal file
25
db-scripts/00-init-db.sh
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Wait for MySQL to become available
|
||||||
|
echo "Waiting for MySQL to become healthy..."
|
||||||
|
until mysql -h "localhost" -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SHOW DATABASES;" &>/dev/null; do
|
||||||
|
echo "Waiting for MySQL..."
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "MySQL is up and running!"
|
||||||
|
|
||||||
|
# Run the initial common setup (always executed)
|
||||||
|
echo "Running 01-init.sql"
|
||||||
|
mysql -u$MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE < /docker-entrypoint-initdb.d/01-init.sql
|
||||||
|
|
||||||
|
echo "Running 02-seed_common_data.sql"
|
||||||
|
mysql -u$MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE < /docker-entrypoint-initdb.d/02-seed_common_data.sql
|
||||||
|
|
||||||
|
# Check the environment variable and execute environment-specific scripts
|
||||||
|
if [ "$ENVIRONMENT" != "production" ]; then
|
||||||
|
echo "Running 03-seed_router_data_qa.sql for QA (non-production)"
|
||||||
|
mysql -u$MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE < /docker-entrypoint-initdb.d/03-seed_router_data_qa.sql
|
||||||
|
else
|
||||||
|
echo "Production environment detected. Skipping seeding data for QA (non-production)."
|
||||||
|
fi
|
||||||
@ -8,6 +8,9 @@ CREATE TABLE IF NOT EXISTS routers (
|
|||||||
router_id VARCHAR(10) UNIQUE NOT NULL, -- Unique router identifier
|
router_id VARCHAR(10) UNIQUE NOT NULL, -- Unique router identifier
|
||||||
facility VARCHAR(50) NOT NULL,
|
facility VARCHAR(50) NOT NULL,
|
||||||
router_alias VARCHAR(50) NOT NULL,
|
router_alias VARCHAR(50) NOT NULL,
|
||||||
|
facility_aet VARCHAR(50) NOT NULL,
|
||||||
|
openvpn_ip VARCHAR(15) NOT NULL,
|
||||||
|
router_vm_primary_ip VARCHAR(15) NOT NULL,
|
||||||
last_seen TIMESTAMP NOT NULL,
|
last_seen TIMESTAMP NOT NULL,
|
||||||
vpn_status_code VARCHAR(50) NOT NULL,
|
vpn_status_code VARCHAR(50) NOT NULL,
|
||||||
disk_status_code VARCHAR(50) NOT NULL,
|
disk_status_code VARCHAR(50) NOT NULL,
|
||||||
@ -76,24 +79,24 @@ CREATE TABLE IF NOT EXISTS container_status (
|
|||||||
);
|
);
|
||||||
|
|
||||||
-- DICOM study overview table with router_id as a string reference
|
-- DICOM study overview table with router_id as a string reference
|
||||||
CREATE TABLE IF NOT EXISTS dicom_study_overview (
|
CREATE TABLE IF NOT EXISTS dicom_study_overview (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
router_id VARCHAR(10) NOT NULL, -- Matching VARCHAR(10) with the routers table
|
router_id VARCHAR(10) NOT NULL, -- Matching VARCHAR(10) with the routers table
|
||||||
study_instance_uid VARCHAR(100) UNIQUE NOT NULL,
|
study_instance_uid VARCHAR(100) UNIQUE NOT NULL,
|
||||||
patient_id VARCHAR(50) NOT NULL,
|
patient_id VARCHAR(50) NOT NULL,
|
||||||
patient_name VARCHAR(100) NOT NULL,
|
patient_name VARCHAR(100) NOT NULL,
|
||||||
accession_number VARCHAR(50) NOT NULL,
|
accession_number VARCHAR(50) NOT NULL,
|
||||||
study_date DATE NOT NULL,
|
study_date DATE NOT NULL,
|
||||||
modality VARCHAR(20) NOT NULL,
|
modality VARCHAR(20) NOT NULL,
|
||||||
study_description VARCHAR(255),
|
study_description VARCHAR(255),
|
||||||
series_instance_uid VARCHAR(100) NOT NULL,
|
series_instance_uid VARCHAR(100) NOT NULL,
|
||||||
procedure_code VARCHAR(50),
|
procedure_code VARCHAR(50),
|
||||||
referring_physician_name VARCHAR(100),
|
referring_physician_name VARCHAR(100),
|
||||||
study_status_code VARCHAR(50) NOT NULL DEFAULT 'NEW', -- Default value, ensure 'NEW' exists in status_type
|
study_status_code VARCHAR(50) NOT NULL DEFAULT 'NEW', -- Default value, ensure 'NEW' exists in status_type
|
||||||
association_id VARCHAR(50) NOT NULL DEFAULT 'NEW',
|
association_id VARCHAR(50) NOT NULL DEFAULT 'NEW',
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Create tables if they don't exist
|
-- Create tables if they don't exist
|
||||||
CREATE TABLE IF NOT EXISTS status_type (
|
CREATE TABLE IF NOT EXISTS status_type (
|
||||||
34
db-scripts/02-seed_common_data.sql
Normal file
34
db-scripts/02-seed_common_data.sql
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
-- Check if the procedure exists, and create it only if it does not
|
||||||
|
DROP PROCEDURE IF EXISTS `seed_common_router_data`;
|
||||||
|
|
||||||
|
DELIMITER //
|
||||||
|
|
||||||
|
CREATE PROCEDURE seed_common_router_data()
|
||||||
|
BEGIN
|
||||||
|
-- Insert Status Categories
|
||||||
|
INSERT INTO status_category (name, description)
|
||||||
|
VALUES
|
||||||
|
('Network', 'Network related statuses'),
|
||||||
|
('Disk', 'Disk related statuses'),
|
||||||
|
('VPN', 'VPN connection statuses'),
|
||||||
|
('License', 'License statuses'),
|
||||||
|
('Container', 'Container related statuses')
|
||||||
|
ON DUPLICATE KEY UPDATE id = id;
|
||||||
|
|
||||||
|
-- Insert Status Types
|
||||||
|
INSERT INTO status_type (category_id, name, code, description, severity)
|
||||||
|
VALUES
|
||||||
|
(1, 'Online', 'NET_ONLINE', 'System is online', 1),
|
||||||
|
(1, 'Offline', 'NET_OFFLINE', 'System is offline', 5),
|
||||||
|
(2, 'Normal', 'DISK_NORMAL', 'Disk usage is normal', 1),
|
||||||
|
(2, 'Warning', 'DISK_WARNING', 'Disk usage is high', 3),
|
||||||
|
(2, 'Critical', 'DISK_CRITICAL', 'Disk usage is critical', 5),
|
||||||
|
(3, 'Connected', 'VPN_CONNECTED', 'VPN is connected', 1),
|
||||||
|
(3, 'Disconnected', 'VPN_DISCONNECTED', 'VPN is disconnected', 5),
|
||||||
|
(5, 'Running', 'CONTAINER_RUNNING', 'Container is running', 1),
|
||||||
|
(5, 'Stopped', 'CONTAINER_STOPPED', 'Container is stopped', 5)
|
||||||
|
ON DUPLICATE KEY UPDATE id = id;
|
||||||
|
|
||||||
|
END //
|
||||||
|
|
||||||
|
DELIMITER ;
|
||||||
49
db-scripts/03-seed_router_data_qa.sql
Normal file
49
db-scripts/03-seed_router_data_qa.sql
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
-- Check if the procedure exists, and create it only if it does not
|
||||||
|
DROP PROCEDURE IF EXISTS `seed_router_data`;
|
||||||
|
|
||||||
|
DELIMITER //
|
||||||
|
|
||||||
|
CREATE PROCEDURE seed_router_data()
|
||||||
|
BEGIN
|
||||||
|
-- Insert Routers
|
||||||
|
INSERT INTO routers (router_id, facility, router_alias, facility_aet, openvpn_ip, router_vm_primary_ip,
|
||||||
|
last_seen, vpn_status_code, disk_status_code, app_status_code, license_status, free_disk, total_disk, disk_usage)
|
||||||
|
VALUES
|
||||||
|
('RTR001', 'Main Hospital', 'MAIN_RAD', 'RTR_1', '10.8.0.101', '192.168.1.101', NOW(), 'VPN_CONNECTED', 'DISK_NORMAL', 'CONTAINER_RUNNING', 'active', 500000000000, 1000000000000, 50.00),
|
||||||
|
('RTR002', 'Emergency Center', 'ER_RAD', 'RTR_2', '10.8.0.102', '192.168.1.102', NOW(), 'VPN_DISCONNECTED', 'DISK_WARNING', 'CONTAINER_RUNNING', 'active', 400000000000, 1000000000000, 60.00),
|
||||||
|
('RTR003', 'Imaging Center', 'IMG_CENTER', 'RTR_3', '10.8.0.103', '192.168.1.103', NOW(), 'VPN_CONNECTED', 'DISK_NORMAL', 'CONTAINER_RUNNING', 'active', 600000000000, 1000000000000, 40.00)
|
||||||
|
ON DUPLICATE KEY UPDATE id = id;
|
||||||
|
|
||||||
|
-- Store Router IDs
|
||||||
|
SET @router1_id = (SELECT id FROM routers WHERE router_id = 'RTR001');
|
||||||
|
SET @router2_id = (SELECT id FROM routers WHERE router_id = 'RTR002');
|
||||||
|
SET @router3_id = (SELECT id FROM routers WHERE router_id = 'RTR003');
|
||||||
|
|
||||||
|
-- Insert Container Status
|
||||||
|
INSERT INTO container_status (router_id, container_name, status_code, created_at, updated_at)
|
||||||
|
VALUES
|
||||||
|
(@router1_id, 'router-cstore-scp', 'CONTAINER_RUNNING', NOW(), NOW()),
|
||||||
|
(@router1_id, 'router-cstore-scu', 'CONTAINER_RUNNING', NOW(), NOW()),
|
||||||
|
(@router2_id, 'router-cstore-scp', 'CONTAINER_RUNNING', NOW(), NOW()),
|
||||||
|
(@router2_id, 'router-cstore-scu', 'CONTAINER_RUNNING', NOW(), NOW()),
|
||||||
|
(@router3_id, 'router-cstore-scp', 'CONTAINER_RUNNING', NOW(), NOW())
|
||||||
|
ON DUPLICATE KEY UPDATE id = id;
|
||||||
|
|
||||||
|
-- Insert DICOM Study Overview
|
||||||
|
INSERT INTO dicom_study_overview (
|
||||||
|
router_id, study_instance_uid, patient_id, patient_name,
|
||||||
|
accession_number, study_date, modality, study_description,
|
||||||
|
series_instance_uid, procedure_code, referring_physician_name,
|
||||||
|
study_status_code
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(@router1_id, '1.2.840.113619.2.55.3.283116435.276.1543707218.134', 'P1', 'John Doe', 'ACC1234', '2024-03-15', 'CT', 'Chest CT', '1.2.840.113619.2.55.3.283116435.276.1543707219.135', 'CT001', 'Dr. Smith', 'idle'),
|
||||||
|
(@router2_id, '1.2.840.113619.2.55.3.283116435.276.1543707218.136', 'P2', 'Jane Doe', 'ACC1235', '2024-03-15', 'MR', 'Brain MRI', '1.2.840.113619.2.55.3.283116435.276.1543707219.137', 'MR001', 'Dr. Johnson', 'idle')
|
||||||
|
ON DUPLICATE KEY UPDATE id = id;
|
||||||
|
|
||||||
|
END //
|
||||||
|
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
-- Automatically call the procedure after creation
|
||||||
|
CALL seed_router_data();
|
||||||
142
deploy.sh
Normal file
142
deploy.sh
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Function to print colored messages
|
||||||
|
print_message() {
|
||||||
|
local color=$1
|
||||||
|
local message=$2
|
||||||
|
echo -e "${color}${message}${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if command was successful
|
||||||
|
check_status() {
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
print_message "$GREEN" "✔ Success: $1"
|
||||||
|
else
|
||||||
|
print_message "$RED" "✘ Error: $1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
ENV="production"
|
||||||
|
SERVER_IP=""
|
||||||
|
FRONTEND_IP=""
|
||||||
|
DB_HOST="mysql"
|
||||||
|
|
||||||
|
# Help message
|
||||||
|
show_help() {
|
||||||
|
echo "Usage: ./deploy.sh [OPTIONS]"
|
||||||
|
echo "Deploy the router dashboard application"
|
||||||
|
echo
|
||||||
|
echo "Options:"
|
||||||
|
echo " -s, --server-ip Server IP address (required)"
|
||||||
|
echo " -f, --frontend-ip Frontend IP address (defaults to server IP if not provided)"
|
||||||
|
echo " -d, --db-host Database host (defaults to mysql)"
|
||||||
|
echo " -e, --environment Environment (development/staging/production, defaults to production)"
|
||||||
|
echo " -h, --help Show this help message"
|
||||||
|
echo
|
||||||
|
echo "Example:"
|
||||||
|
echo " ./deploy.sh -s 192.168.1.100 -f 192.168.1.101 -e production"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse command line arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-s|--server-ip)
|
||||||
|
SERVER_IP="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-f|--frontend-ip)
|
||||||
|
FRONTEND_IP="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-d|--db-host)
|
||||||
|
DB_HOST="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-e|--environment)
|
||||||
|
ENV="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
show_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_message "$RED" "Unknown option: $1"
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Validate required parameters
|
||||||
|
if [ -z "$SERVER_IP" ]; then
|
||||||
|
print_message "$RED" "Error: Server IP is required"
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If frontend IP is not provided, use server IP
|
||||||
|
if [ -z "$FRONTEND_IP" ]; then
|
||||||
|
FRONTEND_IP=$SERVER_IP
|
||||||
|
print_message "$YELLOW" "Frontend IP not provided, using Server IP: $FRONTEND_IP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Export environment variables
|
||||||
|
export SERVER_IP
|
||||||
|
export FRONTEND_IP
|
||||||
|
export DB_HOST
|
||||||
|
export NODE_ENV=$ENV
|
||||||
|
|
||||||
|
# Display deployment information
|
||||||
|
print_message "$GREEN" "\nDeployment Configuration:"
|
||||||
|
echo "Server IP: $SERVER_IP"
|
||||||
|
echo "Frontend IP: $FRONTEND_IP"
|
||||||
|
echo "Database Host: $DB_HOST"
|
||||||
|
echo "Environment: $ENV"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Confirm deployment
|
||||||
|
read -p "Do you want to continue with deployment? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
print_message "$YELLOW" "Deployment cancelled"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start deployment
|
||||||
|
print_message "$GREEN" "\nStarting deployment..."
|
||||||
|
|
||||||
|
# Pull latest changes
|
||||||
|
print_message "$YELLOW" "Pulling latest changes..."
|
||||||
|
git pull
|
||||||
|
check_status "Git pull"
|
||||||
|
|
||||||
|
# Stop existing containers
|
||||||
|
print_message "$YELLOW" "Stopping existing containers..."
|
||||||
|
docker-compose down
|
||||||
|
check_status "Stopping containers"
|
||||||
|
|
||||||
|
# Build containers
|
||||||
|
print_message "$YELLOW" "Building containers..."
|
||||||
|
docker-compose build
|
||||||
|
check_status "Building containers"
|
||||||
|
|
||||||
|
# Start containers
|
||||||
|
print_message "$YELLOW" "Starting containers..."
|
||||||
|
docker-compose up -d
|
||||||
|
check_status "Starting containers"
|
||||||
|
|
||||||
|
# Check container status
|
||||||
|
print_message "$YELLOW" "Checking container status..."
|
||||||
|
docker-compose ps
|
||||||
|
check_status "Container status check"
|
||||||
|
|
||||||
|
print_message "$GREEN" "\nDeployment completed successfully!"
|
||||||
@ -5,61 +5,86 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ./router-dashboard
|
context: ./router-dashboard
|
||||||
dockerfile: dockerfile
|
dockerfile: dockerfile
|
||||||
|
args:
|
||||||
|
- SERVER_IP=${SERVER_IP:-localhost}
|
||||||
ports:
|
ports:
|
||||||
- "5173:5173"
|
- "${FRONTEND_PORT:-5173}:5173"
|
||||||
environment:
|
environment:
|
||||||
- VITE_API_URL=${VITE_API_URL}
|
- SERVER_IP=${SERVER_IP:-localhost}
|
||||||
|
- FRONTEND_IP=${FRONTEND_IP:-localhost}
|
||||||
|
- VITE_API_URL=http://${SERVER_IP:-localhost}:${BACKEND_PORT:-3000}/api/v1
|
||||||
|
- VITE_NODE_ENV=${NODE_ENV:-development}
|
||||||
restart: always
|
restart: always
|
||||||
depends_on:
|
depends_on:
|
||||||
backend:
|
backend:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
container_name: router_dashboard_frontend
|
container_name: router_dashboard_frontend
|
||||||
|
networks:
|
||||||
|
- app_network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--spider", "-q", "http://${SERVER_IP:-localhost}:5173"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
backend:
|
backend:
|
||||||
build:
|
build:
|
||||||
context: ./ve-router-backend
|
context: ./ve-router-backend
|
||||||
dockerfile: dockerfile
|
dockerfile: dockerfile
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "${BACKEND_PORT:-3000}:3000"
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=${NODE_ENV}
|
- NODE_ENV=${NODE_ENV:-development}
|
||||||
- DB_HOST=host.docker.internal
|
- DB_HOST=${DB_HOST:-mysql}
|
||||||
- DB_PORT=3306
|
- DB_PORT=${DB_PORT:-3306}
|
||||||
- DB_USER=ve_router_user
|
- DB_USER=${DB_USER:-ve_router_user}
|
||||||
- DB_PASSWORD=ve_router_password
|
- DB_PASSWORD=${DB_PASSWORD:-ve_router_password}
|
||||||
- DB_NAME=${DB_NAME}
|
- DB_NAME=${DB_NAME:-ve_router_db}
|
||||||
|
- CORS_ORIGIN=http://${FRONTEND_IP:-localhost}:${FRONTEND_PORT:-5173},http://${SERVER_IP:-localhost}:${BACKEND_PORT:-3000}
|
||||||
restart: always
|
restart: always
|
||||||
depends_on:
|
depends_on:
|
||||||
mysql:
|
mysql:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "nc", "-z", "localhost", "3000"] # Netcat check to see if port 3000 is open
|
test: ["CMD", "nc", "-z", "${SERVER_IP:-localhost}", "${BACKEND_PORT:-3000}"]
|
||||||
interval: 30s # Check every 30 seconds
|
interval: 30s
|
||||||
retries: 3 # Retry 3 times before marking unhealthy
|
retries: 3
|
||||||
start_period: 30s # Wait 30 seconds before starting health checks
|
start_period: 30s
|
||||||
timeout: 10s # Wait for 10 seconds for each health check to respond
|
timeout: 10s
|
||||||
|
networks:
|
||||||
|
- app_network
|
||||||
|
container_name: router_dashboard_backend
|
||||||
|
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:8.0
|
image: mysql:8.0
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: rootpassword
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-rootpassword}
|
||||||
MYSQL_DATABASE: ve_router_db
|
MYSQL_DATABASE: ${DB_NAME:-ve_router_db}
|
||||||
MYSQL_USER: ve_router_user
|
MYSQL_USER: ${DB_USER:-ve_router_user}
|
||||||
MYSQL_PASSWORD: ve_router_password
|
MYSQL_PASSWORD: ${DB_PASSWORD:-ve_router_password}
|
||||||
|
ENVIRONMENT: ${NODE_ENV:-development}
|
||||||
volumes:
|
volumes:
|
||||||
- mysql_data:/var/lib/mysql
|
- mysql_data:/var/lib/mysql
|
||||||
# Correct paths for init scripts
|
- ./db-scripts:/docker-entrypoint-initdb.d:ro
|
||||||
- ./sql:/docker-entrypoint-initdb.d
|
|
||||||
ports:
|
ports:
|
||||||
- "3306:3306"
|
- "${DB_PORT:-3306}:3306"
|
||||||
command: --default-authentication-plugin=mysql_native_password
|
command: --default-authentication-plugin=mysql_native_password
|
||||||
restart: always
|
restart: always
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "ve_router_user", "-pve_router_password"]
|
test: ["CMD", "mysqladmin", "ping", "-h", "${DB_HOST:-mysql}", "-u${DB_USER:-ve_router_user}", "-p${DB_PASSWORD:-ve_router_password}"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
start_period: 30s
|
start_period: 30s
|
||||||
|
networks:
|
||||||
|
- app_network
|
||||||
|
container_name: router_dashboard_mysql
|
||||||
|
|
||||||
|
networks:
|
||||||
|
app_network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mysql_data:
|
mysql_data:
|
||||||
|
name: router_dashboard_mysql_data
|
||||||
22
readme.txt
22
readme.txt
@ -15,4 +15,24 @@ user/password: ve_router_user/ve_router_password
|
|||||||
docker-compose down
|
docker-compose down
|
||||||
7. Run below command to stop, remove and delete all the volumes
|
7. Run below command to stop, remove and delete all the volumes
|
||||||
Caution : if mysql has volumes then all the existing data will be erasesd
|
Caution : if mysql has volumes then all the existing data will be erasesd
|
||||||
docker-compose down -v
|
docker-compose down -v
|
||||||
|
|
||||||
|
Deploy Instructions:
|
||||||
|
|
||||||
|
1. Basic usage with just server IP:
|
||||||
|
./deploy.sh -s 192.168.1.100
|
||||||
|
2.Specify different IPs for frontend and backend:
|
||||||
|
./deploy.sh -s 192.168.1.100 -f 192.168.1.101
|
||||||
|
3.Specify environment:
|
||||||
|
./deploy.sh -s 192.168.1.100 -e staging
|
||||||
|
4.Full configuration:
|
||||||
|
./deploy.sh -s 192.168.1.100 -f 192.168.1.101 -d mysql -e production
|
||||||
|
5.Run it with the help flag to see options:
|
||||||
|
./deploy.sh --help
|
||||||
|
|
||||||
|
Important notes:
|
||||||
|
|
||||||
|
In production, you should use HTTPS instead of HTTP
|
||||||
|
Make sure your firewall rules allow the necessary ports (3000, 5173, 3306)
|
||||||
|
Consider using a reverse proxy like Nginx in front of your services
|
||||||
|
The MySQL container is accessible to other containers through the service name "mysql" when using Docker networks
|
||||||
@ -1,2 +1,2 @@
|
|||||||
VITE_API_URL=http://localhost:3000/api/v1
|
VITE_API_URL=http://${SERVER_IP:-localhost}:3000/api/v1
|
||||||
VITE_NODE_ENV=development
|
VITE_NODE_ENV=development
|
||||||
2
router-dashboard/.env.production
Normal file
2
router-dashboard/.env.production
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
VITE_API_URL=http://${SERVER_IP}:3000/api/v1
|
||||||
|
VITE_NODE_ENV=production
|
||||||
@ -36,11 +36,10 @@ const DashboardLayout: React.FC = () => {
|
|||||||
data = data.filter(router => {
|
data = data.filter(router => {
|
||||||
switch (activeFilter) {
|
switch (activeFilter) {
|
||||||
case 'active':
|
case 'active':
|
||||||
return router.routerActivity?.studies &&
|
return router.systemStatus.routerStatus === 'CONNECTED' &&
|
||||||
router.routerActivity.studies.length > 0;
|
router.routerActivity?.studies?.some(study => study.studyStatusCode === 'Active');
|
||||||
case 'critical':
|
case 'critical':
|
||||||
return router.systemStatus.vpnStatus === 'VPN_DISCONNECTED' ||
|
return router.systemStatus.routerStatus === 'DISCONNECTED' ||
|
||||||
router.systemStatus.appStatus === 'DISK_CRITICAL' ||
|
|
||||||
router.diskStatus === 'DISK_CRITICAL';
|
router.diskStatus === 'DISK_CRITICAL';
|
||||||
case 'diskAlert':
|
case 'diskAlert':
|
||||||
return router.diskUsage > 80;
|
return router.diskUsage > 80;
|
||||||
@ -74,17 +73,18 @@ const DashboardLayout: React.FC = () => {
|
|||||||
return {
|
return {
|
||||||
total: routerData.length,
|
total: routerData.length,
|
||||||
active: routerData.filter(r =>
|
active: routerData.filter(r =>
|
||||||
r.routerActivity?.studies &&
|
r.systemStatus.routerStatus === 'CONNECTED' && // Router (VM, app, VPN) is up
|
||||||
r.routerActivity.studies.length > 0
|
r.routerActivity?.studies?.some(study => study.studyStatusCode === 'Active') // At least one study is active
|
||||||
).length,
|
).length,
|
||||||
critical: routerData.filter(r =>
|
critical: routerData.filter(r =>
|
||||||
r.systemStatus.vpnStatus === 'VPN_DISCONNECTED' ||
|
r.systemStatus.routerStatus === 'DISCONNECTED' || // Router (VM, app, VPN) is down
|
||||||
r.systemStatus.appStatus === 'DISK_CRITICAL' ||
|
r.diskStatus === 'DISK_CRITICAL' // Disk is critical
|
||||||
r.diskStatus === 'DISK_CRITICAL'
|
|
||||||
).length,
|
).length,
|
||||||
diskAlert: routerData.filter(r => r.diskUsage > 80).length
|
diskAlert: routerData.filter(r => r.diskUsage > 80).length // Disk usage alert
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@ -128,6 +128,7 @@ const DashboardLayout: React.FC = () => {
|
|||||||
activeFilter === 'active' ? 'ring-2 ring-blue-500' : ''
|
activeFilter === 'active' ? 'ring-2 ring-blue-500' : ''
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setActiveFilter('active')}
|
onClick={() => setActiveFilter('active')}
|
||||||
|
title="Study in transmit currently"
|
||||||
>
|
>
|
||||||
<h3 className="text-sm font-medium text-gray-500">Active Routers</h3>
|
<h3 className="text-sm font-medium text-gray-500">Active Routers</h3>
|
||||||
<p className="text-2xl font-semibold text-green-600 mt-1">{summary.active}</p>
|
<p className="text-2xl font-semibold text-green-600 mt-1">{summary.active}</p>
|
||||||
|
|||||||
@ -22,8 +22,8 @@ interface Tab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Navbar: React.FC<NavbarProps> = ({ activeTab, onTabChange }) => {
|
const Navbar: React.FC<NavbarProps> = ({ activeTab, onTabChange }) => {
|
||||||
const [isCollapsed, setIsCollapsed] = useState(false);
|
const [isCollapsed, setIsCollapsed] = useState(true);
|
||||||
const [isPinned, setIsPinned] = useState(true);
|
const [isPinned, setIsPinned] = useState(false);
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
|
||||||
const tabs: Tab[] = [
|
const tabs: Tab[] = [
|
||||||
|
|||||||
@ -2,13 +2,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ChevronRight, ChevronDown } from 'lucide-react';
|
import { ChevronRight, ChevronDown } from 'lucide-react';
|
||||||
import { RouterData } from '../../types';
|
import { RouterData } from '../../types';
|
||||||
import { STATUS_COLORS, formatStatus, getStatusColor, getVMStatus, getSystemStatus } from '../../utils/statusHelpers';
|
import { STATUS_COLORS, formatStatus, getStatusColor} from '../../utils/statusHelpers';
|
||||||
|
|
||||||
interface RouterTableRowProps {
|
interface RouterTableRowProps {
|
||||||
router: RouterData;
|
router: RouterData;
|
||||||
expandedRows: Set<string>;
|
expandedRows: Set<string>;
|
||||||
timeLeft: { [key: string]: number };
|
timeLeft: { [key: string]: number };
|
||||||
onToggleExpansion: (id: number, section: 'activity' | 'status' | 'disk') => void;
|
onToggleExpansion: (id: number, section: 'router_details' |'activity' | 'status' | 'disk') => void;
|
||||||
onExpandedContentHover: (id: number, section: 'activity' | 'status' | 'disk') => void;
|
onExpandedContentHover: (id: number, section: 'activity' | 'status' | 'disk') => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +41,32 @@ export const RouterTableRow: React.FC<RouterTableRowProps> = ({
|
|||||||
return 'bg-green-500';
|
return 'bg-green-500';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderRouterDetailsPanel = () => (
|
||||||
|
<div
|
||||||
|
className="bg-gray-50 p-4 relative"
|
||||||
|
onMouseEnter={() => onExpandedContentHover(router.id, 'router_details')}
|
||||||
|
>
|
||||||
|
<div className="h-1 bg-gray-200 absolute top-0 left-0 right-0">
|
||||||
|
<div
|
||||||
|
className="h-1 bg-blue-500 transition-all duration-200"
|
||||||
|
style={{ width: `${timeLeft[`${router.id}-router_details`] || 0}%` }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h3 className="font-semibold mb-3">Router Details</h3>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-3 gap-4">
|
||||||
|
<div className="bg-white p-3 rounded shadow-sm">
|
||||||
|
<div className="grid gap-2">
|
||||||
|
<div><span className="font-medium">Facility AET:</span> {router.facilityAET}</div>
|
||||||
|
<div><span className="font-medium">OpenVPN IP:</span> {router.openvpnIp}</div>
|
||||||
|
<div><span className="font-medium">Router VM Primary IP:</span> {router.routerVmPrimaryIp}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
const renderActivityPanel = () => (
|
const renderActivityPanel = () => (
|
||||||
<div
|
<div
|
||||||
className="bg-gray-50 p-4 relative"
|
className="bg-gray-50 p-4 relative"
|
||||||
@ -90,8 +116,8 @@ export const RouterTableRow: React.FC<RouterTableRowProps> = ({
|
|||||||
<div className="grid grid-cols-3 gap-4">
|
<div className="grid grid-cols-3 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-semibold mb-2">VM Status</h4>
|
<h4 className="font-semibold mb-2">VM Status</h4>
|
||||||
<span className={`px-2 py-1 rounded-full text-sm ${getStatusColor(getVMStatus(router.lastSeen))}`}>
|
<span className={`px-2 py-1 rounded-full text-sm ${getStatusColor(router.systemStatus.vmStatus)}`}>
|
||||||
{formatStatus(getVMStatus(router.lastSeen))}
|
{formatStatus(router.systemStatus.vmStatus)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -156,7 +182,19 @@ export const RouterTableRow: React.FC<RouterTableRowProps> = ({
|
|||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<tr className="border-b hover:bg-gray-50">
|
<tr className="border-b hover:bg-gray-50">
|
||||||
<td className="px-4 py-2">{router.slNo}</td>
|
<td className="px-4 py-2">{router.slNo}</td>
|
||||||
<td className="px-4 py-2">{router.routerId}</td>
|
<td className="px-4 py-2">
|
||||||
|
<button
|
||||||
|
onClick={() => onToggleExpansion(router.id, 'router_details')}
|
||||||
|
className="flex items-center gap-1 text-blue-500 hover:text-blue-700"
|
||||||
|
>
|
||||||
|
{expandedRows.has(`${router.id}-router_details`) ? (
|
||||||
|
<ChevronDown size={16} />
|
||||||
|
) : (
|
||||||
|
<ChevronRight size={16} />
|
||||||
|
)}
|
||||||
|
<span>{router.routerId}</span>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
<td className="px-4 py-2">{router.routerAlias}</td>
|
<td className="px-4 py-2">{router.routerAlias}</td>
|
||||||
<td className="px-4 py-2">{router.facility}</td>
|
<td className="px-4 py-2">{router.facility}</td>
|
||||||
<td className="px-4 py-2">
|
<td className="px-4 py-2">
|
||||||
@ -169,7 +207,8 @@ export const RouterTableRow: React.FC<RouterTableRowProps> = ({
|
|||||||
) : (
|
) : (
|
||||||
<ChevronRight size={16} />
|
<ChevronRight size={16} />
|
||||||
)}
|
)}
|
||||||
View Activity ({router.routerActivity.studies.length} studies)
|
|
||||||
|
<span>{router?.routerActivity?.studies?.[0]?.studyStatusCode || "Idle"}</span>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-2">
|
<td className="px-4 py-2">
|
||||||
@ -182,8 +221,8 @@ export const RouterTableRow: React.FC<RouterTableRowProps> = ({
|
|||||||
) : (
|
) : (
|
||||||
<ChevronRight size={16} />
|
<ChevronRight size={16} />
|
||||||
)}
|
)}
|
||||||
<span className={`ml-2 px-2 py-1 rounded-full text-sm ${getStatusColor(router.systemStatus.vpnStatus)}`}>
|
<span className={`ml-2 px-2 py-1 rounded-full text-sm ${getStatusColor(router.systemStatus.routerStatus)}`}>
|
||||||
{formatStatus(router.systemStatus.vpnStatus)}
|
{formatStatus(router.systemStatus.routerStatus)}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
@ -212,6 +251,13 @@ export const RouterTableRow: React.FC<RouterTableRowProps> = ({
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{/* Expandable Panels */}
|
{/* Expandable Panels */}
|
||||||
|
{expandedRows.has(`${router.id}-router_details`) && (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={8}>
|
||||||
|
{renderRouterDetailsPanel()}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
{expandedRows.has(`${router.id}-activity`) && (
|
{expandedRows.has(`${router.id}-activity`) && (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={8}>
|
<td colSpan={8}>
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
// src/config/env.ts
|
// src/config/env.ts
|
||||||
interface Config {
|
interface Config {
|
||||||
apiUrl: string;
|
apiUrl: string;
|
||||||
environment: string;
|
environment: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const config: Config = {
|
const config: Config = {
|
||||||
apiUrl: import.meta.env.VITE_API_URL || 'http://localhost:3000/api/v1',
|
apiUrl: import.meta.env.VITE_API_URL,
|
||||||
environment: import.meta.env.VITE_NODE_ENV || 'development',
|
environment: import.meta.env.VITE_NODE_ENV || 'development',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
@ -21,6 +21,9 @@ export const MOCK_ROUTERS: RouterData[] = [
|
|||||||
routerId: 'RTR001',
|
routerId: 'RTR001',
|
||||||
facility: 'City Hospital',
|
facility: 'City Hospital',
|
||||||
routerAlias: 'Main-Router-1',
|
routerAlias: 'Main-Router-1',
|
||||||
|
facilityAET: 'RTR_1',
|
||||||
|
openvpnIp: '10.8.0.101',
|
||||||
|
routerVmPrimaryIp: '192.168.0.101',
|
||||||
lastSeen: '2024-03-07T14:30:00Z',
|
lastSeen: '2024-03-07T14:30:00Z',
|
||||||
diskStatus: 'Normal',
|
diskStatus: 'Normal',
|
||||||
diskUsage: 45,
|
diskUsage: 45,
|
||||||
@ -64,6 +67,9 @@ export const MOCK_ROUTERS: RouterData[] = [
|
|||||||
routerId: 'RTR002',
|
routerId: 'RTR002',
|
||||||
facility: 'Medical Center',
|
facility: 'Medical Center',
|
||||||
routerAlias: 'Emergency-Router',
|
routerAlias: 'Emergency-Router',
|
||||||
|
facilityAET: 'RTR_2',
|
||||||
|
openvpnIp: '10.8.0.102',
|
||||||
|
routerVmPrimaryIp: '192.168.0.102',
|
||||||
lastSeen: '2024-03-07T14:25:00Z',
|
lastSeen: '2024-03-07T14:25:00Z',
|
||||||
diskStatus: 'Critical',
|
diskStatus: 'Critical',
|
||||||
diskUsage: 92,
|
diskUsage: 92,
|
||||||
@ -97,6 +103,9 @@ export const MOCK_ROUTERS: RouterData[] = [
|
|||||||
routerId: 'RTR003',
|
routerId: 'RTR003',
|
||||||
facility: 'Imaging Center',
|
facility: 'Imaging Center',
|
||||||
routerAlias: 'Radiology-Router',
|
routerAlias: 'Radiology-Router',
|
||||||
|
facilityAET: 'RTR_3',
|
||||||
|
openvpnIp: '10.8.0.103',
|
||||||
|
routerVmPrimaryIp: '192.168.0.103',
|
||||||
lastSeen: '2024-03-07T14:20:00Z',
|
lastSeen: '2024-03-07T14:20:00Z',
|
||||||
diskStatus: 'Warning',
|
diskStatus: 'Warning',
|
||||||
diskUsage: 78,
|
diskUsage: 78,
|
||||||
|
|||||||
@ -58,6 +58,9 @@ class ApiService {
|
|||||||
routerId: router.routerId, // Changed from router.router_id
|
routerId: router.routerId, // Changed from router.router_id
|
||||||
facility: router.facility,
|
facility: router.facility,
|
||||||
routerAlias: router.routerAlias, // Changed from router.router_alias
|
routerAlias: router.routerAlias, // Changed from router.router_alias
|
||||||
|
facilityAET: router.facilityAET, // Changed from router.facility_aet
|
||||||
|
openvpnIp: router.openvpnIp, // Changed from router.openvpn_ip
|
||||||
|
routerVmPrimaryIp: router.routerVmPrimaryIp, // Changed from router.router_vm_primary_ip
|
||||||
lastSeen: router.lastSeen, // Changed from router.last_seen
|
lastSeen: router.lastSeen, // Changed from router.last_seen
|
||||||
diskStatus: router.diskStatus, // Changed from router.disk_status_code
|
diskStatus: router.diskStatus, // Changed from router.disk_status_code
|
||||||
diskUsage: router.diskUsage || 0, // Changed from router.disk_usage
|
diskUsage: router.diskUsage || 0, // Changed from router.disk_usage
|
||||||
@ -72,13 +75,17 @@ class ApiService {
|
|||||||
patientName: study.patientName,
|
patientName: study.patientName,
|
||||||
studyDate: study.studyDate,
|
studyDate: study.studyDate,
|
||||||
modality: study.modality,
|
modality: study.modality,
|
||||||
studyDescription: study.studyDescription
|
studyDescription: study.studyDescription,
|
||||||
|
studyStatusCode: study.studyStatusCode
|
||||||
|
|
||||||
}))
|
}))
|
||||||
: []
|
: []
|
||||||
},
|
},
|
||||||
systemStatus: {
|
systemStatus: {
|
||||||
vpnStatus: router.systemStatus?.vpnStatus || 'unknown',
|
vpnStatus: router.systemStatus?.vpnStatus || 'unknown',
|
||||||
appStatus: router.systemStatus?.appStatus || 'unknown',
|
appStatus: router.systemStatus?.appStatus || 'unknown',
|
||||||
|
vmStatus: router.systemStatus?.vmStatus || 'unknown',
|
||||||
|
routerStatus: router.systemStatus?.routerStatus || 'unknown',
|
||||||
vms: Array.isArray(router.systemStatus?.vms)
|
vms: Array.isArray(router.systemStatus?.vms)
|
||||||
? router.systemStatus.vms.map((vm: any) => ({
|
? router.systemStatus.vms.map((vm: any) => ({
|
||||||
id: vm.id,
|
id: vm.id,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ export interface BackendStudy {
|
|||||||
study_date: string;
|
study_date: string;
|
||||||
modality: string;
|
modality: string;
|
||||||
study_description: string;
|
study_description: string;
|
||||||
|
study_status_code: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BackendVM {
|
export interface BackendVM {
|
||||||
@ -21,6 +22,9 @@ export interface BackendStudy {
|
|||||||
router_id: string;
|
router_id: string;
|
||||||
facility: string;
|
facility: string;
|
||||||
router_alias: string;
|
router_alias: string;
|
||||||
|
facility_aet: string;
|
||||||
|
openvpn_ip: string;
|
||||||
|
router_vm_primary_ip: string;
|
||||||
last_seen: string;
|
last_seen: string;
|
||||||
disk_status_code: string;
|
disk_status_code: string;
|
||||||
disk_usage: number;
|
disk_usage: number;
|
||||||
|
|||||||
@ -7,6 +7,7 @@ export interface Study {
|
|||||||
studyDate: string;
|
studyDate: string;
|
||||||
modality: string;
|
modality: string;
|
||||||
studyDescription: string;
|
studyDescription: string;
|
||||||
|
studyStatusCode: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VM {
|
export interface VM {
|
||||||
@ -27,6 +28,9 @@ export interface RouterData {
|
|||||||
routerId: string;
|
routerId: string;
|
||||||
facility: string;
|
facility: string;
|
||||||
routerAlias: string;
|
routerAlias: string;
|
||||||
|
facilityAET: string;
|
||||||
|
openvpnIp: string;
|
||||||
|
routerVmPrimaryIp: string;
|
||||||
lastSeen: string;
|
lastSeen: string;
|
||||||
diskStatus: string;
|
diskStatus: string;
|
||||||
diskUsage: number;
|
diskUsage: number;
|
||||||
@ -38,6 +42,8 @@ export interface RouterData {
|
|||||||
systemStatus: {
|
systemStatus: {
|
||||||
vpnStatus: string;
|
vpnStatus: string;
|
||||||
appStatus: string;
|
appStatus: string;
|
||||||
|
vmStatus: string;
|
||||||
|
routerStatus: string;
|
||||||
vms: VM[];
|
vms: VM[];
|
||||||
containers: Container[];
|
containers: Container[];
|
||||||
};
|
};
|
||||||
|
|||||||
@ -49,32 +49,3 @@ export const formatStatus = (status: string): string => {
|
|||||||
return getStatus(getStatusAfterUnderscore(status));
|
return getStatus(getStatusAfterUnderscore(status));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getVMStatus = (lastSeen: string | number | Date) => {
|
|
||||||
const currentTime = new Date();
|
|
||||||
const lastSeenTime = new Date(lastSeen);
|
|
||||||
|
|
||||||
// Use getTime() to get timestamps in milliseconds
|
|
||||||
const diffInMinutes = (currentTime.getTime() - lastSeenTime.getTime()) / (1000 * 60);
|
|
||||||
|
|
||||||
return diffInMinutes > 1 ? 'NET_ONLINE' : 'NET_ONLINE'; //demo purpose returning only online
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getSystemStatus = (lastSeen: string | number | Date, vpnStatus: string, appStatus:string) => {
|
|
||||||
const vmStatus = getVMStatus(lastSeen);
|
|
||||||
|
|
||||||
const expectedStatuses = {
|
|
||||||
VPN_CONNECTED: 'VPN_CONNECTED',
|
|
||||||
CONTAINER_RUNNING: 'CONTAINER_RUNNING',
|
|
||||||
NET_ONLINE: 'NET_ONLINE',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (
|
|
||||||
vpnStatus === expectedStatuses.VPN_CONNECTED &&
|
|
||||||
appStatus === expectedStatuses.CONTAINER_RUNNING &&
|
|
||||||
vmStatus === expectedStatuses.NET_ONLINE
|
|
||||||
) {
|
|
||||||
return 'CONNECTED';
|
|
||||||
}
|
|
||||||
return 'DISCONNECTED';
|
|
||||||
|
|
||||||
};
|
|
||||||
@ -1,105 +0,0 @@
|
|||||||
DELIMITER //
|
|
||||||
|
|
||||||
CREATE PROCEDURE seed_complete_router_system()
|
|
||||||
BEGIN
|
|
||||||
DECLARE done INT DEFAULT 0;
|
|
||||||
DECLARE table_name VARCHAR(64);
|
|
||||||
DECLARE table_cursor CURSOR FOR
|
|
||||||
SELECT table_name
|
|
||||||
FROM information_schema.tables
|
|
||||||
WHERE table_schema = DATABASE()
|
|
||||||
AND table_name IN (
|
|
||||||
'auth_log', 'user_sessions', 'user_router_access', 'users',
|
|
||||||
'container_status_history', 'router_status_history',
|
|
||||||
'container_status', 'dicom_study_overview',
|
|
||||||
'router_settings_history', 'router_settings',
|
|
||||||
'routers', 'status_type', 'status_category'
|
|
||||||
);
|
|
||||||
|
|
||||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
|
|
||||||
|
|
||||||
-- Disable foreign key checks
|
|
||||||
SET FOREIGN_KEY_CHECKS=0;
|
|
||||||
|
|
||||||
-- Truncate all tables dynamically
|
|
||||||
OPEN table_cursor;
|
|
||||||
truncate_loop: LOOP
|
|
||||||
FETCH table_cursor INTO table_name;
|
|
||||||
IF done THEN
|
|
||||||
LEAVE truncate_loop;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
SET @query = CONCAT('TRUNCATE TABLE ', table_name);
|
|
||||||
PREPARE stmt FROM @query;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
END LOOP;
|
|
||||||
CLOSE table_cursor;
|
|
||||||
|
|
||||||
-- Re-enable foreign key checks
|
|
||||||
SET FOREIGN_KEY_CHECKS=1;
|
|
||||||
|
|
||||||
-- Insert Status Categories
|
|
||||||
INSERT INTO status_category (name, description)
|
|
||||||
VALUES
|
|
||||||
('Network', 'Network related statuses'),
|
|
||||||
('Disk', 'Disk related statuses'),
|
|
||||||
('VPN', 'VPN connection statuses'),
|
|
||||||
('License', 'License statuses'),
|
|
||||||
('Container', 'Container related statuses')
|
|
||||||
ON DUPLICATE KEY UPDATE id = id;
|
|
||||||
|
|
||||||
-- Insert Status Types
|
|
||||||
INSERT INTO status_type (category_id, name, code, description, severity)
|
|
||||||
VALUES
|
|
||||||
(1, 'Online', 'NET_ONLINE', 'System is online', 1),
|
|
||||||
(1, 'Offline', 'NET_OFFLINE', 'System is offline', 5),
|
|
||||||
(2, 'Normal', 'DISK_NORMAL', 'Disk usage is normal', 1),
|
|
||||||
(2, 'Warning', 'DISK_WARNING', 'Disk usage is high', 3),
|
|
||||||
(2, 'Critical', 'DISK_CRITICAL', 'Disk usage is critical', 5),
|
|
||||||
(3, 'Connected', 'VPN_CONNECTED', 'VPN is connected', 1),
|
|
||||||
(3, 'Disconnected', 'VPN_DISCONNECTED', 'VPN is disconnected', 5),
|
|
||||||
(5, 'Running', 'CONTAINER_RUNNING', 'Container is running', 1),
|
|
||||||
(5, 'Stopped', 'CONTAINER_STOPPED', 'Container is stopped', 5)
|
|
||||||
ON DUPLICATE KEY UPDATE id = id;
|
|
||||||
|
|
||||||
-- Insert Routers
|
|
||||||
INSERT INTO routers (router_id, facility, router_alias, last_seen, vpn_status_code, disk_status_code, app_status_code, license_status, free_disk, total_disk, disk_usage)
|
|
||||||
VALUES
|
|
||||||
('RTR001', 'Main Hospital', 'MAIN_RAD', NOW(), 'VPN_CONNECTED', 'DISK_NORMAL', 'CONTAINER_RUNNING', 'active', 500000000000, 1000000000000, 50.00),
|
|
||||||
('RTR002', 'Emergency Center', 'ER_RAD', NOW(), 'VPN_CONNECTED', 'DISK_WARNING', 'CONTAINER_RUNNING', 'active', 400000000000, 1000000000000, 60.00),
|
|
||||||
('RTR003', 'Imaging Center', 'IMG_CENTER', NOW(), 'VPN_CONNECTED', 'DISK_NORMAL', 'CONTAINER_RUNNING', 'active', 600000000000, 1000000000000, 40.00)
|
|
||||||
ON DUPLICATE KEY UPDATE id = id;
|
|
||||||
|
|
||||||
-- Store Router IDs
|
|
||||||
SET @router1_id = (SELECT id FROM routers WHERE router_id = 'RTR001');
|
|
||||||
SET @router2_id = (SELECT id FROM routers WHERE router_id = 'RTR002');
|
|
||||||
SET @router3_id = (SELECT id FROM routers WHERE router_id = 'RTR003');
|
|
||||||
|
|
||||||
-- Insert Container Status
|
|
||||||
INSERT INTO container_status (router_id, container_name, status_code, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(1, 'router-cstore-scp', 'CONTAINER_RUNNING', NOW(), NOW()),
|
|
||||||
(1, 'router-cstore-scu', 'CONTAINER_RUNNING', NOW(), NOW()),
|
|
||||||
(2, 'router-cstore-scp', 'CONTAINER_RUNNING', NOW(), NOW()),
|
|
||||||
(2, 'router-cstore-scu', 'CONTAINER_RUNNING', NOW(), NOW()),
|
|
||||||
(3, 'router-cstore-scp', 'CONTAINER_RUNNING', NOW(), NOW())
|
|
||||||
ON DUPLICATE KEY UPDATE id = id;
|
|
||||||
|
|
||||||
-- Insert DICOM Study Overview
|
|
||||||
INSERT INTO dicom_study_overview (
|
|
||||||
router_id, study_instance_uid, patient_id, patient_name,
|
|
||||||
accession_number, study_date, modality, study_description,
|
|
||||||
series_instance_uid, procedure_code, referring_physician_name
|
|
||||||
)
|
|
||||||
VALUES
|
|
||||||
(@router1_id, '1.2.840.113619.2.55.3.283116435.276.1543707218.134', 'P1', 'John Doe', 'ACC1234', '2024-03-15', 'CT', 'Chest CT', '1.2.840.113619.2.55.3.283116435.276.1543707219.135', 'CT001', 'Dr. Smith'),
|
|
||||||
(@router2_id, '1.2.840.113619.2.55.3.283116435.276.1543707218.136', 'P2', 'Jane Doe', 'ACC1235', '2024-03-15', 'MR', 'Brain MRI', '1.2.840.113619.2.55.3.283116435.276.1543707219.137', 'MR001', 'Dr. Johnson')
|
|
||||||
ON DUPLICATE KEY UPDATE id = id;
|
|
||||||
|
|
||||||
END //
|
|
||||||
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
-- Automatically call the procedure after creation
|
|
||||||
CALL seed_complete_router_system();
|
|
||||||
@ -1,15 +1,13 @@
|
|||||||
|
|
||||||
# Server Configuration
|
# Server Configuration
|
||||||
NODE_ENV=development
|
NODE_ENV=production
|
||||||
PORT=3000
|
PORT=3000
|
||||||
CORS_ORIGIN=http://localhost:5173,http://localhost:3000
|
CORS_ORIGIN=http://${FRONTEND_IP}:5173,http://${SERVER_IP}:3000
|
||||||
|
|
||||||
|
|
||||||
# Database Configuration
|
# Database Configuration
|
||||||
DB_HOST=localhost
|
DB_HOST=${DB_HOST}
|
||||||
DB_PORT=3306
|
DB_PORT=3306
|
||||||
DB_USER=root
|
DB_USER=ve_router_user
|
||||||
DB_PASSWORD=rootpassword
|
DB_PASSWORD=ve_router_password
|
||||||
DB_NAME=ve_router_db
|
DB_NAME=ve_router_db
|
||||||
DB_CONNECTION_LIMIT=10
|
DB_CONNECTION_LIMIT=10
|
||||||
|
|
||||||
|
|||||||
@ -1,22 +1,20 @@
|
|||||||
// src/config/config.ts
|
// src/config/config.ts
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
// Initialize dotenv at the very start
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
env: process.env.NODE_ENV || 'development',
|
env: process.env.NODE_ENV || 'development',
|
||||||
server: {
|
server: {
|
||||||
port: parseInt(process.env.PORT || '3000', 10),
|
port: parseInt(process.env.PORT || '3000', 10),
|
||||||
// Update this to include your frontend URL
|
corsOrigin: process.env.CORS_ORIGIN?.split(',') || ['*'], // In production, replace with actual domains
|
||||||
corsOrigin: process.env.CORS_ORIGIN?.split(',') || ['http://localhost:5173', 'http://localhost:3000'],
|
|
||||||
apiPrefix: '/api/v1'
|
apiPrefix: '/api/v1'
|
||||||
},
|
},
|
||||||
db: {
|
db: {
|
||||||
host: process.env.DB_HOST || 'localhost',
|
host: process.env.DB_HOST || 'localhost',
|
||||||
port: parseInt(process.env.DB_PORT || '3306', 10),
|
port: parseInt(process.env.DB_PORT || '3306', 10),
|
||||||
user: process.env.DB_USER || 'root',
|
user: process.env.DB_USER || 've_router_user',
|
||||||
password: process.env.DB_PASSWORD || '', // Make sure this is getting the password
|
password: process.env.DB_PASSWORD || 've_router_password',
|
||||||
database: process.env.DB_NAME || 've_router_db',
|
database: process.env.DB_NAME || 've_router_db',
|
||||||
connectionLimit: parseInt(process.env.DB_CONNECTION_LIMIT || '10', 10)
|
connectionLimit: parseInt(process.env.DB_CONNECTION_LIMIT || '10', 10)
|
||||||
},
|
},
|
||||||
@ -26,13 +24,4 @@ const config = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add this for debugging
|
export default config;
|
||||||
console.log('Database Config:', {
|
|
||||||
host: config.db.host,
|
|
||||||
user: config.db.user,
|
|
||||||
database: config.db.database,
|
|
||||||
// Don't log the password
|
|
||||||
});
|
|
||||||
|
|
||||||
export default config;
|
|
||||||
|
|
||||||
@ -11,65 +11,65 @@ export class RouterRepository {
|
|||||||
|
|
||||||
// src/repositories/RouterRepository.ts
|
// src/repositories/RouterRepository.ts
|
||||||
// src/repositories/RouterRepository.ts
|
// src/repositories/RouterRepository.ts
|
||||||
async updateVMs(routerId: string, vms: VMUpdate[]): Promise<any> {
|
async updateVMs(routerId: string, vms: VMUpdate[]): Promise<any> {
|
||||||
console.log('Repository: Starting VM update for router:', routerId);
|
console.log('Repository: Starting VM update for router:', routerId);
|
||||||
const connection = await this.pool.getConnection();
|
const connection = await this.pool.getConnection();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await connection.beginTransaction();
|
await connection.beginTransaction();
|
||||||
console.log('Started transaction');
|
console.log('Started transaction');
|
||||||
|
|
||||||
// First verify router exists
|
// First verify router exists
|
||||||
const [routers] = await connection.query(
|
const [routers] = await connection.query(
|
||||||
'SELECT id FROM routers WHERE router_id = ?',
|
'SELECT id FROM routers WHERE router_id = ?',
|
||||||
[routerId]
|
[routerId]
|
||||||
);
|
);
|
||||||
console.log('Router query result:', routers);
|
console.log('Router query result:', routers);
|
||||||
|
|
||||||
if (!Array.isArray(routers) || routers.length === 0) {
|
if (!Array.isArray(routers) || routers.length === 0) {
|
||||||
throw new Error(`Router ${routerId} not found`);
|
throw new Error(`Router ${routerId} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log each VM update
|
// Log each VM update
|
||||||
for (const vm of vms) {
|
for (const vm of vms) {
|
||||||
console.log(`Processing VM ${vm.vm_number}`);
|
console.log(`Processing VM ${vm.vm_number}`);
|
||||||
const [result]: any = await connection.query(
|
const [result]: any = await connection.query(
|
||||||
`UPDATE vm_details
|
`UPDATE vm_details
|
||||||
SET status_code = ?,
|
SET status_code = ?,
|
||||||
updated_at = CURRENT_TIMESTAMP
|
updated_at = CURRENT_TIMESTAMP
|
||||||
WHERE router_id = ? AND vm_number = ?`,
|
WHERE router_id = ? AND vm_number = ?`,
|
||||||
[vm.status_code, routerId, vm.vm_number]
|
[vm.status_code, routerId, vm.vm_number]
|
||||||
);
|
);
|
||||||
console.log('Update result:', result);
|
console.log('Update result:', result);
|
||||||
|
|
||||||
if (!result.affectedRows) {
|
if (!result.affectedRows) {
|
||||||
console.log('No rows affected, attempting insert');
|
console.log('No rows affected, attempting insert');
|
||||||
await connection.query(
|
await connection.query(
|
||||||
`INSERT INTO vm_details (router_id, vm_number, status_code)
|
`INSERT INTO vm_details (router_id, vm_number, status_code)
|
||||||
VALUES (?, ?, ?)`,
|
VALUES (?, ?, ?)`,
|
||||||
[routerId, vm.vm_number, vm.status_code]
|
[routerId, vm.vm_number, vm.status_code]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await connection.commit();
|
await connection.commit();
|
||||||
console.log('Transaction committed');
|
console.log('Transaction committed');
|
||||||
|
|
||||||
const [updatedVMs] = await connection.query(
|
const [updatedVMs] = await connection.query(
|
||||||
`SELECT * FROM vm_details WHERE router_id = ? ORDER BY vm_number`,
|
`SELECT * FROM vm_details WHERE router_id = ? ORDER BY vm_number`,
|
||||||
[routerId]
|
[routerId]
|
||||||
);
|
);
|
||||||
return updatedVMs;
|
return updatedVMs;
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Repository error:', err);
|
console.error('Repository error:', err);
|
||||||
await connection.rollback();
|
await connection.rollback();
|
||||||
throw err;
|
throw err;
|
||||||
} finally {
|
} finally {
|
||||||
connection.release();
|
connection.release();
|
||||||
console.log('Connection released');
|
console.log('Connection released');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private async getRouterStudies(routerId: number): Promise<Study[]> {
|
private async getRouterStudies(routerId: number): Promise<Study[]> {
|
||||||
try {
|
try {
|
||||||
@ -81,10 +81,12 @@ async updateVMs(routerId: string, vms: VMUpdate[]): Promise<any> {
|
|||||||
patient_name as patientName,
|
patient_name as patientName,
|
||||||
DATE_FORMAT(study_date, '%Y-%m-%d') as studyDate,
|
DATE_FORMAT(study_date, '%Y-%m-%d') as studyDate,
|
||||||
modality,
|
modality,
|
||||||
study_description as studyDescription
|
study_description as studyDescription,
|
||||||
|
CONCAT(UPPER(SUBSTRING(study_status_code, 1, 1)), LOWER(SUBSTRING(study_status_code, 2))) as studyStatusCode
|
||||||
FROM dicom_study_overview
|
FROM dicom_study_overview
|
||||||
WHERE router_id = ?
|
WHERE router_id = ?
|
||||||
ORDER BY study_date DESC`,
|
ORDER BY updated_at DESC
|
||||||
|
LIMIT 1`,
|
||||||
[routerId]
|
[routerId]
|
||||||
);
|
);
|
||||||
return rows as Study[];
|
return rows as Study[];
|
||||||
@ -126,32 +128,52 @@ async updateVMs(routerId: string, vms: VMUpdate[]): Promise<any> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getRouterContainers(routerId: number): Promise<Container[]> {
|
private async getRouterContainers(routerId: number): Promise<Container[]> {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Then use this to query vm_details
|
// Then use this to query vm_details
|
||||||
const [rows] = await pool.query<RowDataPacket[]>(
|
const [rows] = await pool.query<RowDataPacket[]>(
|
||||||
`SELECT
|
`SELECT
|
||||||
container_name,
|
container_name,
|
||||||
status_code
|
status_code
|
||||||
FROM container_status
|
FROM container_status
|
||||||
WHERE router_id = ?`,
|
WHERE router_id = ?`,
|
||||||
[routerId]
|
[routerId]
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info(`Containers for router ${routerId}:`, rows);
|
logger.info(`Containers for router ${routerId}:`, rows);
|
||||||
return rows as Container[];
|
return rows as Container[];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Error fetching Containers for router ${routerId}:`, error);
|
logger.error(`Error fetching Containers for router ${routerId}:`, error);
|
||||||
return [];
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private async calculateVMStatus (lastSeen: string | number | Date): Promise<string> {
|
||||||
|
const currentTime = new Date();
|
||||||
|
const lastSeenTime = new Date(lastSeen);
|
||||||
|
|
||||||
|
// Use getTime() to get timestamps in milliseconds
|
||||||
|
const diffInMinutes = (currentTime.getTime() - lastSeenTime.getTime()) / (1000 * 60);
|
||||||
|
|
||||||
|
return diffInMinutes > 1 ? 'NET_OFFLINE' : 'NET_ONLINE';
|
||||||
|
};
|
||||||
|
|
||||||
|
private async calculateSystemStatus (vpnStatus: string, appStatus: string, vmStatus: string): Promise<string> {
|
||||||
|
return vpnStatus === 'VPN_CONNECTED' && appStatus === 'CONTAINER_RUNNING' && vmStatus === 'NET_ONLINE' ? 'CONNECTED' : 'DISCONNECTED';
|
||||||
|
};
|
||||||
|
|
||||||
private async transformDatabaseRouter(dbRouter: any, index: number): Promise<RouterData> {
|
private async transformDatabaseRouter(dbRouter: any, index: number): Promise<RouterData> {
|
||||||
try {
|
try {
|
||||||
const studies = await this.getRouterStudies(dbRouter.id);
|
const studies = await this.getRouterStudies(dbRouter.id);
|
||||||
const vms = await this.getRouterVMs(dbRouter.id);
|
//const vms = await this.getRouterVMs(dbRouter.id);
|
||||||
|
const vms:VM[] = [];
|
||||||
const containers = await this.getRouterContainers(dbRouter.id);
|
const containers = await this.getRouterContainers(dbRouter.id);
|
||||||
|
const lastSeen = new Date(dbRouter.last_seen).toISOString();
|
||||||
|
const vpnStatus = dbRouter.vpn_status_code.toString();
|
||||||
|
const appStatus = dbRouter.app_status_code.toString();
|
||||||
|
const vmStatus = await this.calculateVMStatus(lastSeen);
|
||||||
|
const routerStatus = await this.calculateSystemStatus(vpnStatus, appStatus, vmStatus);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: dbRouter.id,
|
id: dbRouter.id,
|
||||||
@ -159,7 +181,10 @@ private async getRouterContainers(routerId: number): Promise<Container[]> {
|
|||||||
routerId: dbRouter.router_id,
|
routerId: dbRouter.router_id,
|
||||||
facility: dbRouter.facility,
|
facility: dbRouter.facility,
|
||||||
routerAlias: dbRouter.router_alias,
|
routerAlias: dbRouter.router_alias,
|
||||||
lastSeen: new Date(dbRouter.last_seen).toISOString(),
|
facilityAET: dbRouter.facility_aet,
|
||||||
|
openvpnIp: dbRouter.openvpn_ip,
|
||||||
|
routerVmPrimaryIp: dbRouter.router_vm_primary_ip,
|
||||||
|
lastSeen: lastSeen,
|
||||||
diskStatus: dbRouter.disk_status_code,
|
diskStatus: dbRouter.disk_status_code,
|
||||||
diskUsage: parseFloat(dbRouter.disk_usage),
|
diskUsage: parseFloat(dbRouter.disk_usage),
|
||||||
freeDisk: parseInt(dbRouter.free_disk),
|
freeDisk: parseInt(dbRouter.free_disk),
|
||||||
@ -168,8 +193,10 @@ private async getRouterContainers(routerId: number): Promise<Container[]> {
|
|||||||
studies
|
studies
|
||||||
},
|
},
|
||||||
systemStatus: {
|
systemStatus: {
|
||||||
vpnStatus: dbRouter.vpn_status_code,
|
vpnStatus: vpnStatus,
|
||||||
appStatus: dbRouter.app_status_code,
|
appStatus: appStatus,
|
||||||
|
vmStatus: vmStatus,
|
||||||
|
routerStatus: routerStatus,
|
||||||
vms,
|
vms,
|
||||||
containers
|
containers
|
||||||
}
|
}
|
||||||
@ -233,14 +260,17 @@ private async getRouterContainers(routerId: number): Promise<Container[]> {
|
|||||||
async create(router: Partial<RouterData>): Promise<RouterData> {
|
async create(router: Partial<RouterData>): Promise<RouterData> {
|
||||||
const [result] = await pool.query<ResultSetHeader>(
|
const [result] = await pool.query<ResultSetHeader>(
|
||||||
`INSERT INTO routers (
|
`INSERT INTO routers (
|
||||||
router_id, facility, router_alias, last_seen,
|
router_id, facility, router_alias, facility_aet, openvpn_ip, router_vm_primary_ip,
|
||||||
vpn_status_code, disk_status_code, app_status_code,
|
last_seen, vpn_status_code, disk_status_code, app_status_code,
|
||||||
license_status, free_disk, total_disk, disk_usage
|
license_status, free_disk, total_disk, disk_usage
|
||||||
) VALUES (?, ?, ?, NOW(), ?, ?, ?, 'inactive', ?, ?, ?)`,
|
) VALUES (?, ?, ?, ?, ?, ?, NOW(), ?, ?, ?, 'inactive', ?, ?, ?)`,
|
||||||
[
|
[
|
||||||
router.routerId,
|
router.routerId,
|
||||||
router.facility,
|
router.facility,
|
||||||
router.routerAlias,
|
router.routerAlias,
|
||||||
|
router.facilityAET,
|
||||||
|
router.openvpnIp,
|
||||||
|
router.routerVmPrimaryIp,
|
||||||
router.systemStatus?.vpnStatus || 'unknown',
|
router.systemStatus?.vpnStatus || 'unknown',
|
||||||
router.diskStatus || 'unknown',
|
router.diskStatus || 'unknown',
|
||||||
router.systemStatus?.appStatus || 'unknown',
|
router.systemStatus?.appStatus || 'unknown',
|
||||||
@ -259,6 +289,9 @@ private async getRouterContainers(routerId: number): Promise<Container[]> {
|
|||||||
if (router.routerId) updates.router_id = router.routerId;
|
if (router.routerId) updates.router_id = router.routerId;
|
||||||
if (router.facility) updates.facility = router.facility;
|
if (router.facility) updates.facility = router.facility;
|
||||||
if (router.routerAlias) updates.router_alias = router.routerAlias;
|
if (router.routerAlias) updates.router_alias = router.routerAlias;
|
||||||
|
if (router.facilityAET) updates.facility_aet = router.facilityAET;
|
||||||
|
if (router.openvpnIp) updates.openvpn_ip = router.openvpnIp;
|
||||||
|
if (router.routerVmPrimaryIp) updates.router_vm_primary_ip = router.routerVmPrimaryIp;
|
||||||
if (router.diskStatus) updates.disk_status_code = router.diskStatus;
|
if (router.diskStatus) updates.disk_status_code = router.diskStatus;
|
||||||
|
|
||||||
if (router.systemStatus?.vpnStatus) updates.vpn_status_code = router.systemStatus?.vpnStatus;
|
if (router.systemStatus?.vpnStatus) updates.vpn_status_code = router.systemStatus?.vpnStatus;
|
||||||
|
|||||||
@ -46,7 +46,7 @@ export class DicomStudyService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commented, currently this field is inserted with active/idle
|
// Commented below, currently this field is inserted with active/idle
|
||||||
// Validate status code
|
// Validate status code
|
||||||
//const isValidStatus = await this.isValidStatusCode(studyData.study_status_code);
|
//const isValidStatus = await this.isValidStatusCode(studyData.study_status_code);
|
||||||
//if (!isValidStatus) {
|
//if (!isValidStatus) {
|
||||||
|
|||||||
@ -1,21 +1,26 @@
|
|||||||
// src/types/index.ts
|
// src/types/index.ts
|
||||||
export interface RouterData {
|
export interface RouterData {
|
||||||
id: number; // maps to backend 'id'
|
id: number; // maps to backend 'id'
|
||||||
slNo: number; // maps to backend 'slNo'
|
slNo: number; // maps to backend 'slNo'
|
||||||
routerId: string; // maps to backend 'router_id'
|
routerId: string; // maps to backend 'router_id'
|
||||||
facility: string; // maps to backend 'facility'
|
facility: string; // maps to backend 'facility'
|
||||||
routerAlias: string; // maps to backend 'router_alias'
|
routerAlias: string; // maps to backend 'router_alias'
|
||||||
lastSeen: string; // maps to backend 'last_seen'
|
facilityAET: string; // maps to backend 'facility_aet'
|
||||||
diskStatus: string; // maps to backend 'disk_status_code'
|
openvpnIp: string; // maps to backend 'openvpn_ip'
|
||||||
diskUsage: number; // maps to backend 'disk_usage'
|
routerVmPrimaryIp: string; // maps to backend 'router_vm_primary_ip'
|
||||||
freeDisk: number; // maps to backend 'free_disk'
|
lastSeen: string; // maps to backend 'last_seen'
|
||||||
totalDisk: number; // maps to backend 'total_disk'
|
diskStatus: string; // maps to backend 'disk_status_code'
|
||||||
|
diskUsage: number; // maps to backend 'disk_usage'
|
||||||
|
freeDisk: number; // maps to backend 'free_disk'
|
||||||
|
totalDisk: number; // maps to backend 'total_disk'
|
||||||
routerActivity: {
|
routerActivity: {
|
||||||
studies: Study[];
|
studies: Study[];
|
||||||
};
|
};
|
||||||
systemStatus: {
|
systemStatus: {
|
||||||
vpnStatus: string; // maps to backend 'vpn_status_code'
|
vpnStatus: string; // maps to backend 'vpn_status_code'
|
||||||
appStatus: string; // maps to backend 'app_status_code'
|
appStatus: string; // maps to backend 'app_status_code'
|
||||||
|
vmStatus: string; // router machine status
|
||||||
|
routerStatus: string; // overall operational status of the router
|
||||||
vms: VM[];
|
vms: VM[];
|
||||||
containers: Container[];
|
containers: Container[];
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user