// /SFTP/filemanager.js
(function() {
const FileManager = {
id: "fileManager",
label: "📁 File Manager",
html: `
<div class="fm-container">
<div class="fm-toolbar">
<div class="fm-left" data-toolbar></div>
<span id="fmStatus" class="fm-status">Loading...</span>
</div>
<div id="fmList" class="fm-list"></div>
</div>
`,
toolbar: [
{ id: "up", label: "⬅️ Up", action: "goUpDirectory" },
{ id: "refresh", label: "🔄 Refresh", action: "reload" },
{ id: "newfile", label: "📄 New File", action: "newFile" },
{ id: "newfolder", label: "📁 New Folder", action: "newFolder" }
],
currentPath: "/",
async onRender(el) {
this.el = el;
this.renderToolbar();
// Check if driver is initialized and connected
if (!window.AppStorage || !window.AppStorage.driver) {
this.showError("SFTP driver not initialized. Please use Test SFTP to connect first.");
return;
}
// Check if there's an active connection
if (!window._currentSFTPConnection) {
this.showError("No active SFTP connection. Please use Test SFTP to connect first.");
return;
}
this.log(`Connected to: ${window._currentSFTPConnection.host}`);
await this.loadFiles("/");
},
log(message) {
console.log('[FileManager]', message);
},
renderToolbar() {
const bar = this.el.querySelector("[data-toolbar]");
bar.innerHTML = "";
this.toolbar.forEach(btn => {
const el = document.createElement("button");
el.className = "fm-btn";
el.textContent = btn.label;
el.addEventListener("click", () => this.runAction(btn.action));
bar.appendChild(el);
});
},
runAction(action) {
if (FileManagerActions[action]) FileManagerActions[action](this);
},
async loadFiles(path = "/") {
const fmList = this.el.querySelector("#fmList");
const fmStatus = this.el.querySelector("#fmStatus");
fmList.innerHTML = `<p style="color:#94a3b8;">Loading ${path}...</p>`;
fmStatus.textContent = `Loading ${path}...`;
this.currentPath = path;
try {
// Check if driver exists
if (!window.AppStorage || !window.AppStorage.driver) {
throw new Error("SFTP driver not initialized. Please connect first.");
}
// Check if connected
if (!window._currentSFTPConnection) {
throw new Error("No active SFTP connection. Please connect via Test SFTP first.");
}
this.log(`Loading files from: ${path}`);
this.log(`Connection: ${window._currentSFTPConnection.host}:${window._currentSFTPConnection.port}`);
// Use the SFTPDriver's list method
const files = await window.AppStorage.driver.list(path);
this.log(`Loaded ${files.length} files successfully`);
if (!files || files.length === 0) {
fmList.innerHTML = `<p style="color:#94a3b8;">No files found in ${path}</p>`;
fmStatus.textContent = `Path: ${path} (0 items)`;
return;
}
this.renderFiles(files);
fmStatus.textContent = `Path: ${path} (${files.length} items)`;
} catch (err) {
console.error("[FileManager] Load error:", err);
fmList.innerHTML = `<p style="color:#ef4444;">❌ ${err.message}</p>`;
fmStatus.textContent = "Error loading files";
}
},
renderFiles(files) {
const fmList = this.el.querySelector("#fmList");
fmList.innerHTML = "";
if (!files || files.length === 0) {
fmList.innerHTML = `<p>No files found.</p>`;
return;
}
files.forEach(f => {
const div = document.createElement("div");
div.className = "fm-item";
const deleteBtn = document.createElement("button");
deleteBtn.className = "fm-delete-btn";
deleteBtn.textContent = "🗑️";
deleteBtn.title = "Delete";
deleteBtn.addEventListener("click", (e) => {
e.stopPropagation();
FileManagerActions.deleteItem(this, f);
});
div.innerHTML = `
<div class="fm-name">${f.is_dir ? "📁" : "📄"} ${f.name}</div>
<div class="fm-meta">${f.is_dir ? "Folder" : this.formatBytes(f.size)} • ${f.modified}</div>
`;
div.appendChild(deleteBtn);
if (f.is_dir) {
div.querySelector(".fm-name").addEventListener("click", () => {
const newPath = this.currentPath.endsWith("/")
? this.currentPath + f.name
: this.currentPath + "/" + f.name;
this.loadFiles(newPath);
});
}
fmList.appendChild(div);
});
},
formatBytes(bytes) {
if (!bytes) return "";
if (bytes < 1024) return bytes + " B";
const units = ["KB", "MB", "GB", "TB"];
let u = -1;
do { bytes /= 1024; ++u; } while (bytes >= 1024 && u < units.length - 1);
return bytes.toFixed(1) + " " + units[u];
},
showError(message) {
const fmList = this.el.querySelector("#fmList");
const fmStatus = this.el.querySelector("#fmStatus");
fmList.innerHTML = `<p style="color:#ef4444;">❌ ${message}</p>`;
fmStatus.textContent = "Not connected";
}
};
const FileManagerActions = {
reload: ctx => ctx.loadFiles(ctx.currentPath),
goUpDirectory: ctx => {
const parts = ctx.currentPath.split("/").filter(Boolean);
parts.pop();
const newPath = "/" + parts.join("/");
ctx.loadFiles(newPath || "/");
},
newFile: async ctx => {
if (!window.AppStorage || !window.AppStorage.driver) {
alert("❌ SFTP driver not initialized. Please connect first.");
return;
}
const name = prompt("Enter new file name (e.g., example.txt):");
if (!name) return;
const path = `${ctx.currentPath.replace(/\/$/, "")}/${name}`;
try {
console.log("[FileManager] ==================");
console.log("[FileManager] Creating new file");
console.log("[FileManager] Filename entered:", name);
console.log("[FileManager] Full path:", path);
console.log("[FileManager] Current directory:", ctx.currentPath);
console.log("[FileManager] Connection status:", window._currentSFTPConnection);
console.log("[FileManager] ==================");
// Use the driver's create method (which calls sftpnewfile.js)
const result = await window.AppStorage.driver.create(path, "");
console.log("[FileManager] Create result received:", result);
if (result.success) {
alert(`✅ File created: ${name}`);
ctx.loadFiles(ctx.currentPath);
} else {
alert(`❌ Failed to create file: ${result.message}`);
}
} catch (err) {
console.error("[FileManager] Create file error:", err);
console.error("[FileManager] Error stack:", err.stack);
alert(`❌ Error: ${err.message}`);
}
},
newFolder: async ctx => {
if (!window.AppStorage || !window.AppStorage.driver) {
alert("❌ SFTP driver not initialized. Please connect first.");
return;
}
const name = prompt("Enter new folder name:");
if (!name) return;
const path = `${ctx.currentPath.replace(/\/$/, "")}/${name}`;
try {
console.log("[FileManager] Creating folder:", path);
// Import the createFolder driver
const { createFolder } = await import('/core/js/drivers_files/sftpmkdir.js');
const result = await createFolder(path);
if (result.success) {
alert(`✅ Folder created: ${name}`);
ctx.loadFiles(ctx.currentPath);
} else {
alert(`❌ Failed to create folder: ${result.message}`);
}
} catch (err) {
console.error("[FileManager] Create folder error:", err);
alert(`❌ Error: ${err.message}`);
}
},
deleteItem: async (ctx, file) => {
if (!window.AppStorage || !window.AppStorage.driver) {
alert("❌ SFTP driver not initialized. Please connect first.");
return;
}
const confirmMsg = file.is_dir
? `Delete folder "${file.name}" and all its contents?`
: `Delete file "${file.name}"?`;
if (!confirm(confirmMsg)) return;
const path = `${ctx.currentPath.replace(/\/$/, "")}/${file.name}`;
try {
console.log("[FileManager] Deleting:", path);
// Import the deleteFile driver
const { deleteFile } = await import('/core/js/drivers_files/sftpdelete.js');
const result = await deleteFile(path);
if (result.success) {
alert(`✅ Deleted: ${file.name}`);
ctx.loadFiles(ctx.currentPath);
} else {
alert(`❌ Failed to delete: ${result.message}`);
}
} catch (err) {
console.error("[FileManager] Delete error:", err);
alert(`❌ Error: ${err.message}`);
}
}
};
window.AppItems = window.AppItems || [];
window.AppItems.push(FileManager);
console.log("[FileManager] Registered - uses AppStorage.driver for all operations");
})();