@@ -4346,19 +4346,29 @@ async function refreshFolders(): Promise<void> {
43464346
43474347async function refreshSingleFolder(folderPath: string): Promise<void> {
43484348 const folder = state.folders.find(f => f.path === folderPath);
4349- if (!folder || folder.isRemote ) return;
4349+ if (!folder) return;
43504350
43514351 // Find the refresh button in the DOM and show spinning state
43524352 const groupEl = elements.foldersList.querySelector(`.folder-group[data-path="${CSS.escape(folderPath)}"]`);
43534353 const btn = groupEl?.querySelector('.folder-refresh') as HTMLButtonElement | null;
43544354 if (btn) { btn.disabled = true; btn.textContent = '\u27F3'; }
43554355
43564356 try {
4357- const result = await window.api.readFolder(folder.path);
4358- if (result.success && result.files) {
4359- const newFiles = mapFolderEntries(result.files);
4360- preserveCollapseState(newFiles, folder.files);
4361- folder.files = newFiles;
4357+ if (folder.isRemote) {
4358+ // Remote folder — re-list via SFTP
4359+ const result = await window.api.sshListRemoteDir(folder.path);
4360+ if (result.success && result.files) {
4361+ const newFiles = mapFolderEntries(result.files);
4362+ preserveCollapseState(newFiles, folder.files);
4363+ folder.files = newFiles;
4364+ }
4365+ } else {
4366+ const result = await window.api.readFolder(folder.path);
4367+ if (result.success && result.files) {
4368+ const newFiles = mapFolderEntries(result.files);
4369+ preserveCollapseState(newFiles, folder.files);
4370+ folder.files = newFiles;
4371+ }
43624372 }
43634373 renderFolderTree();
43644374 } finally {
@@ -4374,15 +4384,17 @@ function formatFileSize(bytes: number): string {
43744384
43754385function renderFolderEntries(entries: LocalFolderFile[], depth: number, isRemote: boolean): string {
43764386 return entries.map(entry => {
4377- if (entry.isDirectory && entry.children) {
4387+ if (entry.isDirectory) {
4388+ const hasChildren = entry.children && entry.children.length > 0;
4389+ const isLoading = (entry as any)._loading;
43784390 return `
4379- <div class="folder-subdir ${entry.collapsed ? 'collapsed' : ''}" data-subdir-path="${escapeHtml(entry.path)}">
4391+ <div class="folder-subdir ${entry.collapsed ? 'collapsed' : ''}" data-subdir-path="${escapeHtml(entry.path)}" ${isRemote ? 'data-remote-dir="true"' : ''} >
43804392 <div class="folder-subdir-header" style="padding-left: ${8 + depth * 14}px">
4381- <span class="folder-toggle">&# 9660;</span>
4393+ <span class="folder-toggle">${isLoading ? '⌛' : '&# 9660;'} </span>
43824394 <span class="folder-subdir-name" title="${escapeHtml(entry.path)}">${escapeHtml(entry.name)}</span>
43834395 </div>
43844396 <div class="folder-subdir-files">
4385- ${renderFolderEntries(entry.children, depth + 1, isRemote)}
4397+ ${hasChildren ? renderFolderEntries(entry.children! , depth + 1, isRemote) : (!entry.collapsed && isRemote && !isLoading ? '<div class="folder-loading" style="padding-left:' + (8 + (depth+1) * 14) + 'px;font-size:11px;color:var(--text-muted);">Loading...</div>' : '' )}
43864398 </div>
43874399 </div>`;
43884400 }
@@ -4425,7 +4437,7 @@ function renderFolderTree(): void {
44254437 <div class="folder-header">
44264438 <span class="folder-toggle">▼</span>
44274439 <span class="folder-name" title="${escapeHtml(folder.path)}">${folder.isRemote ? '<span class="ssh-badge">SSH</span> ' : ''}${escapeHtml(folder.name)}</span>
4428- ${!folder.isRemote ? ' <button class="folder-refresh" title="Refresh folder">↻</button>' : ''}
4440+ <button class="folder-refresh" title="Refresh folder">↻</button>
44294441 <button class="folder-close" title="Remove folder">×</button>
44304442 </div>
44314443 <div class="folder-files">
@@ -4463,21 +4475,37 @@ function renderFolderTree(): void {
44634475 });
44644476 });
44654477
4466- // Subfolder toggle events
4478+ // Subfolder toggle events (with lazy remote loading)
44674479 elements.foldersList.querySelectorAll('.folder-subdir-header').forEach((header) => {
4468- header.addEventListener('click', (e) => {
4480+ header.addEventListener('click', async (e) => {
44694481 e.stopPropagation();
44704482 const subdirEl = header.closest('.folder-subdir') as HTMLElement;
44714483 const subdirPath = subdirEl?.dataset.subdirPath;
4484+ const isRemoteDir = subdirEl?.dataset.remoteDir === 'true';
44724485 const folderGroupPath = (subdirEl?.closest('.folder-group') as HTMLElement)?.dataset.path;
44734486 if (!subdirPath || !folderGroupPath) return;
44744487 const folder = state.folders.find(f => f.path === folderGroupPath);
44754488 if (!folder) return;
44764489 const node = findSubfolder(folder.files, subdirPath);
4477- if (node) {
4478- node.collapsed = !node.collapsed;
4490+ if (!node) return;
4491+
4492+ // Toggle collapse
4493+ node.collapsed = !node.collapsed;
4494+
4495+ // Lazy-load remote subdirectory contents if expanding and no children yet
4496+ if (!node.collapsed && isRemoteDir && (!node.children || node.children.length === 0)) {
4497+ (node as any)._loading = true;
44794498 renderFolderTree();
4499+ try {
4500+ const result = await window.api.sshListRemoteDir(subdirPath);
4501+ if (result.success && result.files) {
4502+ node.children = mapFolderEntries(result.files);
4503+ }
4504+ } catch { /* ignore */ }
4505+ (node as any)._loading = false;
44804506 }
4507+
4508+ renderFolderTree();
44814509 });
44824510 });
44834511
0 commit comments