const { createApp } = Vue; createApp({ data() { return { currentLang: 'tr', isDark: false, // Translation dictionary translations: { tr: { globalSettings: 'Genel Ayarlar', renderer: 'Oluşturucu (Renderer)', version: 'Netplan Sürümü', ethernets: 'Ethernet Arayüzleri', addEthernet: 'Ethernet Ekle', wifis: 'Wi-Fi Arayüzleri', addWifi: 'Wi-Fi Ekle', bridges: 'Köprüler (Bridges)', addBridge: 'Köprü Ekle', bonds: 'Bağlar (Bonds)', addBond: 'Bağ Ekle', vlans: 'VLANlar', addVlan: 'VLAN Ekle', noInterfaces: 'Henüz arayüz eklenmedi.', interfaceName: 'Arayüz Adı', interfaces: 'Arayüzler (Interfaces)', ipAddresses: 'IP Adresleri', gateway4: 'Gateway (IPv4)', nameservers: 'DNS Sunucuları', commaSeparated: 'Virgülle ayrılmış (örn: 192.168.1.1, 8.8.8.8)', advancedSettings: 'Gelişmiş Ayarlar', routes: 'Statik Rotalar (Routes)', downloadYaml: 'YAML İndir', copyClipboard: 'Kopyala', parameters: 'Parametreler', mode: 'Mod', id: 'ID', link: 'Bağlantı (Link)', instructions: 'Kurulum Talimatları', step1: '1. Oluşturulan dosyayı kopyalayın veya indirin.', step2: '2. Linux sunucunuzda aşağıdaki dizine dosyayı kaydedin (varsayılan dosya adı genellikle 00-installer-config.yaml veya 01-netcfg.yaml olabilir):', step3: '3. Dosya izinlerini güvenli hale getirin:', step4: '4. Yapılandırmayı test edin (Hata varsa geri alır):', step5: '5. Eğer test başarılıysa yapılandırmayı uygulayın:', note: 'Not: Netplan dosya isimleri alfabetik sıraya göre işlenir. Eski yapılandırma dosyalarını yedeklemeyi veya silmeyi unutmayın.' }, en: { globalSettings: 'Global Settings', renderer: 'Renderer', version: 'Netplan Version', ethernets: 'Ethernet Interfaces', addEthernet: 'Add Ethernet', wifis: 'Wi-Fi Interfaces', addWifi: 'Add Wi-Fi', bridges: 'Bridges', addBridge: 'Add Bridge', bonds: 'Bonds', addBond: 'Add Bond', vlans: 'VLANs', addVlan: 'Add VLAN', noInterfaces: 'No interfaces added yet.', interfaceName: 'Interface Name', interfaces: 'Interfaces', ipAddresses: 'IP Addresses', gateway4: 'Gateway (IPv4)', nameservers: 'Nameservers', commaSeparated: 'Comma separated (e.g. 192.168.1.1, 8.8.8.8)', advancedSettings: 'Advanced Settings', routes: 'Static Routes', wifis: 'Wi-Fi Interfaces', addWifi: 'Add Wi-Fi', noWifis: 'No Wi-Fi interfaces added yet.', downloadYaml: 'Download YAML', copyClipboard: 'Copy', parameters: 'Parameters', mode: 'Mode', id: 'ID', link: 'Link', instructions: 'Installation Instructions', step1: '1. Copy or download the generated file.', step2: '2. Save the file to the following directory on your Linux server (default filename is usually 00-installer-config.yaml or 01-netcfg.yaml):', step3: '3. Secure the file permissions:', step4: '4. Test the configuration (Reverts on error):', step5: '5. If the test is successful, apply the configuration:', note: 'Note: Netplan processes files in alphabetical order. Remember to backup or remove old configuration files.' } }, // Configuration Model config: { version: 2, renderer: 'networkd', ethernets: [], wifis: [], bridges: [], bonds: [], vlans: [] } } }, computed: { generatedYaml() { const network = { version: this.config.version, renderer: this.config.renderer }; // Helper to clean common fields const processCommon = (item) => { const obj = {}; // DHCP if (item.dhcp4) { obj.dhcp4 = true; } // Static IP & Gateway & DNS - only if not DHCP (usually, though netplan allows mixing but let's keep simple) // Actually netplan allows addresses with dhcp4: true (e.g. static + dhcp). But let's follow the UI logic: // if DHCP is unchecked, these fields are shown. if (!item.dhcp4) { if (item.addressesInput) { obj.addresses = item.addressesInput.split(',').map(s => { let addr = s.trim(); if (addr && !addr.includes('/')) { addr += '/24'; // Default to /24 if missing } return addr; }).filter(s => s); } if (item.nameserversInput) { obj.nameservers = { addresses: item.nameserversInput.split(',').map(s => s.trim()).filter(s => s) }; } } // Advanced if (item.mtu) obj.mtu = item.mtu; if (item.macaddress) obj.macaddress = item.macaddress; // Routes let finalRoutes = []; // Deprecated gateway4 -> converted to default route if (!item.dhcp4 && item.gateway4) { finalRoutes.push({ to: 'default', via: item.gateway4 }); } // Custom Routes if (item.routes && item.routes.length > 0) { const validRoutes = item.routes.filter(r => r.to && r.via).map(r => ({ to: r.to, via: r.via })); finalRoutes = finalRoutes.concat(validRoutes); } if (finalRoutes.length > 0) { obj.routes = finalRoutes; } return obj; }; // Ethernets if (this.config.ethernets.length > 0) { network.ethernets = {}; this.config.ethernets.forEach(eth => { if (eth.name) { network.ethernets[eth.name] = processCommon(eth); } }); } // Wi-Fis if (this.config.wifis.length > 0) { network.wifis = {}; this.config.wifis.forEach(wifi => { if (!wifi.name) return; const obj = processCommon(wifi); if (wifi.accessPoints && wifi.accessPoints.length > 0) { obj['access-points'] = {}; wifi.accessPoints.forEach(ap => { if (ap.ssid) { obj['access-points'][ap.ssid] = {}; if (ap.password) { obj['access-points'][ap.ssid].password = ap.password; } } }); } network.wifis[wifi.name] = obj; }); } // Bridges if (this.config.bridges.length > 0) { network.bridges = {}; this.config.bridges.forEach(bridge => { if (!bridge.name) return; const obj = processCommon(bridge); if (bridge.interfacesInput) { obj.interfaces = bridge.interfacesInput.split(',').map(s => s.trim()).filter(s => s); } if (bridge.parameters) { obj.parameters = {}; if (bridge.parameters.stp !== null) obj.parameters.stp = bridge.parameters.stp; if (bridge.parameters.forwardDelay !== null && bridge.parameters.forwardDelay !== '') obj.parameters['forward-delay'] = bridge.parameters.forwardDelay; } network.bridges[bridge.name] = obj; }); } // Bonds if (this.config.bonds.length > 0) { network.bonds = {}; this.config.bonds.forEach(bond => { if (!bond.name) return; const obj = processCommon(bond); if (bond.interfacesInput) { obj.interfaces = bond.interfacesInput.split(',').map(s => s.trim()).filter(s => s); } if (bond.parameters) { obj.parameters = {}; if (bond.parameters.mode) obj.parameters.mode = bond.parameters.mode; } network.bonds[bond.name] = obj; }); } // VLANs if (this.config.vlans.length > 0) { network.vlans = {}; this.config.vlans.forEach(vlan => { if (!vlan.name) return; const obj = processCommon(vlan); if (vlan.id) obj.id = vlan.id; if (vlan.link) obj.link = vlan.link; network.vlans[vlan.name] = obj; }); } try { // Using js-yaml from CDN if (typeof jsyaml !== 'undefined') { return jsyaml.dump({ network: network }, { indent: 2, noRefs: true }); } else { return 'js-yaml library not loaded.'; } } catch (e) { return 'Error generating YAML: ' + e.message; } } }, methods: { t(key) { return this.translations[this.currentLang][key] || key; }, toggleLanguage() { this.currentLang = this.currentLang === 'tr' ? 'en' : 'tr'; }, toggleTheme() { this.isDark = !this.isDark; if (this.isDark) { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } }, createInterface(type) { const base = { dhcp4: true, addressesInput: '', gateway4: '', nameserversInput: '', mtu: null, macaddress: '', routes: [], showAdvanced: false }; if (type === 'ethernet') { return { ...base, name: 'eth' + this.config.ethernets.length }; } if (type === 'wifi') { return { ...base, name: 'wlan' + this.config.wifis.length, accessPoints: [{ ssid: '', password: '' }] }; } if (type === 'bridge') { return { ...base, name: 'br' + this.config.bridges.length, interfacesInput: '', parameters: { stp: false, forwardDelay: 0 } }; } if (type === 'bond') { return { ...base, name: 'bond' + this.config.bonds.length, interfacesInput: '', parameters: { mode: 'active-backup' } }; } if (type === 'vlan') { return { ...base, name: 'vlan' + this.config.vlans.length, id: 10, link: '' }; } }, addEthernet() { this.config.ethernets.push(this.createInterface('ethernet')); }, removeEthernet(index) { this.config.ethernets.splice(index, 1); }, addWifi() { this.config.wifis.push(this.createInterface('wifi')); }, removeWifi(index) { this.config.wifis.splice(index, 1); }, addBridge() { this.config.bridges.push(this.createInterface('bridge')); }, removeBridge(index) { this.config.bridges.splice(index, 1); }, addBond() { this.config.bonds.push(this.createInterface('bond')); }, removeBond(index) { this.config.bonds.splice(index, 1); }, addVlan() { this.config.vlans.push(this.createInterface('vlan')); }, removeVlan(index) { this.config.vlans.splice(index, 1); }, async copyToClipboard() { try { await navigator.clipboard.writeText(this.generatedYaml); // alert('Kopyalandı!'); } catch (err) { console.error('Failed to copy: ', err); } }, downloadYaml() { const blob = new Blob([this.generatedYaml], { type: 'text/yaml' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = '01-netcfg.yaml'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } }, mounted() { this.addEthernet(); } }).mount('#app');