import { ListDir, GetConnections, SaveConnection, DeleteConnection, Delete, Rename, PromptUploadFiles, PromptUploadDirectory, PromptDownload } from '../wailsjs/go/main/App.js'; let currentConn = 'local'; let currentPath = ''; let connectionsCache = []; function uuidv4() { return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) ); } async function init() { await loadConnections(); await loadDirectory(currentConn, currentPath); document.getElementById('conn-form').addEventListener('submit', async (e) => { e.preventDefault(); const conn = { id: document.getElementById('conn-id').value, name: document.getElementById('conn-name').value, protocol: document.getElementById('conn-protocol').value, host: document.getElementById('conn-host').value, port: parseInt(document.getElementById('conn-port').value) || 0, bucket: document.getElementById('conn-bucket').value, region: document.getElementById('conn-region').value, path_style: document.getElementById('conn-pathstyle').checked, username: document.getElementById('conn-username').value }; const secret = document.getElementById('conn-secret').value; try { await SaveConnection(conn, secret); closeConnModal(); loadConnections(); } catch(err) { alert("Failed to save connection: " + err); } }); } async function loadConnections() { const list = document.getElementById('conn-list'); list.innerHTML = `
OS Local Filesystem
`; try { const conns = await GetConnections(); connectionsCache = conns || []; if (connectionsCache) { connectionsCache.forEach(c => { const el = document.createElement('div'); el.className = `conn-item ${currentConn === c.id ? 'active' : ''}`; el.innerHTML = `${c.protocol} ${c.name} `; el.onclick = () => switchConn(c.id); list.appendChild(el); }); } } catch(e) { console.error(e); } } window.switchConn = async (id) => { currentConn = id; currentPath = ''; // Root path loadConnections(); // To update 'active' class await loadDirectory(currentConn, currentPath); }; window.editConnection = (id) => { const c = connectionsCache.find(conn => conn.id === id); if (!c) return; document.getElementById('modal-title').innerText = "Edit Connection"; document.getElementById('conn-id').value = c.id; document.getElementById('conn-name').value = c.name; document.getElementById('conn-protocol').value = c.protocol; document.getElementById('conn-host').value = c.host || ''; document.getElementById('conn-port').value = c.port || ''; document.getElementById('conn-bucket').value = c.bucket || ''; document.getElementById('conn-region').value = c.region || ''; document.getElementById('conn-pathstyle').checked = c.path_style || false; document.getElementById('conn-username').value = c.username || ''; document.getElementById('conn-secret').value = ''; document.getElementById('conn-delete-btn').style.display = 'block'; updateProtocolFields(); document.getElementById('conn-modal').style.display = 'flex'; }; window.openConnModal = () => { document.getElementById('modal-title').innerText = "Add Connection"; document.getElementById('conn-form').reset(); document.getElementById('conn-id').value = uuidv4(); document.getElementById('conn-delete-btn').style.display = 'none'; updateProtocolFields(); document.getElementById('conn-modal').style.display = 'flex'; }; window.closeConnModal = () => { document.getElementById('conn-modal').style.display = 'none'; }; window.updateProtocolFields = () => { const protocol = document.getElementById('conn-protocol').value; const showBucket = protocol === 's3' || protocol === 'smb'; document.getElementById('bucket-fields').style.display = showBucket ? 'block' : 'none'; // Only show S3 specific fields when S3 is selected const showS3Specific = protocol === 's3'; document.getElementById('region-group').style.display = showS3Specific ? 'flex' : 'none'; document.getElementById('pathstyle-group').style.display = showS3Specific ? 'flex' : 'none'; }; window.deleteConnection = async () => { if(!confirm("Are you sure you want to delete this connection?")) return; const id = document.getElementById('conn-id').value; try { await DeleteConnection(id); closeConnModal(); if(currentConn === id) { switchConn('local'); } else { loadConnections(); } } catch(err) { alert("Failed to delete connection: " + err); } }; async function loadDirectory(connId, path) { const tbody = document.getElementById('file-list'); tbody.innerHTML = 'Loading...'; document.getElementById('breadcrumb').innerText = path || '/'; try { const files = await ListDir(connId, path); tbody.innerHTML = ''; if (!files || files.length === 0) { tbody.innerHTML = 'Empty directory'; return; } files.forEach(f => { const tr = document.createElement('tr'); tr.innerHTML = ` ${f.is_dir ? '📁 ' : '📄 '}${f.name} ${f.is_dir ? '-' : formatBytes(f.size)} ${f.modified} ${f.permissions} `; if (f.is_dir) { tr.ondblclick = () => { currentPath = f.path; loadDirectory(currentConn, currentPath); }; } tr.dataset.path = f.path; tr.dataset.name = f.name; tbody.appendChild(tr); }); } catch(e) { tbody.innerHTML = `Error: ${e}`; } } window.refreshCurrentDir = () => { loadDirectory(currentConn, currentPath); }; window.showTransfers = () => { document.getElementById('transfer-tray').style.display = 'block'; }; window.hideTransfers = () => { document.getElementById('transfer-tray').style.display = 'none'; }; function formatBytes(bytes) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } window.addEventListener('load', init); // Context Menu Logic let contextMenuTarget = null; document.addEventListener('contextmenu', (e) => { const menu = document.getElementById('context-menu'); menu.style.display = 'none'; const row = e.target.closest('tr'); if (row && row.dataset.path) { e.preventDefault(); contextMenuTarget = { path: row.dataset.path, name: row.dataset.name }; menu.style.display = 'block'; menu.style.left = `${e.pageX}px`; menu.style.top = `${e.pageY}px`; } }); document.addEventListener('click', () => { document.getElementById('context-menu').style.display = 'none'; const uploadMenu = document.getElementById('upload-menu'); if (uploadMenu) uploadMenu.style.display = 'none'; }); window.toggleUploadMenu = (e) => { if (e) e.stopPropagation(); const menu = document.getElementById('upload-menu'); if (menu.style.display === 'none') { menu.style.display = 'block'; } else { menu.style.display = 'none'; } }; window.handleContextMenu = async (action) => { if (!contextMenuTarget) return; const { path, name } = contextMenuTarget; try { if (action === 'delete') { if (confirm(`Are you sure you want to delete ${name}?`)) { await Delete(currentConn, path); refreshCurrentDir(); } } else if (action === 'rename') { const newName = prompt(`Enter new name for ${name}:`, name); if (newName && newName !== name) { // Construct new path by replacing the last part const pathParts = path.split('/'); pathParts[pathParts.length - 1] = newName; const newPath = pathParts.join('/'); await Rename(currentConn, path, newPath); refreshCurrentDir(); } } else if (action === 'download') { await PromptDownload(currentConn, path); showTransfers(); } } catch (e) { alert(`Failed to ${action}: ${e}`); } }; window.promptUploadFiles = async () => { try { await PromptUploadFiles(currentConn, currentPath); showTransfers(); } catch (e) { alert("Upload failed: " + e); } }; window.promptUploadDirectory = async () => { try { await PromptUploadDirectory(currentConn, currentPath); showTransfers(); } catch (e) { alert("Upload failed: " + e); } };