// Simple SFTP Test Connection Component
(function() {
const TestConnection = {
id: "testConnection",
label: "🔧 Test SFTP",
html: `
<div class="test-container">
<h1>🔐 SFTP Connection Test</h1>
<div class="test-info">
<div><strong>Host:</strong> files.devbrewing.com</div>
<div><strong>Port:</strong> 22</div>
<div><strong>Username:</strong> olinhll</div>
<div><strong>Password:</strong> devbrewing123</div>
</div>
<button id="connectTestBtn" class="test-btn test-btn-connect">🚀 Test Connection</button>
<button id="listTestBtn" class="test-btn test-btn-list" disabled>📁 List Root Directory</button>
<button id="disconnectTestBtn" class="test-btn test-btn-disconnect" disabled>🔌 Disconnect</button>
<div id="testOutput" class="test-output"></div>
</div>
<style>
.test-container {
padding: 20px;
max-width: 800px;
margin: 0 auto;
}
.test-container h1 {
margin: 0 0 20px 0;
font-size: 24px;
color: #e2e8f0;
}
.test-info {
background: #0f172a;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
font-size: 14px;
line-height: 1.8;
}
.test-info div {
margin-bottom: 5px;
}
.test-info strong {
color: #60a5fa;
min-width: 100px;
display: inline-block;
}
.test-btn {
background: linear-gradient(135deg, #3b82f6, #9333ea);
color: white;
border: none;
padding: 12px 24px;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
margin-right: 10px;
margin-bottom: 15px;
}
.test-btn:hover:not(:disabled) {
opacity: 0.9;
}
.test-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.test-output {
background: #0f172a;
border: 1px solid #334155;
border-radius: 8px;
padding: 15px;
font-family: 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
max-height: 500px;
overflow-y: auto;
white-space: pre-wrap;
word-break: break-all;
}
.test-output:empty::before {
content: 'Click "Test Connection" to begin...';
color: #64748b;
font-style: italic;
}
.log-success { color: #10b981; }
.log-error { color: #ef4444; }
.log-info { color: #60a5fa; }
.log-warn { color: #f59e0b; }
</style>
`,
driver: null,
async onRender(el) {
this.el = el;
// Attach event listeners
el.querySelector('#connectTestBtn').addEventListener('click', () => this.testConnection());
el.querySelector('#listTestBtn').addEventListener('click', () => this.testList());
el.querySelector('#disconnectTestBtn').addEventListener('click', () => this.testDisconnect());
this.log('Component ready. Click "Test Connection" to start.', 'info');
},
log(message, type = 'info') {
const output = this.el.querySelector('#testOutput');
const time = new Date().toLocaleTimeString();
const className = `log-${type}`;
const div = document.createElement('div');
div.className = className;
div.textContent = `[${time}] ${message}`;
output.appendChild(div);
output.scrollTop = output.scrollHeight;
},
async testConnection() {
const connectBtn = this.el.querySelector('#connectTestBtn');
const listBtn = this.el.querySelector('#listTestBtn');
const disconnectBtn = this.el.querySelector('#disconnectTestBtn');
connectBtn.disabled = true;
connectBtn.textContent = '⏳ Connecting...';
this.el.querySelector('#testOutput').innerHTML = '';
this.log('Starting connection test...', 'info');
try {
// Load the SFTP driver with cache busting
this.log('Loading SFTP driver module...', 'info');
const cacheBuster = '?v=' + Date.now();
this.log('Cache buster: ' + cacheBuster, 'info');
const module = await import('/core/js/drivers_files/sftp.js' + cacheBuster);
this.log('Module loaded, checking exports...', 'info');
this.log('Available exports: ' + Object.keys(module).join(', '), 'info');
this.driver = module.SFTPDriver || module.default;
if (!this.driver) {
throw new Error('SFTPDriver not found in module exports');
}
this.log('Checking driver methods...', 'info');
this.log('Has connect: ' + (typeof this.driver.connect === 'function'), 'info');
this.log('Has list: ' + (typeof this.driver.list === 'function'), 'info');
this.log('Has disconnect: ' + (typeof this.driver.disconnect === 'function'), 'info');
this.log('✓ SFTP driver loaded successfully', 'success');
// Test connection
this.log('Attempting to connect to files.devbrewing.com:22...', 'info');
this.log('Username: olinhll', 'info');
const result = await this.driver.connect(
'files.devbrewing.com',
22,
'olinhll',
'devbrewing123'
);
this.log('✓ Connection successful!', 'success');
this.log('Server response: ' + JSON.stringify(result, null, 2), 'success');
connectBtn.textContent = '✅ Connected';
listBtn.disabled = false;
disconnectBtn.disabled = false;
} catch (err) {
this.log('✗ Connection FAILED!', 'error');
this.log('Error message: ' + err.message, 'error');
this.log('Error stack: ' + err.stack, 'error');
connectBtn.textContent = '🚀 Test Connection';
connectBtn.disabled = false;
}
},
async testList() {
const listBtn = this.el.querySelector('#listTestBtn');
listBtn.disabled = true;
listBtn.textContent = '⏳ Loading...';
try {
this.log('==================', 'info');
this.log('Listing root directory (/)...', 'info');
const files = await this.driver.list('/');
this.log(`✓ Successfully loaded ${files.length} items:`, 'success');
this.log('==================', 'info');
if (files.length === 0) {
this.log(' (Directory is empty)', 'warn');
} else {
files.forEach(file => {
const icon = file.is_dir ? '📁' : '📄';
const size = file.is_dir ? 'DIR' : this.formatBytes(file.size);
const modified = file.modified || 'unknown';
this.log(` ${icon} ${file.name.padEnd(30)} ${size.padEnd(10)} ${modified}`, 'info');
});
}
listBtn.textContent = '📁 List Root Directory';
listBtn.disabled = false;
} catch (err) {
this.log('✗ List operation FAILED!', 'error');
this.log('Error: ' + err.message, 'error');
this.log('Stack: ' + err.stack, 'error');
listBtn.textContent = '📁 List Root Directory';
listBtn.disabled = false;
}
},
async testDisconnect() {
const disconnectBtn = this.el.querySelector('#disconnectTestBtn');
const connectBtn = this.el.querySelector('#connectTestBtn');
const listBtn = this.el.querySelector('#listTestBtn');
disconnectBtn.disabled = true;
try {
this.log('==================', 'info');
this.log('Disconnecting from server...', 'info');
const result = await this.driver.disconnect();
this.log('✓ Disconnected successfully', 'success');
this.log('Server response: ' + JSON.stringify(result, null, 2), 'success');
connectBtn.textContent = '🚀 Test Connection';
connectBtn.disabled = false;
listBtn.disabled = true;
disconnectBtn.disabled = true;
} catch (err) {
this.log('✗ Disconnect FAILED!', 'error');
this.log('Error: ' + err.message, 'error');
disconnectBtn.disabled = false;
}
},
formatBytes(bytes) {
if (!bytes || bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}
};
// Register the component
window.AppItems = window.AppItems || [];
window.AppItems.push(TestConnection);
console.log('[TestConnection] Component registered and ready');
})();