CalejoControl/src/dashboard/templates.py

668 lines
29 KiB
Python
Raw Normal View History

"""
Dashboard HTML templates for Calejo Control Adapter
"""
DASHBOARD_HTML = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calejo Control Adapter - Dashboard</title>
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.header {
text-align: center;
margin-bottom: 30px;
border-bottom: 2px solid #007acc;
padding-bottom: 10px;
}
.status-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 30px;
}
.status-card {
padding: 15px;
border-radius: 6px;
text-align: center;
background: #f8f9fa;
border-left: 4px solid #007acc;
}
.status-card.running { border-left-color: #28a745; }
.status-card.error { border-left-color: #dc3545; }
.status-card.warning { border-left-color: #ffc107; }
.config-section {
margin-bottom: 30px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 6px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input, select {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
button {
background: #007acc;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
font-weight: bold;
}
button:hover {
background: #005a9e;
}
.alert {
padding: 10px;
border-radius: 4px;
margin-bottom: 15px;
}
.alert.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.alert.warning {
background: #fff3cd;
color: #856404;
border: 1px solid #ffeaa7;
}
.alert.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.tab-container {
margin-bottom: 20px;
}
.tab-buttons {
display: flex;
border-bottom: 1px solid #ddd;
}
.tab-button {
padding: 10px 20px;
background: #f8f9fa;
border: 1px solid #ddd;
border-bottom: none;
cursor: pointer;
border-bottom: 3px solid transparent;
color: #333;
margin-right: 2px;
border-radius: 4px 4px 0 0;
font-weight: bold;
}
.tab-button.active {
border-bottom-color: #007acc;
font-weight: bold;
background: white;
border-color: #ddd;
border-bottom-color: white;
}
.tab-button:hover {
background: #e9ecef;
}
.tab-content {
display: none;
padding: 20px 0;
}
.tab-content.active {
display: block;
}
.action-buttons {
margin-top: 20px;
text-align: center;
}
/* Protocol Selector Styles */
.protocol-selector {
display: flex;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.protocol-btn {
padding: 8px 16px;
background: #f8f9fa;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
font-weight: normal;
}
.protocol-btn.active {
background: #007acc;
color: white;
border-color: #007acc;
font-weight: bold;
}
.protocol-btn:hover {
background: #e9ecef;
}
.protocol-btn.active:hover {
background: #005a9e;
}
/* Modal Styles */
.modal {
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
}
.modal-content {
background-color: white;
margin: 10% auto;
padding: 20px;
border-radius: 8px;
width: 80%;
max-width: 600px;
position: relative;
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover {
color: black;
}
.logs-container {
max-height: 400px;
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
background: #f8f9fa;
}
.log-entry {
padding: 5px;
border-bottom: 1px solid #eee;
font-family: monospace;
font-size: 12px;
}
.log-entry.error {
color: #dc3545;
}
.log-entry.warning {
color: #856404;
}
.log-entry.info {
color: #007acc;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Calejo Control Adapter Dashboard</h1>
<p>Configuration and Monitoring Interface</p>
</div>
<div class="tab-container">
<div class="tab-buttons">
<button class="tab-button active" onclick="showTab('status')">Status</button>
<button class="tab-button" onclick="showTab('config')">Configuration</button>
<button class="tab-button" onclick="showTab('scada')">SCADA/Hardware</button>
<button class="tab-button" onclick="showTab('signals')">Signal Overview</button>
<button class="tab-button" onclick="showTab('protocol-mapping')">Protocol Mapping</button>
<button class="tab-button" onclick="showTab('logs')">Logs</button>
<button class="tab-button" onclick="showTab('actions')">Actions</button>
</div>
<!-- Status Tab -->
<div id="status-tab" class="tab-content active">
<h2>System Status</h2>
<div class="status-grid" id="status-grid">
<!-- Status cards will be populated by JavaScript -->
</div>
<div class="action-buttons">
<button onclick="refreshStatus()">Refresh Status</button>
</div>
</div>
<!-- Configuration Tab -->
<div id="config-tab" class="tab-content">
<h2>Configuration</h2>
<div id="alerts"></div>
<form id="config-form">
<div class="config-section">
<h3>Database Configuration</h3>
<div class="form-group">
<label for="db_host">Host:</label>
<input type="text" id="db_host" name="db_host" required>
</div>
<div class="form-group">
<label for="db_port">Port:</label>
<input type="number" id="db_port" name="db_port" min="1" max="65535" required>
</div>
<div class="form-group">
<label for="db_name">Database Name:</label>
<input type="text" id="db_name" name="db_name" required>
</div>
<div class="form-group">
<label for="db_user">Username:</label>
<input type="text" id="db_user" name="db_user" required>
</div>
<div class="form-group">
<label for="db_password">Password:</label>
<input type="password" id="db_password" name="db_password">
</div>
</div>
<div class="config-section">
<h3>Protocol Configuration</h3>
<div class="form-group">
<label>
<input type="checkbox" id="opcua_enabled" name="opcua_enabled">
Enable OPC UA Server
</label>
</div>
<div class="form-group">
<label for="opcua_port">OPC UA Port:</label>
<input type="number" id="opcua_port" name="opcua_port" min="1" max="65535">
</div>
<div class="form-group">
<label>
<input type="checkbox" id="modbus_enabled" name="modbus_enabled">
Enable Modbus Server
</label>
</div>
<div class="form-group">
<label for="modbus_port">Modbus Port:</label>
<input type="number" id="modbus_port" name="modbus_port" min="1" max="65535">
</div>
</div>
<div class="config-section">
<h3>REST API Configuration</h3>
<div class="form-group">
<label for="rest_api_host">Host:</label>
<input type="text" id="rest_api_host" name="rest_api_host">
</div>
<div class="form-group">
<label for="rest_api_port">Port:</label>
<input type="number" id="rest_api_port" name="rest_api_port" min="1" max="65535">
</div>
<div class="form-group">
<label>
<input type="checkbox" id="rest_api_cors_enabled" name="rest_api_cors_enabled">
Enable CORS
</label>
</div>
</div>
<div class="config-section">
<h3>Monitoring Configuration</h3>
<div class="form-group">
<label for="health_monitor_port">Health Monitor Port:</label>
<input type="number" id="health_monitor_port" name="health_monitor_port" min="1" max="65535">
</div>
</div>
<div class="action-buttons">
<button type="button" onclick="loadConfiguration()">Load Current</button>
<button type="button" onclick="saveConfiguration()">Save Configuration</button>
<button type="button" onclick="validateConfiguration()">Validate</button>
</div>
</form>
</div>
<!-- SCADA/Hardware Tab -->
<div id="scada-tab" class="tab-content">
<h2>SCADA/Hardware Configuration</h2>
<div id="scada-alerts"></div>
<div class="config-section">
<h3>Modbus TCP Configuration</h3>
<div class="form-group">
<label for="modbus_enabled_scada">
<input type="checkbox" id="modbus_enabled_scada" name="modbus_enabled_scada">
Enable Modbus TCP Server
</label>
</div>
<div class="form-group">
<label for="modbus_port_scada">Modbus Port:</label>
<input type="number" id="modbus_port_scada" name="modbus_port_scada" min="1" max="65535" value="502">
</div>
<div class="form-group">
<label for="modbus_slave_id">Slave ID:</label>
<input type="number" id="modbus_slave_id" name="modbus_slave_id" min="1" max="247" value="1">
</div>
<div class="form-group">
<label for="modbus_baud_rate">Baud Rate:</label>
<select id="modbus_baud_rate" name="modbus_baud_rate">
<option value="9600">9600</option>
<option value="19200">19200</option>
<option value="38400">38400</option>
<option value="57600">57600</option>
<option value="115200" selected>115200</option>
</select>
</div>
</div>
<div class="config-section">
<h3>OPC UA Configuration</h3>
<div class="form-group">
<label for="opcua_enabled_scada">
<input type="checkbox" id="opcua_enabled_scada" name="opcua_enabled_scada">
Enable OPC UA Server
</label>
</div>
<div class="form-group">
<label for="opcua_port_scada">OPC UA Port:</label>
<input type="number" id="opcua_port_scada" name="opcua_port_scada" min="1" max="65535" value="4840">
</div>
<div class="form-group">
<label for="opcua_security_mode">Security Mode:</label>
<select id="opcua_security_mode" name="opcua_security_mode">
<option value="None">None</option>
<option value="Sign">Sign</option>
<option value="SignAndEncrypt" selected>Sign and Encrypt</option>
</select>
</div>
</div>
<div class="config-section">
<h3>Device Mapping</h3>
<div class="form-group">
<label for="device_mapping">Device Address Mapping:</label>
<textarea id="device_mapping" name="device_mapping" rows="8" placeholder="Device ID,Address,Type,Description
1,40001,Holding Register,Temperature Sensor
2,40002,Holding Register,Pressure Sensor
3,10001,Coil,Relay Output
4,10002,Coil,Valve Control"></textarea>
</div>
</div>
<div class="config-section">
<h3>Current SCADA Status</h3>
<div class="status-grid" id="scada-status-grid">
<!-- SCADA status will be populated by JavaScript -->
</div>
</div>
<div class="action-buttons">
<button type="button" onclick="loadSCADAConfig()">Load Current</button>
<button type="button" onclick="saveSCADAConfig()">Save Configuration</button>
<button type="button" onclick="testSCADAConnection()">Test Connection</button>
</div>
</div>
<!-- Signal Overview Tab -->
<div id="signals-tab" class="tab-content">
<h2>Signal Overview</h2>
<div id="signals-alerts"></div>
<div class="config-section">
<h3>Active Signals</h3>
<div class="action-buttons">
<button onclick="refreshSignals()">Refresh Signals</button>
<button onclick="exportSignals()">Export to CSV</button>
</div>
<div style="margin-top: 20px;">
<table style="width: 100%; border-collapse: collapse;" id="signals-table">
<thead>
<tr style="background: #f8f9fa;">
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Signal Name</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Protocol</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Address/Node</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Data Type</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Current Value</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Quality</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Timestamp</th>
</tr>
</thead>
<tbody id="signals-body">
<!-- Signals will be populated by JavaScript -->
</tbody>
</table>
</div>
</div>
<div class="config-section">
<h3>Protocol Statistics</h3>
<div class="status-grid" id="protocol-stats-grid">
<!-- Protocol statistics will be populated by JavaScript -->
</div>
</div>
<div class="config-section">
<h3>Signal Configuration</h3>
<div class="form-group">
<label for="signal_filter">Filter Signals:</label>
<input type="text" id="signal_filter" placeholder="Filter by name, protocol, or address..." style="width: 300px;">
</div>
<div class="form-group">
<label for="protocol_filter">Protocol:</label>
<select id="protocol_filter">
<option value="">All Protocols</option>
<option value="modbus">Modbus</option>
<option value="opcua">OPC UA</option>
<option value="profinet">Profinet</option>
<option value="rest">REST API</option>
</select>
</div>
</div>
</div>
<!-- Logs Tab -->
<div id="logs-tab" class="tab-content">
<h2>System Logs</h2>
<div class="logs-container" id="logs-container">
<!-- Logs will be populated by JavaScript -->
</div>
<div class="action-buttons">
<button onclick="loadLogs()">Refresh Logs</button>
</div>
</div>
<!-- Protocol Mapping Tab -->
<div id="protocol-mapping-tab" class="tab-content">
<h2>Protocol Mapping Configuration</h2>
<div id="protocol-mapping-alerts"></div>
<!-- Protocol Selector -->
<div class="config-section">
<h3>Protocol Selection</h3>
<div class="protocol-selector">
<button class="protocol-btn active" onclick="selectProtocol('all')">All Protocols</button>
<button class="protocol-btn" onclick="selectProtocol('modbus_tcp')">Modbus TCP</button>
<button class="protocol-btn" onclick="selectProtocol('opcua')">OPC UA</button>
<button class="protocol-btn" onclick="selectProtocol('modbus_rtu')">Modbus RTU</button>
<button class="protocol-btn" onclick="selectProtocol('rest_api')">REST API</button>
</div>
</div>
<!-- Protocol Discovery -->
<div class="config-section">
<h3>Protocol Discovery</h3>
<div id="discovery-notifications"></div>
<div class="discovery-controls">
<div class="action-buttons">
<button id="start-discovery-scan" class="btn-primary">
<i class="fas fa-search"></i> Start Discovery Scan
</button>
<button id="stop-discovery-scan" class="btn-secondary" disabled>
<i class="fas fa-stop"></i> Stop Scan
</button>
<button id="refresh-discovery-status" class="btn-outline">
<i class="fas fa-sync"></i> Refresh Status
</button>
</div>
<div id="discovery-status" style="margin-top: 15px;">
<div class="alert alert-info">
<i class="fas fa-info-circle"></i>
Discovery service ready
</div>
</div>
</div>
<div id="discovery-results" style="margin-top: 20px;">
<!-- Discovery results will be populated here -->
</div>
</div>
<!-- Mapping Grid -->
<div class="config-section">
<h3>Protocol Mappings</h3>
<div class="action-buttons">
<button onclick="loadProtocolMappings()">Refresh Mappings</button>
<button onclick="showAddMappingModal()" style="background: #28a745;">Add New Mapping</button>
<button onclick="exportProtocolMappings()">Export to CSV</button>
</div>
<div style="margin-top: 20px;">
<table style="width: 100%; border-collapse: collapse;" id="protocol-mappings-table">
<thead>
<tr style="background: #f8f9fa;">
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">ID</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Protocol</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Station</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Pump</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Data Type</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Protocol Address</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Database Source</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Actions</th>
</tr>
</thead>
<tbody id="protocol-mappings-body">
<!-- Protocol mappings will be populated by JavaScript -->
</tbody>
</table>
</div>
</div>
<!-- Add/Edit Mapping Modal -->
<div id="mapping-modal" class="modal" style="display: none;">
<div class="modal-content">
<span class="close" onclick="closeMappingModal()">&times;</span>
<h3 id="modal-title">Add Protocol Mapping</h3>
<form id="mapping-form">
<div class="form-group">
<label for="mapping_id">Mapping ID:</label>
<input type="text" id="mapping_id" name="mapping_id" required>
</div>
<div class="form-group">
<label for="protocol_type">Protocol Type:</label>
<select id="protocol_type" name="protocol_type" required onchange="updateProtocolFields()">
<option value="">Select Protocol</option>
<option value="modbus_tcp">Modbus TCP</option>
<option value="opcua">OPC UA</option>
<option value="modbus_rtu">Modbus RTU</option>
<option value="rest_api">REST API</option>
</select>
</div>
<div class="form-group">
<label for="station_id">Station ID:</label>
<input type="text" id="station_id" name="station_id" required>
</div>
<div class="form-group">
<label for="pump_id">Pump ID:</label>
<input type="text" id="pump_id" name="pump_id" required>
</div>
<div class="form-group">
<label for="data_type">Data Type:</label>
<select id="data_type" name="data_type" required>
<option value="">Select Data Type</option>
<option value="setpoint">Setpoint</option>
<option value="actual_speed">Actual Speed</option>
<option value="status">Status</option>
<option value="power">Power</option>
<option value="flow">Flow</option>
<option value="level">Level</option>
<option value="safety">Safety</option>
</select>
</div>
<div class="form-group">
<label for="protocol_address">Protocol Address:</label>
<input type="text" id="protocol_address" name="protocol_address" required>
<small id="protocol_address_help" style="color: #666;"></small>
</div>
<div class="form-group">
<label for="db_source">Database Source:</label>
<input type="text" id="db_source" name="db_source" required placeholder="table.column">
</div>
<div class="action-buttons">
<button type="button" onclick="validateMapping()">Validate</button>
<button type="submit" style="background: #28a745;">Save Mapping</button>
<button type="button" onclick="closeMappingModal()" style="background: #dc3545;">Cancel</button>
</div>
</form>
</div>
</div>
</div>
<!-- Actions Tab -->
<div id="actions-tab" class="tab-content">
<h2>System Actions</h2>
<div class="config-section">
<h3>System Operations</h3>
<div class="action-buttons">
<button onclick="restartSystem()" style="background: #dc3545;">Restart System</button>
<button onclick="createBackup()" style="background: #28a745;">Create Backup</button>
</div>
</div>
<div class="config-section">
<h3>Health Checks</h3>
<div class="action-buttons">
<button onclick="runHealthCheck()">Run Health Check</button>
<button onclick="viewMetrics()">View Metrics</button>
</div>
</div>
</div>
</div>
</div>
<script src="/static/dashboard.js"></script>
<script src="/static/protocol_mapping.js"></script>
<script src="/static/discovery.js"></script>
</body>
</html>
"""