/** * DNS Template Selector * Presents DNS server template options when user chooses to set up DNS */ (function(window) { 'use strict'; class DnsTemplateSelector { constructor(progressTracker) { this.progressTracker = progressTracker; this.modal = null; this.onTemplateSelected = null; console.log('[DnsTemplateSelector] Module loaded'); } /** * Get available DNS server templates from app templates * @returns {Array} Array of DNS template objects */ getDnsTemplates() { // In a real implementation, this would fetch from app-templates.js // For now, return hardcoded templates matching what we added return [ { id: 'technitium', name: 'Technitium DNS Server', description: 'Modern DNS server with web UI for managing private zones', icon: '🌐', difficulty: 'Easy', features: [ 'Web-based management interface', 'Private zone management for .sami domain', 'DHCP server integration', 'DNS-over-HTTPS and DNS-over-TLS support' ], recommended: true }, { id: 'bind9', name: 'BIND9 DNS Server', description: 'Industry-standard DNS server - powerful and flexible', icon: '🔧', difficulty: 'Advanced', features: [ 'Industry standard DNS server', 'Full RFC compliance', 'Advanced zone management', 'DNSSEC support' ], recommended: false }, { id: 'pihole', name: 'Pi-hole', description: 'Network-wide ad blocker with DNS capabilities', icon: '🛡️', difficulty: 'Intermediate', features: [ 'Ad blocking at DNS level', 'Web interface for management', 'DHCP server included', 'Query logging and statistics' ], recommended: false }, { id: 'powerdns', name: 'PowerDNS', description: 'High-performance DNS server with SQL backend', icon: '⚡', difficulty: 'Intermediate', features: [ 'SQL database backend', 'RESTful API for automation', 'Geographic load balancing', 'DNSSEC support' ], recommended: false }, { id: 'coredns', name: 'CoreDNS', description: 'Cloud-native DNS server - lightweight and flexible', icon: '☁️', difficulty: 'Intermediate', features: [ 'Plugin-based architecture', 'Kubernetes-native', 'Lightweight and fast', 'Prometheus metrics' ], recommended: false } ]; } /** * Show DNS template selection modal */ showTemplateSelector() { // Create modal if it doesn't exist if (!this.modal) { this.createModal(); } // Populate with templates this.populateTemplates(); // Show modal this.modal.style.display = 'flex'; document.body.style.overflow = 'hidden'; } /** * Create the modal HTML structure * @private */ createModal() { const modal = document.createElement('div'); modal.id = 'dns-template-modal'; modal.className = 'dns-template-modal'; modal.innerHTML = `

🌐 Choose a DNS Server

Setting up a DNS server is essential for managing your private .sami domain

`; document.body.appendChild(modal); this.modal = modal; // Add event listeners modal.querySelector('.dns-template-close').addEventListener('click', () => this.close()); modal.querySelector('#dns-setup-later').addEventListener('click', () => this.handleSetupLater()); // Close on overlay click modal.addEventListener('click', (e) => { if (e.target === modal) { this.close(); } }); // Close on Escape key document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && modal.style.display === 'flex') { this.close(); } }); } /** * Populate modal with DNS templates * @private */ populateTemplates() { const grid = document.getElementById('dns-template-grid'); if (!grid) return; const templates = this.getDnsTemplates(); grid.innerHTML = ''; templates.forEach(template => { const card = this.createTemplateCard(template); grid.appendChild(card); }); } /** * Create a template card element * @private */ createTemplateCard(template) { const card = document.createElement('div'); card.className = 'dns-template-card'; if (template.recommended) { card.classList.add('recommended'); } const difficultyClass = template.difficulty.toLowerCase(); card.innerHTML = ` ${template.recommended ? '' : ''}
${template.icon}

${template.name}

${template.description}

${template.difficulty}
`; // Add click handler to select button const selectBtn = card.querySelector('.dns-template-select-btn'); selectBtn.addEventListener('click', () => this.handleTemplateSelection(template)); return card; } /** * Handle template selection * @private */ handleTemplateSelection(template) { console.log(`[DnsTemplateSelector] Template selected: ${template.id}`); // Close modal this.close(); // Trigger callback if set if (this.onTemplateSelected) { this.onTemplateSelected(template); } else { // Default behavior: open app selector with DNS filter this.openAppSelector(template.id); } } /** * Handle "Set up later" button * @private */ handleSetupLater() { console.log('[DnsTemplateSelector] DNS setup deferred'); // Mark as deferred in progress tracker if (this.progressTracker) { this.progressTracker.markDnsSetupDeferred(); } // Close modal this.close(); // Show notification this.showNotification('DNS setup deferred. You can set it up later from the App Selector.'); } /** * Open app selector with specific template * @private */ openAppSelector(templateId) { // Try to open the app selector modal if it exists const appSelectorBtn = document.querySelector('[onclick*="showAppSelector"]'); if (appSelectorBtn) { appSelectorBtn.click(); // Wait a bit then filter to the selected template setTimeout(() => { const searchInput = document.querySelector('#app-search'); if (searchInput) { searchInput.value = templateId; searchInput.dispatchEvent(new Event('input', { bubbles: true })); } }, 300); } else { // Fallback: show instructions this.showNotification(`To deploy ${templateId}, use the App Selector and search for "${templateId}"`); } } /** * Show notification message * @private */ showNotification(message) { // Simple notification - could be enhanced const notification = document.createElement('div'); notification.className = 'dns-template-notification'; notification.textContent = message; notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background: var(--card-base); color: var(--fg); padding: 15px 20px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.3); z-index: 10001; max-width: 300px; `; document.body.appendChild(notification); setTimeout(() => { notification.style.opacity = '0'; notification.style.transition = 'opacity 0.3s'; setTimeout(() => notification.remove(), 300); }, 3000); } /** * Close the modal */ close() { if (this.modal) { this.modal.style.display = 'none'; document.body.style.overflow = ''; } } } window.DnsTemplateSelector = DnsTemplateSelector; console.log('[DnsTemplateSelector] Module loaded'); })(window);