🐛 Update: Added support for the 'find' command in settings.local.json. Enhanced logging for various modules, including initialization and performance metrics. Improved SQLite database optimization and ensured better tracking of user interactions and system processes. 📚
This commit is contained in:
471
network-visualization/script.js
Normal file
471
network-visualization/script.js
Normal file
@@ -0,0 +1,471 @@
|
||||
/**
|
||||
* MYP Professional Network Diagram - Interactive Script
|
||||
* Mercedes-Benz 3D-Druck-Management-System
|
||||
*/
|
||||
|
||||
class MYPNetworkDiagram {
|
||||
constructor() {
|
||||
this.nodes = document.querySelectorAll('.node');
|
||||
this.connections = document.querySelectorAll('.connection');
|
||||
this.isInteractive = true;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.setupNodeInteractions();
|
||||
this.setupConnectionHighlighting();
|
||||
this.logSystemInfo();
|
||||
|
||||
// Add keyboard shortcuts
|
||||
this.setupKeyboardControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup interactive node behaviors
|
||||
*/
|
||||
setupNodeInteractions() {
|
||||
this.nodes.forEach(node => {
|
||||
// Mouse enter - highlight connections
|
||||
node.addEventListener('mouseenter', (e) => {
|
||||
if (!this.isInteractive) return;
|
||||
this.highlightNodeConnections(e.target);
|
||||
});
|
||||
|
||||
// Mouse leave - reset highlights
|
||||
node.addEventListener('mouseleave', () => {
|
||||
if (!this.isInteractive) return;
|
||||
this.resetHighlights();
|
||||
});
|
||||
|
||||
// Click - show node details
|
||||
node.addEventListener('click', (e) => {
|
||||
this.showNodeDetails(e.target);
|
||||
});
|
||||
|
||||
// Make nodes keyboard accessible
|
||||
node.setAttribute('tabindex', '0');
|
||||
node.setAttribute('role', 'button');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight connections related to the active node
|
||||
*/
|
||||
highlightNodeConnections(activeNode) {
|
||||
const nodeId = activeNode.id;
|
||||
const nodeType = this.getNodeType(activeNode);
|
||||
|
||||
// Get connected node IDs
|
||||
const connections = this.getNodeConnections(nodeId, nodeType);
|
||||
|
||||
// Dim all nodes first
|
||||
this.nodes.forEach(node => {
|
||||
if (node !== activeNode && !connections.includes(node.id)) {
|
||||
node.style.opacity = '0.3';
|
||||
node.style.filter = 'blur(1px)';
|
||||
}
|
||||
});
|
||||
|
||||
// Highlight connected nodes
|
||||
connections.forEach(connectedId => {
|
||||
const connectedNode = document.getElementById(connectedId);
|
||||
if (connectedNode) {
|
||||
connectedNode.style.opacity = '1';
|
||||
connectedNode.style.filter = 'none';
|
||||
connectedNode.style.transform = 'translateY(-4px) scale(1.02)';
|
||||
}
|
||||
});
|
||||
|
||||
// Highlight relevant connections
|
||||
this.highlightConnections(nodeId, connections);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all visual highlights
|
||||
*/
|
||||
resetHighlights() {
|
||||
this.nodes.forEach(node => {
|
||||
node.style.opacity = '';
|
||||
node.style.filter = '';
|
||||
node.style.transform = '';
|
||||
});
|
||||
|
||||
this.connections.forEach(conn => {
|
||||
conn.style.opacity = '';
|
||||
conn.style.strokeWidth = '';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight specific connections
|
||||
*/
|
||||
highlightConnections(nodeId, connectedIds) {
|
||||
this.connections.forEach(conn => {
|
||||
conn.style.opacity = '0.2';
|
||||
});
|
||||
|
||||
// This would need more sophisticated logic to match
|
||||
// connections to specific nodes based on coordinates
|
||||
// For now, we'll use a simplified approach
|
||||
}
|
||||
|
||||
/**
|
||||
* Get node type from CSS classes
|
||||
*/
|
||||
getNodeType(node) {
|
||||
if (node.classList.contains('frontend-node')) return 'frontend';
|
||||
if (node.classList.contains('backend-node')) return 'backend';
|
||||
if (node.classList.contains('smartplug-node')) return 'smartplug';
|
||||
if (node.classList.contains('printer-node')) return 'printer';
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get connected node IDs for a given node
|
||||
*/
|
||||
getNodeConnections(nodeId, nodeType) {
|
||||
const connectionMap = {
|
||||
// Frontend connections
|
||||
'kiosk': ['webapp', 'server'],
|
||||
'webapp': ['kiosk', 'auth', 'flask'],
|
||||
'auth': ['webapp', 'security'],
|
||||
|
||||
// Backend connections
|
||||
'server': ['kiosk', 'flask'],
|
||||
'flask': ['webapp', 'server', 'database'],
|
||||
'database': ['flask', 'scheduler'],
|
||||
'scheduler': ['database', 'security', 'plug1', 'plug2', 'plug3', 'plug4', 'plug6'],
|
||||
'security': ['auth', 'scheduler', 'monitor'],
|
||||
'monitor': ['security', 'plug6', 'printer5'],
|
||||
|
||||
// Smart plug connections
|
||||
'plug1': ['scheduler', 'printer1'],
|
||||
'plug2': ['scheduler', 'printer2'],
|
||||
'plug3': ['scheduler', 'printer3'],
|
||||
'plug4': ['scheduler', 'printer4'],
|
||||
'plug6': ['scheduler', 'printer5', 'monitor'],
|
||||
|
||||
// Printer connections
|
||||
'printer1': ['plug1'],
|
||||
'printer2': ['plug2'],
|
||||
'printer3': ['plug3'],
|
||||
'printer4': ['plug4'],
|
||||
'printer5': ['plug6', 'monitor']
|
||||
};
|
||||
|
||||
return connectionMap[nodeId] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Show detailed information about a node
|
||||
*/
|
||||
showNodeDetails(node) {
|
||||
const nodeLabel = node.querySelector('.node-label').textContent;
|
||||
const nodeDetail = node.querySelector('.node-detail').textContent;
|
||||
const nodeType = this.getNodeType(node);
|
||||
|
||||
const details = this.getNodeDetailedInfo(node.id, nodeType);
|
||||
|
||||
console.log(`🔧 MYP Node: ${nodeLabel}`);
|
||||
console.log(`📋 Details: ${nodeDetail}`);
|
||||
console.log(`🔗 Type: ${nodeType}`);
|
||||
console.log(`📊 Info:`, details);
|
||||
|
||||
// Visual feedback
|
||||
node.style.transform = 'scale(0.95)';
|
||||
setTimeout(() => {
|
||||
node.style.transform = '';
|
||||
}, 150);
|
||||
|
||||
// Could show a modal or tooltip here
|
||||
this.showTooltip(node, details);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get detailed information for a node
|
||||
*/
|
||||
getNodeDetailedInfo(nodeId, nodeType) {
|
||||
const detailsMap = {
|
||||
'kiosk': {
|
||||
description: 'Mercedes-Benz Kiosk Terminal im TBA Marienfelde',
|
||||
specs: ['Touch-Interface', 'HTTPS-only', 'Corporate Design'],
|
||||
status: 'Online'
|
||||
},
|
||||
'webapp': {
|
||||
description: 'Next.js Progressive Web App mit Flask Backend',
|
||||
specs: ['React/Next.js', 'PWA Features', 'Responsive Design'],
|
||||
status: 'Active'
|
||||
},
|
||||
'auth': {
|
||||
description: 'Authentifizierungssystem mit bcrypt und OTP',
|
||||
specs: ['bcrypt Hashing', 'OTP Guest Access', 'Session Management'],
|
||||
status: 'Secure'
|
||||
},
|
||||
'server': {
|
||||
description: 'Raspberry Pi 4B Production Server',
|
||||
specs: ['ARM Cortex-A72', '8GB RAM', 'Debian OS'],
|
||||
status: 'Online - 192.168.0.100'
|
||||
},
|
||||
'flask': {
|
||||
description: 'Flask Backend mit 15+ Blueprint Modulen',
|
||||
specs: ['Python Flask', 'SQLAlchemy ORM', 'REST API'],
|
||||
status: 'Running'
|
||||
},
|
||||
'database': {
|
||||
description: 'SQLite WAL Database mit Thread-Pool',
|
||||
specs: ['WAL Mode', 'Thread-Safe', 'Auto-Backup'],
|
||||
status: 'Synchronized'
|
||||
},
|
||||
'scheduler': {
|
||||
description: 'APScheduler Job Queue System',
|
||||
specs: ['Background Jobs', 'Cron Tasks', 'Queue Management'],
|
||||
status: 'Active'
|
||||
},
|
||||
'security': {
|
||||
description: 'Security Suite mit SSL/TLS Management',
|
||||
specs: ['SSL/TLS', 'Audit Logging', 'CSRF Protection'],
|
||||
status: 'Protected'
|
||||
},
|
||||
'monitor': {
|
||||
description: 'System Monitoring & Analytics',
|
||||
specs: ['Performance Tracking', 'Error Logging', 'Health Checks'],
|
||||
status: 'Monitoring'
|
||||
}
|
||||
};
|
||||
|
||||
// Smart Plugs
|
||||
if (nodeId.startsWith('plug')) {
|
||||
const plugNumber = nodeId.replace('plug', '');
|
||||
return {
|
||||
description: `TP-Link Tapo P110 Smart Plug #${plugNumber}`,
|
||||
specs: ['Energy Monitoring', '230V AC Control', 'Remote Management'],
|
||||
status: `Online - 192.168.0.10${plugNumber}`
|
||||
};
|
||||
}
|
||||
|
||||
// Printers
|
||||
if (nodeId.startsWith('printer')) {
|
||||
const printerNumber = nodeId.replace('printer', '');
|
||||
const printerModels = {
|
||||
'1': 'Prusa MK3S+',
|
||||
'2': 'Ender 3 Pro',
|
||||
'3': 'Bambu Lab A1',
|
||||
'4': 'Prusa MINI+',
|
||||
'5': 'Artillery X1'
|
||||
};
|
||||
return {
|
||||
description: `3D-Drucker Arbeitsplatz ${printerNumber}`,
|
||||
specs: [printerModels[printerNumber], 'Smart-Plug Controlled', 'Job Queue Ready'],
|
||||
status: 'Ready for Production'
|
||||
};
|
||||
}
|
||||
|
||||
return detailsMap[nodeId] || {
|
||||
description: 'MYP System Component',
|
||||
specs: ['Network Connected', 'Monitored'],
|
||||
status: 'Online'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Show tooltip with node information
|
||||
*/
|
||||
showTooltip(node, details) {
|
||||
// Remove existing tooltip
|
||||
const existingTooltip = document.querySelector('.node-tooltip');
|
||||
if (existingTooltip) {
|
||||
existingTooltip.remove();
|
||||
}
|
||||
|
||||
const tooltip = document.createElement('div');
|
||||
tooltip.className = 'node-tooltip';
|
||||
tooltip.innerHTML = `
|
||||
<div class="tooltip-header">${details.description}</div>
|
||||
<div class="tooltip-specs">
|
||||
${details.specs.map(spec => `<div class="tooltip-spec">• ${spec}</div>`).join('')}
|
||||
</div>
|
||||
<div class="tooltip-status">Status: ${details.status}</div>
|
||||
`;
|
||||
|
||||
// Style the tooltip
|
||||
tooltip.style.cssText = `
|
||||
position: absolute;
|
||||
background: rgba(0, 0, 0, 0.95);
|
||||
color: white;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
font-size: 0.8rem;
|
||||
max-width: 250px;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
||||
`;
|
||||
|
||||
// Position tooltip
|
||||
const rect = node.getBoundingClientRect();
|
||||
tooltip.style.left = (rect.left + rect.width + 10) + 'px';
|
||||
tooltip.style.top = rect.top + 'px';
|
||||
|
||||
document.body.appendChild(tooltip);
|
||||
|
||||
// Auto-remove after 3 seconds
|
||||
setTimeout(() => {
|
||||
tooltip.remove();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup connection highlighting on hover
|
||||
*/
|
||||
setupConnectionHighlighting() {
|
||||
this.connections.forEach(conn => {
|
||||
conn.addEventListener('mouseenter', () => {
|
||||
if (!this.isInteractive) return;
|
||||
conn.style.strokeWidth = '4';
|
||||
conn.style.opacity = '1';
|
||||
});
|
||||
|
||||
conn.addEventListener('mouseleave', () => {
|
||||
if (!this.isInteractive) return;
|
||||
conn.style.strokeWidth = '';
|
||||
conn.style.opacity = '';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup keyboard controls
|
||||
*/
|
||||
setupKeyboardControls() {
|
||||
document.addEventListener('keydown', (e) => {
|
||||
switch(e.key) {
|
||||
case 'Escape':
|
||||
this.resetHighlights();
|
||||
break;
|
||||
case 'i':
|
||||
case 'I':
|
||||
this.toggleInteractivity();
|
||||
break;
|
||||
case 'r':
|
||||
case 'R':
|
||||
this.resetDiagram();
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle interactivity mode
|
||||
*/
|
||||
toggleInteractivity() {
|
||||
this.isInteractive = !this.isInteractive;
|
||||
console.log(`🎮 Interactivity ${this.isInteractive ? 'enabled' : 'disabled'}`);
|
||||
|
||||
if (!this.isInteractive) {
|
||||
this.resetHighlights();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset diagram to initial state
|
||||
*/
|
||||
resetDiagram() {
|
||||
this.resetHighlights();
|
||||
|
||||
// Remove any tooltips
|
||||
document.querySelectorAll('.node-tooltip').forEach(tooltip => {
|
||||
tooltip.remove();
|
||||
});
|
||||
|
||||
console.log('🔄 Diagram reset');
|
||||
}
|
||||
|
||||
/**
|
||||
* Log system information
|
||||
*/
|
||||
logSystemInfo() {
|
||||
console.log('🚀 MYP Professional Network Diagram loaded');
|
||||
console.log('📊 System Components:', this.nodes.length);
|
||||
console.log('🔗 Connections:', this.connections.length);
|
||||
console.log('🏭 Location: Mercedes-Benz TBA Marienfelde');
|
||||
console.log('🖥️ Server: Raspberry Pi 4B (192.168.0.100)');
|
||||
console.log('🔌 Smart Plugs: 5x Tapo P110 (192.168.0.101-104, 106)');
|
||||
console.log('🖨️ 3D Printers: 5 Arbeitsplätze');
|
||||
console.log('⌨️ Keyboard: [I] Toggle Interactivity, [R] Reset, [ESC] Clear');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class for diagram export and screenshot optimization
|
||||
*/
|
||||
class DiagramExport {
|
||||
static enableScreenshotMode() {
|
||||
document.body.classList.add('screenshot-mode');
|
||||
|
||||
const style = document.createElement('style');
|
||||
style.id = 'screenshot-styles';
|
||||
style.textContent = `
|
||||
.screenshot-mode .node {
|
||||
animation: none !important;
|
||||
}
|
||||
.screenshot-mode .node:hover {
|
||||
transform: none !important;
|
||||
box-shadow: inherit !important;
|
||||
}
|
||||
.screenshot-mode .connection {
|
||||
animation: none !important;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
console.log('📸 Screenshot mode enabled');
|
||||
}
|
||||
|
||||
static disableScreenshotMode() {
|
||||
document.body.classList.remove('screenshot-mode');
|
||||
const screenshotStyles = document.getElementById('screenshot-styles');
|
||||
if (screenshotStyles) {
|
||||
screenshotStyles.remove();
|
||||
}
|
||||
|
||||
console.log('🎮 Interactive mode restored');
|
||||
}
|
||||
|
||||
static printDiagram() {
|
||||
window.print();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize when DOM is ready
|
||||
*/
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Initialize the network diagram
|
||||
const networkDiagram = new MYPNetworkDiagram();
|
||||
|
||||
// Make utilities globally available
|
||||
window.MYP = {
|
||||
diagram: networkDiagram,
|
||||
export: DiagramExport
|
||||
};
|
||||
|
||||
// Check URL parameters for special modes
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
|
||||
if (urlParams.get('screenshot') === 'true') {
|
||||
DiagramExport.enableScreenshotMode();
|
||||
}
|
||||
|
||||
if (urlParams.get('print') === 'true') {
|
||||
setTimeout(() => {
|
||||
DiagramExport.printDiagram();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
console.log('✅ MYP Professional Network Diagram initialized');
|
||||
console.log('🔧 Access via: window.MYP.diagram');
|
||||
console.log('📸 Screenshot mode: ?screenshot=true');
|
||||
});
|
Reference in New Issue
Block a user